From 1d094806fc13ed0e5ed368b9a7da338ac24457f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:48:42 +0100 Subject: [PATCH 001/517] OpenWrt files --- .../mtd/partitions/openwrt,uimage.yaml | 91 + Documentation/networking/adm6996.txt | 110 + .../mt7981-rfb-mxl-2p5g-phy-eth1.dtso | 34 + .../mt7981-rfb-mxl-2p5g-phy-swp5.dtso | 35 + .../dts/mediatek/mt7981-rfb-spim-nand.dtso | 78 + arch/arm64/boot/dts/mediatek/mt7981-rfb.dts | 189 + .../dts/mediatek/mt7986a-rfb-spim-nand.dts | 52 + .../dts/mediatek/mt7986a-rfb-spim-nor.dts | 51 + arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi | 391 + arch/mips/fw/myloader/Makefile | 5 + arch/mips/fw/myloader/myloader.c | 63 + drivers/bcma/fallback-sprom.c | 534 + drivers/bcma/fallback-sprom.h | 7 + drivers/leds/leds-smartrg-system.c | 225 + drivers/mfd/airoha-an8855.c | 278 + drivers/mtd/mtdsplit/Kconfig | 117 + drivers/mtd/mtdsplit/Makefile | 20 + drivers/mtd/mtdsplit/mtdsplit.c | 130 + drivers/mtd/mtdsplit/mtdsplit.h | 67 + drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c | 186 + drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c | 535 + drivers/mtd/mtdsplit/mtdsplit_brnimage.c | 104 + drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c | 90 + drivers/mtd/mtdsplit/mtdsplit_elf.c | 287 + drivers/mtd/mtdsplit/mtdsplit_eva.c | 103 + drivers/mtd/mtdsplit/mtdsplit_fit.c | 365 + drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c | 167 + drivers/mtd/mtdsplit/mtdsplit_jimage.c | 284 + drivers/mtd/mtdsplit/mtdsplit_lzma.c | 109 + drivers/mtd/mtdsplit/mtdsplit_minor.c | 142 + drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c | 270 + drivers/mtd/mtdsplit/mtdsplit_seama.c | 118 + drivers/mtd/mtdsplit/mtdsplit_seil.c | 191 + drivers/mtd/mtdsplit/mtdsplit_squashfs.c | 72 + drivers/mtd/mtdsplit/mtdsplit_tplink.c | 176 + drivers/mtd/mtdsplit/mtdsplit_trx.c | 155 + drivers/mtd/mtdsplit/mtdsplit_uimage.c | 282 + drivers/mtd/mtdsplit/mtdsplit_wrgg.c | 142 + drivers/mtd/nand/mtk_bmt.c | 474 + drivers/mtd/nand/mtk_bmt.h | 137 + drivers/mtd/nand/mtk_bmt_bbt.c | 203 + drivers/mtd/nand/mtk_bmt_nmbm.c | 2348 ++ drivers/mtd/nand/mtk_bmt_v2.c | 506 + drivers/mtd/parsers/routerbootpart.c | 365 + drivers/net/dsa/an8855.c | 2308 ++ drivers/net/dsa/an8855.h | 783 + drivers/net/mdio/mdio-an8855.c | 113 + drivers/net/phy/adm6996.c | 1241 + drivers/net/phy/adm6996.h | 186 + drivers/net/phy/air_an8855.c | 267 + drivers/net/phy/ar8216.c | 2909 ++ drivers/net/phy/ar8216.h | 725 + drivers/net/phy/ar8327.c | 1589 ++ drivers/net/phy/ar8327.h | 334 + drivers/net/phy/b53/Kconfig | 37 + drivers/net/phy/b53/Makefile | 10 + drivers/net/phy/b53/b53_common.c | 1724 ++ drivers/net/phy/b53/b53_mdio.c | 436 + drivers/net/phy/b53/b53_mmap.c | 239 + drivers/net/phy/b53/b53_phy_fixup.c | 55 + drivers/net/phy/b53/b53_priv.h | 336 + drivers/net/phy/b53/b53_regs.h | 348 + drivers/net/phy/b53/b53_spi.c | 344 + drivers/net/phy/b53/b53_srab.c | 376 + drivers/net/phy/en8801sc.c | 1117 + drivers/net/phy/en8801sc.h | 250 + drivers/net/phy/ip17xx.c | 1370 + drivers/net/phy/psb6970.c | 443 + drivers/net/phy/rtk/Makefile | 66 + drivers/net/phy/rtk/rtl8367c/acl.c | 2061 ++ drivers/net/phy/rtk/rtl8367c/cpu.c | 537 + drivers/net/phy/rtk/rtl8367c/dot1x.c | 843 + drivers/net/phy/rtk/rtl8367c/eee.c | 162 + drivers/net/phy/rtk/rtl8367c/i2c.c | 436 + drivers/net/phy/rtk/rtl8367c/igmp.c | 1555 ++ drivers/net/phy/rtk/rtl8367c/include/acl.h | 990 + drivers/net/phy/rtk/rtl8367c/include/cpu.h | 327 + drivers/net/phy/rtk/rtl8367c/include/dot1x.h | 470 + drivers/net/phy/rtk/rtl8367c/include/eee.h | 82 + drivers/net/phy/rtk/rtl8367c/include/i2c.h | 168 + drivers/net/phy/rtk/rtl8367c/include/igmp.h | 769 + .../net/phy/rtk/rtl8367c/include/interrupt.h | 254 + drivers/net/phy/rtk/rtl8367c/include/l2.h | 1181 + drivers/net/phy/rtk/rtl8367c/include/leaky.h | 371 + drivers/net/phy/rtk/rtl8367c/include/led.h | 481 + drivers/net/phy/rtk/rtl8367c/include/mirror.h | 272 + drivers/net/phy/rtk/rtl8367c/include/oam.h | 188 + drivers/net/phy/rtk/rtl8367c/include/port.h | 959 + drivers/net/phy/rtk/rtl8367c/include/ptp.h | 511 + drivers/net/phy/rtk/rtl8367c/include/qos.h | 781 + drivers/net/phy/rtk/rtl8367c/include/rate.h | 305 + drivers/net/phy/rtk/rtl8367c/include/rldp.h | 264 + .../net/phy/rtk/rtl8367c/include/rtk_error.h | 229 + .../net/phy/rtk/rtl8367c/include/rtk_hal.h | 44 + .../net/phy/rtk/rtl8367c/include/rtk_switch.h | 741 + .../net/phy/rtk/rtl8367c/include/rtk_types.h | 155 + .../rtk/rtl8367c/include/rtl8367c_asicdrv.h | 129 + .../rtl8367c/include/rtl8367c_asicdrv_acl.h | 231 + .../include/rtl8367c_asicdrv_cputag.h | 49 + .../rtl8367c/include/rtl8367c_asicdrv_dot1x.h | 52 + .../rtl8367c/include/rtl8367c_asicdrv_eav.h | 109 + .../rtl8367c/include/rtl8367c_asicdrv_eee.h | 31 + .../rtl8367c/include/rtl8367c_asicdrv_fc.h | 99 + .../rtl8367c/include/rtl8367c_asicdrv_green.h | 36 + .../rtl8367c/include/rtl8367c_asicdrv_hsb.h | 43 + .../rtl8367c/include/rtl8367c_asicdrv_i2c.h | 47 + .../rtl8367c/include/rtl8367c_asicdrv_igmp.h | 169 + .../include/rtl8367c_asicdrv_inbwctrl.h | 30 + .../include/rtl8367c_asicdrv_interrupt.h | 66 + .../rtl8367c/include/rtl8367c_asicdrv_led.h | 138 + .../rtl8367c/include/rtl8367c_asicdrv_lut.h | 159 + .../rtl8367c/include/rtl8367c_asicdrv_meter.h | 34 + .../rtl8367c/include/rtl8367c_asicdrv_mib.h | 133 + .../include/rtl8367c_asicdrv_mii_mgr.h | 26 + .../include/rtl8367c_asicdrv_mirror.h | 49 + .../rtl8367c/include/rtl8367c_asicdrv_misc.h | 34 + .../rtl8367c/include/rtl8367c_asicdrv_oam.h | 47 + .../rtl8367c/include/rtl8367c_asicdrv_phy.h | 43 + .../rtl8367c/include/rtl8367c_asicdrv_port.h | 237 + .../include/rtl8367c_asicdrv_portIsolation.h | 28 + .../rtl8367c/include/rtl8367c_asicdrv_qos.h | 96 + .../rtl8367c/include/rtl8367c_asicdrv_rldp.h | 60 + .../rtl8367c/include/rtl8367c_asicdrv_rma.h | 57 + .../include/rtl8367c_asicdrv_scheduling.h | 58 + .../rtl8367c/include/rtl8367c_asicdrv_storm.h | 61 + .../rtl8367c/include/rtl8367c_asicdrv_svlan.h | 132 + .../include/rtl8367c_asicdrv_trunking.h | 48 + .../rtl8367c_asicdrv_unknownMulticast.h | 59 + .../rtl8367c/include/rtl8367c_asicdrv_vlan.h | 157 + .../phy/rtk/rtl8367c/include/rtl8367c_base.h | 596 + .../phy/rtk/rtl8367c/include/rtl8367c_reg.h | 22819 ++++++++++++++++ drivers/net/phy/rtk/rtl8367c/include/smi.h | 54 + drivers/net/phy/rtk/rtl8367c/include/stat.h | 433 + drivers/net/phy/rtk/rtl8367c/include/storm.h | 422 + drivers/net/phy/rtk/rtl8367c/include/svlan.h | 896 + drivers/net/phy/rtk/rtl8367c/include/trap.h | 757 + drivers/net/phy/rtk/rtl8367c/include/trunk.h | 328 + drivers/net/phy/rtk/rtl8367c/include/vlan.h | 892 + drivers/net/phy/rtk/rtl8367c/interrupt.c | 434 + drivers/net/phy/rtk/rtl8367c/l2.c | 2911 ++ drivers/net/phy/rtk/rtl8367c/leaky.c | 590 + drivers/net/phy/rtk/rtl8367c/led.c | 792 + drivers/net/phy/rtk/rtl8367c/mirror.c | 548 + drivers/net/phy/rtk/rtl8367c/oam.c | 245 + drivers/net/phy/rtk/rtl8367c/port.c | 2467 ++ drivers/net/phy/rtk/rtl8367c/ptp.c | 759 + drivers/net/phy/rtk/rtl8367c/qos.c | 1452 + drivers/net/phy/rtk/rtl8367c/rate.c | 607 + drivers/net/phy/rtk/rtl8367c/rldp.c | 468 + drivers/net/phy/rtk/rtl8367c/rtk_hal.c | 839 + drivers/net/phy/rtk/rtl8367c/rtk_switch.c | 1794 ++ .../net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c | 639 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c | 1173 + .../rtk/rtl8367c/rtl8367c_asicdrv_cputag.c | 369 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c | 415 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c | 877 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c | 141 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c | 1354 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c | 445 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c | 81 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c | 474 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c | 2109 ++ .../rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c | 164 + .../rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c | 205 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c | 727 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c | 1549 ++ .../phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c | 305 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c | 570 + .../rtk/rtl8367c/rtl8367c_asicdrv_mirror.c | 472 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c | 268 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c | 194 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c | 394 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c | 5752 ++++ .../rtl8367c/rtl8367c_asicdrv_portIsolation.c | 119 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c | 778 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c | 674 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c | 362 + .../rtl8367c/rtl8367c_asicdrv_scheduling.c | 525 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c | 851 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c | 1003 + .../rtk/rtl8367c/rtl8367c_asicdrv_trunking.c | 356 + .../rtl8367c_asicdrv_unknownMulticast.c | 238 + .../phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c | 1505 + drivers/net/phy/rtk/rtl8367c/smi.c | 442 + drivers/net/phy/rtk/rtl8367c/stat.c | 626 + drivers/net/phy/rtk/rtl8367c/storm.c | 816 + drivers/net/phy/rtk/rtl8367c/svlan.c | 2415 ++ drivers/net/phy/rtk/rtl8367c/trap.c | 1229 + drivers/net/phy/rtk/rtl8367c/trunk.c | 605 + drivers/net/phy/rtk/rtl8367c/vlan.c | 2124 ++ drivers/net/phy/rtk/rtl8367s.c | 580 + drivers/net/phy/rtk/rtl8367s_dbg.c | 648 + drivers/net/phy/rtk/rtl8367s_mdio.c | 301 + drivers/net/phy/rtl8261n/Kconfig | 5 + drivers/net/phy/rtl8261n/Makefile | 11 + .../phy/rtl8261n/construct/conf_rtl8261n_c.c | 1465 + .../phy/rtl8261n/construct/conf_rtl8264b.c | 2177 ++ drivers/net/phy/rtl8261n/error.h | 165 + drivers/net/phy/rtl8261n/phy_patch.c | 188 + drivers/net/phy/rtl8261n/phy_patch.h | 174 + drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c | 1031 + drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h | 63 + drivers/net/phy/rtl8261n/rtk_osal.c | 57 + drivers/net/phy/rtl8261n/rtk_osal.h | 99 + drivers/net/phy/rtl8261n/rtk_phy.c | 324 + drivers/net/phy/rtl8261n/rtk_phylib.c | 108 + drivers/net/phy/rtl8261n/rtk_phylib.h | 106 + drivers/net/phy/rtl8261n/rtk_phylib_def.h | 166 + .../net/phy/rtl8261n/rtk_phylib_rtl826xb.c | 57 + .../net/phy/rtl8261n/rtk_phylib_rtl826xb.h | 19 + drivers/net/phy/rtl8261n/type.h | 117 + drivers/net/phy/rtl8306.c | 1063 + drivers/net/phy/rtl8366_smi.c | 1625 ++ drivers/net/phy/rtl8366_smi.h | 171 + drivers/net/phy/rtl8366rb.c | 1529 ++ drivers/net/phy/rtl8366s.c | 1317 + drivers/net/phy/rtl8367.c | 1859 ++ drivers/net/phy/rtl8367b.c | 1649 ++ drivers/net/phy/swconfig.c | 1242 + drivers/net/phy/swconfig_leds.c | 555 + drivers/nvmem/an8855-efuse.c | 63 + drivers/platform/mikrotik/Kconfig | 31 + drivers/platform/mikrotik/Makefile | 6 + drivers/platform/mikrotik/rb_hardconfig.c | 844 + drivers/platform/mikrotik/rb_hardconfig.h | 32 + drivers/platform/mikrotik/rb_lz77.c | 446 + drivers/platform/mikrotik/rb_lz77.h | 35 + drivers/platform/mikrotik/rb_nvmem.c | 230 + drivers/platform/mikrotik/rb_softconfig.c | 795 + drivers/platform/mikrotik/routerboot.c | 251 + drivers/platform/mikrotik/routerboot.h | 38 + drivers/ssb/fallback-sprom.c | 745 + drivers/ssb/fallback-sprom.h | 7 + include/dt-bindings/mtd/partitions/uimage.h | 198 + include/linux/ar8216_platform.h | 134 + include/linux/ath5k_platform.h | 30 + include/linux/mfd/airoha-an8855-mfd.h | 41 + include/linux/mtd/mtk_bmt.h | 18 + include/linux/myloader.h | 121 + include/linux/platform_data/adm6996-gpio.h | 29 + include/linux/routerboot.h | 106 + include/linux/rtl8366.h | 42 + include/linux/rtl8367.h | 63 + include/linux/switch.h | 179 + include/uapi/linux/switch.h | 119 + 245 files changed, 143699 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml create mode 100644 Documentation/networking/adm6996.txt create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7981-rfb.dts create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi create mode 100644 arch/mips/fw/myloader/Makefile create mode 100644 arch/mips/fw/myloader/myloader.c create mode 100644 drivers/bcma/fallback-sprom.c create mode 100644 drivers/bcma/fallback-sprom.h create mode 100644 drivers/leds/leds-smartrg-system.c create mode 100644 drivers/mfd/airoha-an8855.c create mode 100644 drivers/mtd/mtdsplit/Kconfig create mode 100644 drivers/mtd/mtdsplit/Makefile create mode 100644 drivers/mtd/mtdsplit/mtdsplit.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit.h create mode 100644 drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_brnimage.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_elf.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_eva.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_fit.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_jimage.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_lzma.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_minor.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_seama.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_seil.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_squashfs.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_tplink.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_trx.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_uimage.c create mode 100644 drivers/mtd/mtdsplit/mtdsplit_wrgg.c create mode 100644 drivers/mtd/nand/mtk_bmt.c create mode 100644 drivers/mtd/nand/mtk_bmt.h create mode 100644 drivers/mtd/nand/mtk_bmt_bbt.c create mode 100644 drivers/mtd/nand/mtk_bmt_nmbm.c create mode 100644 drivers/mtd/nand/mtk_bmt_v2.c create mode 100644 drivers/mtd/parsers/routerbootpart.c create mode 100644 drivers/net/dsa/an8855.c create mode 100644 drivers/net/dsa/an8855.h create mode 100644 drivers/net/mdio/mdio-an8855.c create mode 100644 drivers/net/phy/adm6996.c create mode 100644 drivers/net/phy/adm6996.h create mode 100644 drivers/net/phy/air_an8855.c create mode 100644 drivers/net/phy/ar8216.c create mode 100644 drivers/net/phy/ar8216.h create mode 100644 drivers/net/phy/ar8327.c create mode 100644 drivers/net/phy/ar8327.h create mode 100644 drivers/net/phy/b53/Kconfig create mode 100644 drivers/net/phy/b53/Makefile create mode 100644 drivers/net/phy/b53/b53_common.c create mode 100644 drivers/net/phy/b53/b53_mdio.c create mode 100644 drivers/net/phy/b53/b53_mmap.c create mode 100644 drivers/net/phy/b53/b53_phy_fixup.c create mode 100644 drivers/net/phy/b53/b53_priv.h create mode 100644 drivers/net/phy/b53/b53_regs.h create mode 100644 drivers/net/phy/b53/b53_spi.c create mode 100644 drivers/net/phy/b53/b53_srab.c create mode 100644 drivers/net/phy/en8801sc.c create mode 100644 drivers/net/phy/en8801sc.h create mode 100644 drivers/net/phy/ip17xx.c create mode 100644 drivers/net/phy/psb6970.c create mode 100644 drivers/net/phy/rtk/Makefile create mode 100644 drivers/net/phy/rtk/rtl8367c/acl.c create mode 100644 drivers/net/phy/rtk/rtl8367c/cpu.c create mode 100644 drivers/net/phy/rtk/rtl8367c/dot1x.c create mode 100644 drivers/net/phy/rtk/rtl8367c/eee.c create mode 100644 drivers/net/phy/rtk/rtl8367c/i2c.c create mode 100644 drivers/net/phy/rtk/rtl8367c/igmp.c create mode 100644 drivers/net/phy/rtk/rtl8367c/include/acl.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/cpu.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/dot1x.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/eee.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/i2c.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/igmp.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/interrupt.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/l2.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/leaky.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/led.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/mirror.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/oam.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/port.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/ptp.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/qos.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rate.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rldp.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_error.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtk_types.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/smi.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/stat.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/storm.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/svlan.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/trap.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/trunk.h create mode 100644 drivers/net/phy/rtk/rtl8367c/include/vlan.h create mode 100644 drivers/net/phy/rtk/rtl8367c/interrupt.c create mode 100644 drivers/net/phy/rtk/rtl8367c/l2.c create mode 100644 drivers/net/phy/rtk/rtl8367c/leaky.c create mode 100644 drivers/net/phy/rtk/rtl8367c/led.c create mode 100644 drivers/net/phy/rtk/rtl8367c/mirror.c create mode 100644 drivers/net/phy/rtk/rtl8367c/oam.c create mode 100644 drivers/net/phy/rtk/rtl8367c/port.c create mode 100644 drivers/net/phy/rtk/rtl8367c/ptp.c create mode 100644 drivers/net/phy/rtk/rtl8367c/qos.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rate.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rldp.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtk_hal.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtk_switch.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mirror.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c create mode 100644 drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c create mode 100644 drivers/net/phy/rtk/rtl8367c/smi.c create mode 100644 drivers/net/phy/rtk/rtl8367c/stat.c create mode 100644 drivers/net/phy/rtk/rtl8367c/storm.c create mode 100644 drivers/net/phy/rtk/rtl8367c/svlan.c create mode 100644 drivers/net/phy/rtk/rtl8367c/trap.c create mode 100644 drivers/net/phy/rtk/rtl8367c/trunk.c create mode 100644 drivers/net/phy/rtk/rtl8367c/vlan.c create mode 100644 drivers/net/phy/rtk/rtl8367s.c create mode 100644 drivers/net/phy/rtk/rtl8367s_dbg.c create mode 100644 drivers/net/phy/rtk/rtl8367s_mdio.c create mode 100644 drivers/net/phy/rtl8261n/Kconfig create mode 100644 drivers/net/phy/rtl8261n/Makefile create mode 100644 drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c create mode 100644 drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c create mode 100644 drivers/net/phy/rtl8261n/error.h create mode 100644 drivers/net/phy/rtl8261n/phy_patch.c create mode 100644 drivers/net/phy/rtl8261n/phy_patch.h create mode 100644 drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c create mode 100644 drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h create mode 100644 drivers/net/phy/rtl8261n/rtk_osal.c create mode 100644 drivers/net/phy/rtl8261n/rtk_osal.h create mode 100644 drivers/net/phy/rtl8261n/rtk_phy.c create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib.c create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib.h create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_def.h create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c create mode 100644 drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h create mode 100644 drivers/net/phy/rtl8261n/type.h create mode 100644 drivers/net/phy/rtl8306.c create mode 100644 drivers/net/phy/rtl8366_smi.c create mode 100644 drivers/net/phy/rtl8366_smi.h create mode 100644 drivers/net/phy/rtl8366rb.c create mode 100644 drivers/net/phy/rtl8366s.c create mode 100644 drivers/net/phy/rtl8367.c create mode 100644 drivers/net/phy/rtl8367b.c create mode 100644 drivers/net/phy/swconfig.c create mode 100644 drivers/net/phy/swconfig_leds.c create mode 100644 drivers/nvmem/an8855-efuse.c create mode 100644 drivers/platform/mikrotik/Kconfig create mode 100644 drivers/platform/mikrotik/Makefile create mode 100644 drivers/platform/mikrotik/rb_hardconfig.c create mode 100644 drivers/platform/mikrotik/rb_hardconfig.h create mode 100644 drivers/platform/mikrotik/rb_lz77.c create mode 100644 drivers/platform/mikrotik/rb_lz77.h create mode 100644 drivers/platform/mikrotik/rb_nvmem.c create mode 100644 drivers/platform/mikrotik/rb_softconfig.c create mode 100644 drivers/platform/mikrotik/routerboot.c create mode 100644 drivers/platform/mikrotik/routerboot.h create mode 100644 drivers/ssb/fallback-sprom.c create mode 100644 drivers/ssb/fallback-sprom.h create mode 100644 include/dt-bindings/mtd/partitions/uimage.h create mode 100644 include/linux/ar8216_platform.h create mode 100644 include/linux/ath5k_platform.h create mode 100644 include/linux/mfd/airoha-an8855-mfd.h create mode 100644 include/linux/mtd/mtk_bmt.h create mode 100644 include/linux/myloader.h create mode 100644 include/linux/platform_data/adm6996-gpio.h create mode 100644 include/linux/routerboot.h create mode 100644 include/linux/rtl8366.h create mode 100644 include/linux/rtl8367.h create mode 100644 include/linux/switch.h create mode 100644 include/uapi/linux/switch.h diff --git a/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml b/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml new file mode 100644 index 000000000000..d052ab1fc981 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/openwrt,uimage.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OpenWrt variations of U-Boot Image partitions + +maintainers: + - Bjørn Mork + +description: | + The image format defined by the boot loader "Das U-Boot" is often + modified or extended by device vendors. This defines a few optional + properties which can be used to describe such modifications. + +# partition.txt defines common properties, but has not yet been +# converted to YAML +#allOf: +# - $ref: ../partition.yaml# + +properties: + compatible: + items: + - enum: + - openwrt,uimage + - const: denx,uimage + + openwrt,padding: + description: Number of padding bytes between header and data + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + openwrt,ih-magic: + description: U-Boot Image Header magic number. + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0x27051956 # IH_MAGIC + + openwrt,ih-type: + description: U-Boot Image type + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 # IH_TYPE_KERNEL + + openwrt,offset: + description: + Offset between partition start and U-Boot Image in bytes + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + openwrt,partition-magic: + description: + Magic number found at the start of the partition. Will only be + validated if both this property and openwrt,offset is non-zero + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + +required: + - compatible + - reg + +#unevaluatedProperties: false +additionalProperties: false + +examples: + - | + // device with non-default magic + partition@300000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x00300000 0xe80000>; + label = "firmware"; + openwrt,ih-magic = <0x4e474520>; + }; + - | + // device with U-Boot Image at an offset, with a partition magic value + partition@70000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x00070000 0x00790000>; + label = "firmware"; + openwrt,offset = <20>; + openwrt,partition-magic = <0x43535953>; + }; + - | + // device using a non-default image type + #include "dt-bindings/mtd/partitions/uimage.h" + partition@6c0000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x6c0000 0x1900000>; + label = "firmware"; + openwrt,ih-magic = <0x33373033>; + openwrt,ih-type = ; + }; diff --git a/Documentation/networking/adm6996.txt b/Documentation/networking/adm6996.txt new file mode 100644 index 000000000000..ab59f1df0337 --- /dev/null +++ b/Documentation/networking/adm6996.txt @@ -0,0 +1,110 @@ +------- + +ADM6996FC / ADM6996M switch chip driver + + +1. General information + + This driver supports the FC and M models only. The ADM6996F and L are + completely different chips. + + Support for the FC model is extremely limited at the moment. There is no VLAN + support as of yet. The driver will not offer an swconfig interface for the FC + chip. + +1.1 VLAN IDs + + It is possible to define 16 different VLANs. Every VLAN has an identifier, its + VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the + swconfig based configuration is very straightforward. To define two VLANs with + IDs 4 and 5, you can invoke, for example: + + # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' + # swconfig dev ethX vlan 5 set ports '0t 1t 5t' + + The swconfig framework will automatically invoke 'port Y set pvid Z' for every + port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In + this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port + is the VLAN ID associated with untagged packets coming in on that port. + + But if you wish to use VLAN IDs outside the range 0-15, this automatic + behaviour of the swconfig framework becomes a problem. The 16 VLANs that + swconfig can configure on the ADM6996 also have a "vid" setting. By default, + this is the same as the number of the VLAN entry, to make the simple behaviour + above possible. To still support a VLAN with a VLAN ID higher than 15 + (presumably because you are in a network where such VLAN IDs are already in + use), you can change the "vid" setting of the VLAN to anything in the range + 0-1023. But suppose you did the following: + + # swconfig dev ethX vlan 0 set vid 998 + # swconfig dev ethX vlan 0 set ports '0 2 5t' + + Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid + 0'. But the "pvid" should be set to 998, so you are responsible for manually + fixing this! + +1.2 VLAN filtering + + The switch is configured to apply source port filtering. This means that + packets are only accepted when the port the packets came in on is a member of + the VLAN the packet should go to. + + Only membership of a VLAN is tested, it does not matter whether it is a tagged + or untagged membership. + + For untagged packets, the destination VLAN is the Primary VLAN ID of the + incoming port. So if the PVID of a port is 0, but that port is not a member of + the VLAN with ID 0, this means that untagged packets on that port are dropped. + This can be used as a roundabout way of dropping untagged packets from a port, + a mode often referred to as "Admit only tagged packets". + +1.3 Reset + + The two supported chip models do not have a sofware-initiated reset. When the + driver is initialised, as well as when the 'reset' swconfig option is invoked, + the driver will set those registers it knows about and supports to the correct + default value. But there are a lot of registers in the chip that the driver + does not support. If something changed those registers, invoking 'reset' or + performing a warm reboot might still leave the chip in a "broken" state. Only + a hardware reset will bring it back in the default state. + +2. Technical details on PHYs and the ADM6996 + + From the viewpoint of the Linux kernel, it is common that an Ethernet adapter + can be seen as a separate MAC entity and a separate PHY entity. The PHY entity + can be queried and set through registers accessible via an MDIO bus. A PHY + normally has a single address on that bus, in the range 0 through 31. + + The ADM6996 has special-purpose registers in the range of PHYs 0 through 10. + Even though all these registers control a single ADM6996 chip, the Linux + kernel treats this as 11 separate PHYs. The driver will bind to these + addresses to prevent a different PHY driver from binding and corrupting these + registers. + + What Linux sees as the PHY on address 0 is meant for the Ethernet MAC + connected to the CPU port of the ADM6996 switch chip (port 5). This is the + Ethernet MAC you will use to send and receive data through the switch. + + The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of + the switch chip. These can be accessed with the Generic PHY driver, as the + registers have the common layout. + + If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC + needs to bind to PHY address 20 for the port to work correctly. + + The ADM6996 switch driver will reset the ports 0 through 3 on startup and when + 'reset' is invoked. This could clash with a different PHY driver if the kernel + binds a PHY driver to address 16 through 19. + + If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996 + driver will simply always report a connected 100 Mbit/s full-duplex link for + that PHY, and provide no other functionality. This is most likely not what you + want. So if you see a message in your log + + ethX: PHY overlaps ADM6996, providing fixed PHY yy. + + This is most likely an indication that ethX will not work properly, and your + kernel needs to be configured to attach a different PHY to that Ethernet MAC. + + Controlling the mapping between MACs and PHYs is usually done in platform- or + board-specific fixup code. The ADM6996 driver has no influence over this. diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso new file mode 100644 index 000000000000..51d5dc661ad6 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-eth1.dtso @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; + + fragment@0 { + target = <&gmac1>; + __overlay__ { + phy-mode = "2500base-x"; + phy-handle = <&phy5>; + }; + }; + + fragment@1 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + reset-gpios = <&pio 14 GPIO_ACTIVE_LOW>; + reset-delay-us = <600>; + reset-post-delay-us = <20000>; + + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso new file mode 100644 index 000000000000..4cc3cf1df6cf --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-mxl-2p5g-phy-swp5.dtso @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; + + fragment@0 { + target = <&sw_p5>; + __overlay__ { + phy-mode = "2500base-x"; + phy-handle = <&phy5>; + status = "okay"; + }; + }; + + fragment@1 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + reset-gpios = <&pio 14 GPIO_ACTIVE_LOW>; + reset-delay-us = <600>; + reset-post-delay-us = <20000>; + + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso new file mode 100644 index 000000000000..af4845ec6cff --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nand.dtso @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; + + fragment@0 { + target = <&chosen>; + rootdisk-spim-nand = <&ubi_rootdisk>; + }; + + fragment@1 { + target = <&spi0>; + __overlay__ { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + spi_nand: spi_nand@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x00000 0x0100000>; + read-only; + }; + + partition@100000 { + label = "u-boot-env"; + reg = <0x0100000 0x0080000>; + }; + + factory: partition@180000 { + label = "Factory"; + reg = <0x180000 0x0200000>; + }; + + partition@380000 { + label = "FIP"; + reg = <0x380000 0x0200000>; + }; + + partition@580000 { + label = "ubi"; + reg = <0x580000 0x4000000>; + compatible = "linux,ubi"; + + volumes { + ubi_rootdisk: ubi-volume-fit { + volname = "fit"; + }; + }; + }; + }; + }; + }; + }; + + fragment@2 { + target = <&wifi>; + __overlay__ { + mediatek,mtd-eeprom = <&factory 0x0>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts new file mode 100644 index 000000000000..155157762479 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7981b.dtsi" + +/ { + model = "MediaTek MT7981 RFB"; + compatible = "mediatek,mt7981-rfb", "mediatek,mt7981"; + + aliases { + serial0 = &uart0; + }; + + chosen: chosen { + stdout-path = "serial0:115200n8"; + bootargs-append = " root=/dev/fit0 rootwait"; + }; + + memory@40000000 { + reg = <0 0x40000000 0 0x20000000>; + device_type = "memory"; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; + + gpio-keys { + compatible = "gpio-keys"; + reset { + label = "reset"; + linux,code = ; + gpios = <&pio 1 GPIO_ACTIVE_LOW>; + }; + wps { + label = "wps"; + linux,code = ; + gpios = <&pio 0 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "gmii"; + phy-handle = <&int_gbe_phy>; + }; +}; + +&mdio_bus { + switch: switch@1f { + compatible = "mediatek,mt7531"; + reg = <31>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&pio>; + interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; + reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&crypto { + status = "okay"; +}; + +&pio { + spi0_flash_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + conf-pu { + pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; + drive-strength = ; + bias-pull-up = ; + }; + conf-pd { + pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; + drive-strength = ; + bias-pull-down = ; + }; + }; + +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; + +&switch { + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan1"; + }; + + port@1 { + reg = <1>; + label = "lan2"; + }; + + port@2 { + reg = <2>; + label = "lan3"; + }; + + port@3 { + reg = <3>; + label = "lan4"; + }; + + sw_p5: port@5 { + reg = <5>; + label = "lan5"; + status = "disabled"; + }; + + port@6 { + reg = <6>; + ethernet = <&gmac0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + }; +}; + +&xhci { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts new file mode 100644 index 000000000000..479a5ca2fc4d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ + +#include "mt7986a-rfb.dtsi" + +/ { + compatible = "mediatek,mt7986a-rfb-snand"; +}; + +&spi0 { + status = "okay"; + + spi_nand: spi_nand@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "BL2"; + reg = <0x00000 0x0100000>; + read-only; + }; + partition@100000 { + label = "u-boot-env"; + reg = <0x0100000 0x0080000>; + }; + factory: partition@180000 { + label = "Factory"; + reg = <0x180000 0x0200000>; + }; + partition@380000 { + label = "FIP"; + reg = <0x380000 0x0200000>; + }; + partition@580000 { + label = "ubi"; + reg = <0x580000 0x4000000>; + }; + }; + }; +}; + +&wifi { + mediatek,mtd-eeprom = <&factory 0>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts new file mode 100644 index 000000000000..ea148315f055 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nor.dts @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ + +#include "mt7986a-rfb.dtsi" + +/ { + compatible = "mediatek,mt7986a-rfb-snor"; +}; + +&spi0 { + status = "okay"; + + spi_nor: spi_nor@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@00000 { + label = "BL2"; + reg = <0x00000 0x0040000>; + }; + partition@40000 { + label = "u-boot-env"; + reg = <0x40000 0x0010000>; + }; + factory: partition@50000 { + label = "Factory"; + reg = <0x50000 0x00B0000>; + }; + partition@100000 { + label = "FIP"; + reg = <0x100000 0x0080000>; + }; + partition@180000 { + label = "firmware"; + reg = <0x180000 0xE00000>; + }; + }; + }; +}; + +&wifi { + mediatek,mtd-eeprom = <&factory 0>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi new file mode 100644 index 000000000000..1dfb64d4565e --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb.dtsi @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include +#include +#include "mt7986a.dtsi" + +/ { + model = "MediaTek MT7986a RFB"; + compatible = "mediatek,mt7986a-rfb"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "2500base-x"; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&wifi { + status = "okay"; + pinctrl-names = "default", "dbdc"; + pinctrl-0 = <&wf_2g_5g_pins>; + pinctrl-1 = <&wf_dbdc_pins>; +}; + +&mdio { + phy5: phy@5 { + compatible = "ethernet-phy-id67c9.de0a"; + reg = <5>; + + reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>; + reset-deassert-us = <20000>; + }; + + phy6: phy@6 { + compatible = "ethernet-phy-id67c9.de0a"; + reg = <6>; + }; + + switch: switch@1f { + compatible = "mediatek,mt7531"; + reg = <31>; + reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&crypto { + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + hs400-ds-delay = <0x14014>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + non-removable; + no-sd; + no-sdio; + status = "okay"; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +&pio { + mmc0_pins_default: mmc0-pins { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = ; + bias-pull-up = ; /* pull-up 10K */ + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = ; + bias-pull-down = ; /* pull-down 50K */ + }; + conf-ds { + pins = "EMMC_DSL"; + bias-pull-down = ; /* pull-down 50K */ + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = ; + bias-pull-up = ; /* pull-up 10K */ + }; + }; + + mmc0_pins_uhs: mmc0-uhs-pins { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = ; + bias-pull-up = ; /* pull-up 10K */ + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = ; + bias-pull-down = ; /* pull-down 50K */ + }; + conf-ds { + pins = "EMMC_DSL"; + bias-pull-down = ; /* pull-down 50K */ + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = ; + bias-pull-up = ; /* pull-up 10K */ + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_clk", "pcie_wake", "pcie_pereset"; + }; + }; + + spic_pins_g2: spic-pins-29-to-32 { + mux { + function = "spi"; + groups = "spi1_2"; + }; + }; + + spi_flash_pins: spi-flash-pins-33-to-38 { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + conf-pu { + pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; + drive-strength = ; + bias-disable; /* bias-disable */ + }; + conf-pd { + pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; + drive-strength = ; + bias-disable; /* bias-disable */ + }; + }; + + uart1_pins: uart1-pins { + mux { + function = "uart"; + groups = "uart1"; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2"; + }; + }; + + wf_2g_5g_pins: wf_2g_5g-pins { + mux { + function = "wifi"; + groups = "wf_2g", "wf_5g"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = ; + }; + }; + + wf_dbdc_pins: wf_dbdc-pins { + mux { + function = "wifi"; + groups = "wf_dbdc"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = ; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi_flash_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spic_pins_g2>; + status = "okay"; + + proslic_spi: proslic_spi@0 { + compatible = "silabs,proslic_spi"; + reg = <0>; + spi-max-frequency = <10000000>; + spi-cpha = <1>; + spi-cpol = <1>; + channel_count = <1>; + debug_level = <4>; /* 1 = TRC, 2 = DBG, 4 = ERR */ + reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>; + ig,enable-spi = <1>; /* 1: Enable, 0: Disable */ + }; +}; + +&gmac1 { + phy-mode = "2500base-x"; + phy-connection-type = "2500base-x"; + phy-handle = <&phy6>; +}; + +&switch { + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan1"; + }; + + port@1 { + reg = <1>; + label = "lan2"; + }; + + port@2 { + reg = <2>; + label = "lan3"; + }; + + port@3 { + reg = <3>; + label = "lan4"; + }; + + port@4 { + reg = <4>; + label = "wan"; + }; + + port@5 { + reg = <5>; + label = "lan6"; + + phy-mode = "2500base-x"; + phy-handle = <&phy5>; + }; + + port@6 { + reg = <6>; + ethernet = <&gmac0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + }; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; diff --git a/arch/mips/fw/myloader/Makefile b/arch/mips/fw/myloader/Makefile new file mode 100644 index 000000000000..34acfd01cc0a --- /dev/null +++ b/arch/mips/fw/myloader/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Compex's MyLoader support on MIPS architecture +# + +lib-y += myloader.o diff --git a/arch/mips/fw/myloader/myloader.c b/arch/mips/fw/myloader/myloader.c new file mode 100644 index 000000000000..a26f9ad3fdbf --- /dev/null +++ b/arch/mips/fw/myloader/myloader.c @@ -0,0 +1,63 @@ +/* + * Compex's MyLoader specific prom routines + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include +#include + +#define SYS_PARAMS_ADDR KSEG1ADDR(0x80000800) +#define BOARD_PARAMS_ADDR KSEG1ADDR(0x80000A00) +#define PART_TABLE_ADDR KSEG1ADDR(0x80000C00) +#define BOOT_PARAMS_ADDR KSEG1ADDR(0x80000E00) + +static struct myloader_info myloader_info __initdata; +static int myloader_found __initdata; + +struct myloader_info * __init myloader_get_info(void) +{ + struct mylo_system_params *sysp; + struct mylo_board_params *boardp; + struct mylo_partition_table *parts; + + if (myloader_found) + return &myloader_info; + + sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR); + boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR); + parts = (struct mylo_partition_table *)(PART_TABLE_ADDR); + + printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n", + sysp->magic, boardp->magic, parts->magic); + + /* Check for some magic numbers */ + if (sysp->magic != MYLO_MAGIC_SYS_PARAMS || + boardp->magic != MYLO_MAGIC_BOARD_PARAMS || + le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS) + return NULL; + + printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n", + sysp->vid, sysp->did, sysp->svid, sysp->sdid); + + myloader_info.vid = sysp->vid; + myloader_info.did = sysp->did; + myloader_info.svid = sysp->svid; + myloader_info.sdid = sysp->sdid; + + memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs)); + + myloader_found = 1; + + return &myloader_info; +} diff --git a/drivers/bcma/fallback-sprom.c b/drivers/bcma/fallback-sprom.c new file mode 100644 index 000000000000..6932c3c8f574 --- /dev/null +++ b/drivers/bcma/fallback-sprom.c @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * BCMA Fallback SPROM Driver + * + * Copyright (C) 2020 Álvaro Fernández Rojas + * Copyright (C) 2014 Jonas Gorski + * Copyright (C) 2008 Maxime Bizon + * Copyright (C) 2008 Florian Fainelli + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "fallback-sprom.h" + +#define BCMA_FBS_MAX_SIZE 468 + +/* SPROM Extraction */ +#define SPOFF(offset) ((offset) / sizeof(u16)) + +#define SPEX(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) + +#define SPEX32(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ + in[SPOFF(_offset)]) & (_mask)) >> (_shift)) + +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + +struct bcma_fbs { + struct device *dev; + struct list_head list; + struct ssb_sprom sprom; + u32 pci_bus; + u32 pci_dev; + bool devid_override; +}; + +static DEFINE_SPINLOCK(bcma_fbs_lock); +static struct list_head bcma_fbs_list = LIST_HEAD_INIT(bcma_fbs_list); + +int bcma_get_fallback_sprom(struct bcma_bus *bus, struct ssb_sprom *out) +{ + struct bcma_fbs *pos; + u32 pci_bus, pci_dev; + + if (bus->hosttype != BCMA_HOSTTYPE_PCI) + return -ENOENT; + + pci_bus = bus->host_pci->bus->number; + pci_dev = PCI_SLOT(bus->host_pci->devfn); + + list_for_each_entry(pos, &bcma_fbs_list, list) { + if (pos->pci_bus != pci_bus || + pos->pci_dev != pci_dev) + continue; + + if (pos->devid_override) + bus->host_pci->device = pos->sprom.dev_id; + + memcpy(out, &pos->sprom, sizeof(struct ssb_sprom)); + dev_info(pos->dev, "requested by [%x:%x]", + pos->pci_bus, pos->pci_dev); + + return 0; + } + + pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus, pci_dev); + + return -EINVAL; +} + +static s8 sprom_extract_antgain(const u16 *in, u16 offset, u16 mask, u16 shift) +{ + u16 v; + u8 gain; + + v = in[SPOFF(offset)]; + gain = (v & mask) >> shift; + if (gain == 0xFF) { + gain = 8; /* If unset use 2dBm */ + } else { + /* Q5.2 Fractional part is stored in 0xC0 */ + gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); + } + + return (s8)gain; +} + +static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) +{ + static const u16 pwr_info_offset[] = { + SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, + SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 + }; + u16 o; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != + ARRAY_SIZE(out->core_pwr_info)); + + SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0); + SPEX(board_type, SSB_SPROM1_SPID, ~0, 0); + + SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0, + SSB_SPROM4_TXPID2G0_SHIFT); + SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G1, + SSB_SPROM4_TXPID2G1_SHIFT); + SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G2, + SSB_SPROM4_TXPID2G2_SHIFT); + SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, SSB_SPROM4_TXPID2G3, + SSB_SPROM4_TXPID2G3_SHIFT); + + SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL0, + SSB_SPROM4_TXPID5GL0_SHIFT); + SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, SSB_SPROM4_TXPID5GL1, + SSB_SPROM4_TXPID5GL1_SHIFT); + SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL2, + SSB_SPROM4_TXPID5GL2_SHIFT); + SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, SSB_SPROM4_TXPID5GL3, + SSB_SPROM4_TXPID5GL3_SHIFT); + + SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G0, + SSB_SPROM4_TXPID5G0_SHIFT); + SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, SSB_SPROM4_TXPID5G1, + SSB_SPROM4_TXPID5G1_SHIFT); + SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G2, + SSB_SPROM4_TXPID5G2_SHIFT); + SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, SSB_SPROM4_TXPID5G3, + SSB_SPROM4_TXPID5G3_SHIFT); + + SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH0, + SSB_SPROM4_TXPID5GH0_SHIFT); + SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, SSB_SPROM4_TXPID5GH1, + SSB_SPROM4_TXPID5GH1_SHIFT); + SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH2, + SSB_SPROM4_TXPID5GH2_SHIFT); + SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, SSB_SPROM4_TXPID5GH3, + SSB_SPROM4_TXPID5GH3_SHIFT); + + SPEX(boardflags_lo, SSB_SPROM8_BFLLO, ~0, 0); + SPEX(boardflags_hi, SSB_SPROM8_BFLHI, ~0, 0); + SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); + SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); + + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); + + /* Extract core's power info */ + for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { + o = pwr_info_offset[i]; + SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, + SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, + SSB_SPROM8_2G_MAXP, 0); + + SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); + + SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, + SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, + SSB_SPROM8_5G_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, + SSB_SPROM8_5GH_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, + SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); + + SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); + } + + SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TSSIPOS, + SSB_SROM8_FEM_TSSIPOS_SHIFT); + SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_EXTPA_GAIN, + SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); + SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_PDET_RANGE, + SSB_SROM8_FEM_PDET_RANGE_SHIFT); + SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_TR_ISO, + SSB_SROM8_FEM_TR_ISO_SHIFT); + SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, SSB_SROM8_FEM_ANTSWLUT, + SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TSSIPOS, + SSB_SROM8_FEM_TSSIPOS_SHIFT); + SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_EXTPA_GAIN, + SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); + SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_PDET_RANGE, + SSB_SROM8_FEM_PDET_RANGE_SHIFT); + SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_TR_ISO, + SSB_SROM8_FEM_TR_ISO_SHIFT); + SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, + SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, + SSB_SPROM8_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, + SSB_SPROM8_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, + SSB_SPROM8_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, + SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); + SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, + SSB_SPROM8_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, + SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, + SSB_SPROM8_RXPO2G_SHIFT); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + + SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0); + + /* Extract the antenna gain values. */ + out->antenna_gain.a0 = sprom_extract_antgain(in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, + SSB_SPROM8_AGAIN0_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, + SSB_SPROM8_AGAIN1_SHIFT); + out->antenna_gain.a2 = sprom_extract_antgain(in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, + SSB_SPROM8_AGAIN2_SHIFT); + out->antenna_gain.a3 = sprom_extract_antgain(in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, + SSB_SPROM8_AGAIN3_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); +} + +static int sprom_extract(struct bcma_fbs *priv, const u16 *in, u16 size) +{ + struct ssb_sprom *out = &priv->sprom; + + memset(out, 0, sizeof(*out)); + + out->revision = in[size - 1] & 0x00FF; + if (out->revision < 8 || out->revision > 11) { + dev_warn(priv->dev, + "Unsupported SPROM revision %d detected." + " Will extract v8\n", + out->revision); + out->revision = 8; + } + + sprom_extract_r8(out, in); + + return 0; +} + +static void bcma_fbs_fixup(struct bcma_fbs *priv, u16 *sprom) +{ + struct device_node *node = priv->dev->of_node; + u32 fixups, off, val; + int i = 0; + + if (!of_get_property(node, "brcm,sprom-fixups", &fixups)) + return; + + fixups /= sizeof(u32); + + dev_info(priv->dev, "patching SPROM with %u fixups...\n", fixups >> 1); + + while (i < fixups) { + if (of_property_read_u32_index(node, "brcm,sprom-fixups", + i++, &off)) { + dev_err(priv->dev, "error reading fixup[%u] offset\n", + i - 1); + return; + } + + if (of_property_read_u32_index(node, "brcm,sprom-fixups", + i++, &val)) { + dev_err(priv->dev, "error reading fixup[%u] value\n", + i - 1); + return; + } + + dev_dbg(priv->dev, "fixup[%d]=0x%04x\n", off, val); + + sprom[off] = val; + } +} + +static bool sprom_override_devid(struct bcma_fbs *priv, struct ssb_sprom *out, + const u16 *in) +{ + SPEX(dev_id, 0x0060, 0xFFFF, 0); + return !!out->dev_id; +} + +static void bcma_fbs_set(struct bcma_fbs *priv, struct device_node *node) +{ + struct ssb_sprom *sprom = &priv->sprom; + const struct firmware *fw; + const char *sprom_name; + int err; + + if (of_property_read_string(node, "brcm,sprom", &sprom_name)) + sprom_name = NULL; + + if (sprom_name) { + err = request_firmware_direct(&fw, sprom_name, priv->dev); + if (err) + dev_err(priv->dev, "%s load error\n", sprom_name); + } else { + err = -ENOENT; + } + + if (err) { + sprom->revision = 0x02; + sprom->board_rev = 0x0017; + sprom->country_code = 0x00; + sprom->ant_available_bg = 0x03; + sprom->pa0b0 = 0x15ae; + sprom->pa0b1 = 0xfa85; + sprom->pa0b2 = 0xfe8d; + sprom->pa1b0 = 0xffff; + sprom->pa1b1 = 0xffff; + sprom->pa1b2 = 0xffff; + sprom->gpio0 = 0xff; + sprom->gpio1 = 0xff; + sprom->gpio2 = 0xff; + sprom->gpio3 = 0xff; + sprom->maxpwr_bg = 0x4c; + sprom->itssi_bg = 0x00; + sprom->boardflags_lo = 0x2848; + sprom->boardflags_hi = 0x0000; + priv->devid_override = false; + + dev_warn(priv->dev, "using basic SPROM\n"); + } else { + size_t size = min(fw->size, (size_t) BCMA_FBS_MAX_SIZE); + u16 tmp_sprom[BCMA_FBS_MAX_SIZE >> 1]; + u32 i, j; + + for (i = 0, j = 0; i < size; i += 2, j++) + tmp_sprom[j] = (fw->data[i] << 8) | fw->data[i + 1]; + + release_firmware(fw); + bcma_fbs_fixup(priv, tmp_sprom); + sprom_extract(priv, tmp_sprom, size >> 1); + + priv->devid_override = sprom_override_devid(priv, sprom, + tmp_sprom); + } +} + +static int bcma_fbs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct bcma_fbs *priv; + unsigned long flags; + u8 mac[ETH_ALEN]; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + bcma_fbs_set(priv, node); + + of_property_read_u32(node, "pci-bus", &priv->pci_bus); + of_property_read_u32(node, "pci-dev", &priv->pci_dev); + + of_get_mac_address(node, mac); + if (is_valid_ether_addr(mac)) { + dev_info(dev, "mtd mac %pM\n", mac); + } else { + eth_random_addr(mac); + dev_info(dev, "random mac %pM\n", mac); + } + + memcpy(priv->sprom.il0mac, mac, ETH_ALEN); + memcpy(priv->sprom.et0mac, mac, ETH_ALEN); + memcpy(priv->sprom.et1mac, mac, ETH_ALEN); + memcpy(priv->sprom.et2mac, mac, ETH_ALEN); + + spin_lock_irqsave(&bcma_fbs_lock, flags); + list_add(&priv->list, &bcma_fbs_list); + spin_unlock_irqrestore(&bcma_fbs_lock, flags); + + dev_info(dev, "registered SPROM for [%x:%x]\n", + priv->pci_bus, priv->pci_dev); + + return 0; +} + +static const struct of_device_id bcma_fbs_of_match[] = { + { .compatible = "brcm,bcma-sprom", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcma_fbs_of_match); + +static struct platform_driver bcma_fbs_driver = { + .probe = bcma_fbs_probe, + .driver = { + .name = "bcma-sprom", + .of_match_table = bcma_fbs_of_match, + }, +}; + +int __init bcma_fbs_register(void) +{ + return platform_driver_register(&bcma_fbs_driver); +} diff --git a/drivers/bcma/fallback-sprom.h b/drivers/bcma/fallback-sprom.h new file mode 100644 index 000000000000..363663413dc4 --- /dev/null +++ b/drivers/bcma/fallback-sprom.h @@ -0,0 +1,7 @@ +#ifndef _FALLBACK_SPROM_H +#define _FALLBACK_SPROM_H + +int __init bcma_fbs_register(void); +int bcma_get_fallback_sprom(struct bcma_bus *dev, struct ssb_sprom *out); + +#endif /* _FALLBACK_SPROM_H */ diff --git a/drivers/leds/leds-smartrg-system.c b/drivers/leds/leds-smartrg-system.c new file mode 100644 index 000000000000..c1770aa81b59 --- /dev/null +++ b/drivers/leds/leds-smartrg-system.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include + +/** + * Driver for SmartRG RGBW LED microcontroller. + * RGBW LED is connected to a Holtek HT45F0062 that is on the I2C bus. + * + */ + +struct srg_led_ctrl; +struct srg_led { + u8 index; + struct led_classdev led; + struct srg_led_ctrl *ctrl; +}; + +struct srg_led_ctrl { + struct mutex lock; + struct i2c_client *client; + struct srg_led channel[4]; + u8 control[5]; +}; + +static int +srg_led_i2c_write(struct srg_led_ctrl *sysled_ctrl, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(sysled_ctrl->client, reg, value); +} + +/* + * MC LED Command: 0 = OFF, 1 = ON, 2 = Flash, 3 = Pulse, 4 = Blink + * */ +static int +srg_led_control_sync(struct srg_led_ctrl *sysled_ctrl) +{ + int i, ret; + + for (i = 1; i < 5; i++) { + ret = srg_led_i2c_write(sysled_ctrl, i, sysled_ctrl->control[i]); + if (ret) + break; + } + return ret; +} + +/* + * This function overrides the led driver timer trigger to offload + * flashing to the micro-controller. The negative effect of this + * is the inability to configure the delay_on and delay_off periods. + * + * */ +static int +srg_led_set_pulse(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct srg_led *sysled = container_of(led_cdev, struct srg_led, led); + struct srg_led_ctrl *sysled_ctrl = sysled->ctrl; + bool blinking = false, pulsing = false; + u8 cbyte; + int ret; + + if (delay_on && delay_off && (*delay_on > 100) && (*delay_on <= 500)) { + pulsing = true; + *delay_on = 500; + *delay_off = 500; + } else if (delay_on && delay_off && (*delay_on >= 50) && (*delay_on <= 100)) { + blinking = true; + *delay_on = 50; + *delay_off = 50; + } + + cbyte = pulsing ? 3 : blinking ? 2 : 0; + mutex_lock(&sysled_ctrl->lock); + ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4, + (blinking || pulsing) ? 255 : 0); + if (!ret) { + sysled_ctrl->control[sysled->index] = cbyte; + ret = srg_led_control_sync(sysled_ctrl); + } + mutex_unlock(&sysled_ctrl->lock); + + return !cbyte; +} + +static int +srg_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct srg_led *sysled = container_of(led_cdev, struct srg_led, led); + struct srg_led_ctrl *sysled_ctrl = sysled->ctrl; + int ret; + + mutex_lock(&sysled_ctrl->lock); + ret = srg_led_i2c_write(sysled_ctrl, sysled->index + 4, value); + if (!ret) { + sysled_ctrl->control[sysled->index] = !!value; + ret = srg_led_control_sync(sysled_ctrl); + } + mutex_unlock(&sysled_ctrl->lock); + return ret; +} + +static int +srg_led_init_led(struct srg_led_ctrl *sysled_ctrl, struct device_node *np) +{ + struct led_init_data init_data = {}; + struct led_classdev *led_cdev; + struct srg_led *sysled; + int index, ret; + + if (!np) + return -ENOENT; + + ret = of_property_read_u32(np, "reg", &index); + if (ret) { + dev_err(&sysled_ctrl->client->dev, + "srg_led_init_led: no reg defined in np!\n"); + return ret; + } + + if (index < 1 || index > 4) + return -EINVAL; + + sysled = &sysled_ctrl->channel[index - 1]; + led_cdev = &sysled->led; + + sysled->index = index; + sysled->ctrl = sysled_ctrl; + + init_data.fwnode = of_fwnode_handle(np); + + led_cdev->name = of_get_property(np, "label", NULL) ? : np->name; + led_cdev->brightness = LED_OFF; + led_cdev->max_brightness = LED_FULL; + led_cdev->brightness_set_blocking = srg_led_set_brightness; + led_cdev->blink_set = srg_led_set_pulse; + + srg_led_i2c_write(sysled_ctrl, index + 4, 0); + + ret = devm_led_classdev_register_ext(&sysled_ctrl->client->dev, + led_cdev, &init_data); + if (ret) { + dev_err(&sysled_ctrl->client->dev, + "srg_led_init_led: led register %s error ret %d!n", + led_cdev->name, ret); + return ret; + } + + return 0; +} + +static int + +srg_led_probe(struct i2c_client *client) +{ + struct device_node *np = client->dev.of_node, *child; + struct srg_led_ctrl *sysled_ctrl; + int err; + + sysled_ctrl = devm_kzalloc(&client->dev, sizeof(*sysled_ctrl), GFP_KERNEL); + if (!sysled_ctrl) + return -ENOMEM; + + sysled_ctrl->client = client; + + err = devm_mutex_init(&client->dev, &sysled_ctrl->lock); + if (err) + return err; + + i2c_set_clientdata(client, sysled_ctrl); + + for_each_available_child_of_node(np, child) { + if (srg_led_init_led(sysled_ctrl, child)) + continue; + + msleep(5); + } + + return srg_led_control_sync(sysled_ctrl);; +} + +static void srg_led_disable(struct i2c_client *client) +{ + struct srg_led_ctrl *sysled_ctrl = i2c_get_clientdata(client); + int i; + + for (i = 1; i < 10; i++) + srg_led_i2c_write(sysled_ctrl, i, 0); +} + +static const struct i2c_device_id srg_led_id[] = { + { "srg-sysled", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, srg_led_id); + +static const struct of_device_id of_srg_led_match[] = { + { .compatible = "srg,sysled", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_srg_led_match); + +static struct i2c_driver srg_sysled_driver = { + .driver = { + .name = "srg-sysled", + .of_match_table = of_srg_led_match, + }, + .probe = srg_led_probe, + .remove = srg_led_disable, + .id_table = srg_led_id, +}; +module_i2c_driver(srg_sysled_driver); + +MODULE_DESCRIPTION("SmartRG system LED driver"); +MODULE_AUTHOR("Shen Loh "); +MODULE_AUTHOR("Daniel Golle "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/airoha-an8855.c b/drivers/mfd/airoha-an8855.c new file mode 100644 index 000000000000..eeaea348aa41 --- /dev/null +++ b/drivers/mfd/airoha-an8855.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MFD driver for Airoha AN8855 Switch + */ + +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell an8855_mfd_devs[] = { + { + .name = "an8855-efuse", + .of_compatible = "airoha,an8855-efuse", + }, { + .name = "an8855-switch", + .of_compatible = "airoha,an8855-switch", + }, { + .name = "an8855-mdio", + .of_compatible = "airoha,an8855-mdio", + } +}; + +int an8855_mii_set_page(struct an8855_mfd_priv *priv, u8 phy_id, + u8 page) __must_hold(&priv->bus->mdio_lock) +{ + struct mii_bus *bus = priv->bus; + int ret; + + ret = __mdiobus_write(bus, phy_id, AN8855_PHY_SELECT_PAGE, page); + if (ret < 0) + dev_err_ratelimited(&bus->dev, + "failed to set an8855 mii page\n"); + + /* Cache current page if next mii read/write is for switch */ + priv->current_page = page; + return ret < 0 ? ret : 0; +} +EXPORT_SYMBOL_GPL(an8855_mii_set_page); + +static int an8855_mii_read32(struct mii_bus *bus, u8 phy_id, u32 reg, + u32 *val) __must_hold(&bus->mdio_lock) +{ + int lo, hi, ret; + + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_MODE, + AN8855_PBUS_MODE_ADDR_FIXED); + if (ret < 0) + goto err; + + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_RD_ADDR_HIGH, + upper_16_bits(reg)); + if (ret < 0) + goto err; + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_RD_ADDR_LOW, + lower_16_bits(reg)); + if (ret < 0) + goto err; + + hi = __mdiobus_read(bus, phy_id, AN8855_PBUS_RD_DATA_HIGH); + if (hi < 0) { + ret = hi; + goto err; + } + lo = __mdiobus_read(bus, phy_id, AN8855_PBUS_RD_DATA_LOW); + if (lo < 0) { + ret = lo; + goto err; + } + + *val = ((u16)hi << 16) | ((u16)lo & 0xffff); + + return 0; +err: + dev_err_ratelimited(&bus->dev, + "failed to read an8855 register\n"); + return ret; +} + +static int an8855_regmap_read(void *ctx, uint32_t reg, uint32_t *val) +{ + struct an8855_mfd_priv *priv = ctx; + struct mii_bus *bus = priv->bus; + u16 addr = priv->switch_addr; + int ret; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); + if (ret < 0) + goto exit; + + ret = an8855_mii_read32(bus, addr, reg, val); + +exit: + mutex_unlock(&bus->mdio_lock); + + return ret < 0 ? ret : 0; +} + +static int an8855_mii_write32(struct mii_bus *bus, u8 phy_id, u32 reg, + u32 val) __must_hold(&bus->mdio_lock) +{ + int ret; + + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_MODE, + AN8855_PBUS_MODE_ADDR_FIXED); + if (ret < 0) + goto err; + + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_ADDR_HIGH, + upper_16_bits(reg)); + if (ret < 0) + goto err; + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_ADDR_LOW, + lower_16_bits(reg)); + if (ret < 0) + goto err; + + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_DATA_HIGH, + upper_16_bits(val)); + if (ret < 0) + goto err; + ret = __mdiobus_write(bus, phy_id, AN8855_PBUS_WR_DATA_LOW, + lower_16_bits(val)); + if (ret < 0) + goto err; + + return 0; +err: + dev_err_ratelimited(&bus->dev, + "failed to write an8855 register\n"); + return ret; +} + +static int +an8855_regmap_write(void *ctx, uint32_t reg, uint32_t val) +{ + struct an8855_mfd_priv *priv = ctx; + struct mii_bus *bus = priv->bus; + u16 addr = priv->switch_addr; + int ret; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); + if (ret < 0) + goto exit; + + ret = an8855_mii_write32(bus, addr, reg, val); + +exit: + mutex_unlock(&bus->mdio_lock); + + return ret < 0 ? ret : 0; +} + +static int an8855_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, + uint32_t write_val) +{ + struct an8855_mfd_priv *priv = ctx; + struct mii_bus *bus = priv->bus; + u16 addr = priv->switch_addr; + u32 val; + int ret; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + ret = an8855_mii_set_page(priv, addr, AN8855_PHY_PAGE_EXTENDED_4); + if (ret < 0) + goto exit; + + ret = an8855_mii_read32(bus, addr, reg, &val); + if (ret < 0) + goto exit; + + val &= ~mask; + val |= write_val; + ret = an8855_mii_write32(bus, addr, reg, val); + +exit: + mutex_unlock(&bus->mdio_lock); + + return ret < 0 ? ret : 0; +} + +static const struct regmap_range an8855_readable_ranges[] = { + regmap_reg_range(0x10000000, 0x10000fff), /* SCU */ + regmap_reg_range(0x10001000, 0x10001fff), /* RBUS */ + regmap_reg_range(0x10002000, 0x10002fff), /* MCU */ + regmap_reg_range(0x10005000, 0x10005fff), /* SYS SCU */ + regmap_reg_range(0x10007000, 0x10007fff), /* I2C Slave */ + regmap_reg_range(0x10008000, 0x10008fff), /* I2C Master */ + regmap_reg_range(0x10009000, 0x10009fff), /* PDMA */ + regmap_reg_range(0x1000a100, 0x1000a2ff), /* General Purpose Timer */ + regmap_reg_range(0x1000a200, 0x1000a2ff), /* GPU timer */ + regmap_reg_range(0x1000a300, 0x1000a3ff), /* GPIO */ + regmap_reg_range(0x1000a400, 0x1000a5ff), /* EFUSE */ + regmap_reg_range(0x1000c000, 0x1000cfff), /* GDMP CSR */ + regmap_reg_range(0x10010000, 0x1001ffff), /* GDMP SRAM */ + regmap_reg_range(0x10200000, 0x10203fff), /* Switch - ARL Global */ + regmap_reg_range(0x10204000, 0x10207fff), /* Switch - BMU */ + regmap_reg_range(0x10208000, 0x1020bfff), /* Switch - ARL Port */ + regmap_reg_range(0x1020c000, 0x1020cfff), /* Switch - SCH */ + regmap_reg_range(0x10210000, 0x10213fff), /* Switch - MAC */ + regmap_reg_range(0x10214000, 0x10217fff), /* Switch - MIB */ + regmap_reg_range(0x10218000, 0x1021bfff), /* Switch - Port Control */ + regmap_reg_range(0x1021c000, 0x1021ffff), /* Switch - TOP */ + regmap_reg_range(0x10220000, 0x1022ffff), /* SerDes */ + regmap_reg_range(0x10286000, 0x10286fff), /* RG Batcher */ + regmap_reg_range(0x1028c000, 0x1028ffff), /* ETHER_SYS */ + regmap_reg_range(0x30000000, 0x37ffffff), /* I2C EEPROM */ + regmap_reg_range(0x38000000, 0x3fffffff), /* BOOT_ROM */ + regmap_reg_range(0xa0000000, 0xbfffffff), /* GPHY */ +}; + +static const struct regmap_access_table an8855_readable_table = { + .yes_ranges = an8855_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(an8855_readable_ranges), +}; + +static const struct regmap_config an8855_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0xbfffffff, + .reg_read = an8855_regmap_read, + .reg_write = an8855_regmap_write, + .reg_update_bits = an8855_regmap_update_bits, + .disable_locking = true, + .rd_table = &an8855_readable_table, +}; + +static int an8855_mfd_probe(struct mdio_device *mdiodev) +{ + struct an8855_mfd_priv *priv; + struct regmap *regmap; + + priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + priv->switch_addr = mdiodev->addr; + /* no DMA for mdiobus, mute warning for DMA mask not set */ + priv->dev->dma_mask = &priv->dev->coherent_dma_mask; + + regmap = devm_regmap_init(priv->dev, NULL, priv, + &an8855_regmap_config); + if (IS_ERR(regmap)) + dev_err_probe(priv->dev, PTR_ERR(priv->dev), + "regmap initialization failed\n"); + + dev_set_drvdata(&mdiodev->dev, priv); + + return devm_mfd_add_devices(priv->dev, PLATFORM_DEVID_AUTO, an8855_mfd_devs, + ARRAY_SIZE(an8855_mfd_devs), NULL, 0, + NULL); +} + +static const struct of_device_id an8855_mfd_of_match[] = { + { .compatible = "airoha,an8855-mfd" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, an8855_mfd_of_match); + +static struct mdio_driver an8855_mfd_driver = { + .probe = an8855_mfd_probe, + .mdiodrv.driver = { + .name = "an8855", + .of_match_table = an8855_mfd_of_match, + }, +}; +mdio_module_driver(an8855_mfd_driver); + +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Driver for Airoha AN8855 MFD"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/mtdsplit/Kconfig b/drivers/mtd/mtdsplit/Kconfig new file mode 100644 index 000000000000..396becf160cf --- /dev/null +++ b/drivers/mtd/mtdsplit/Kconfig @@ -0,0 +1,117 @@ +config MTD_SPLIT + def_bool n + help + Generic MTD split support. + +config MTD_SPLIT_SUPPORT + def_bool MTD = y + +comment "Rootfs partition parsers" + +config MTD_SPLIT_SQUASHFS_ROOT + bool "Squashfs based root partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + help + This provides a parsing function which allows to detect the + offset and size of the unused portion of a rootfs partition + containing a squashfs. + +comment "Firmware partition parsers" + +config MTD_SPLIT_BCM63XX_FW + bool "BCM63xx firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_BCM_WFI_FW + bool "Broadcom Whole Flash Image parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_CFE_BOOTFS + bool "Parser finding rootfs appended to the CFE bootfs" + depends on MTD_SPLIT_SUPPORT && (ARCH_BCM4908 || ARCH_BCMBCA) + select MTD_SPLIT + help + cferom on BCM4908 (and bcm63xx) uses JFFS2 bootfs partition + for storing kernel, cferam and some device specific files. + There isn't any straight way of storing rootfs so it gets + appended to the JFFS2 bootfs partition. Kernel needs to find + it and run init from it. This parser is responsible for + finding appended rootfs. + +config MTD_SPLIT_SEAMA_FW + bool "Seama firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_WRGG_FW + bool "WRGG firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_UIMAGE_FW + bool "uImage based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_FIT_FW + bool "FIT based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_LZMA_FW + bool "LZMA compressed kernel based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TPLINK_FW + bool "TP-Link firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TRX_FW + bool "TRX image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_BRNIMAGE_FW + bool "brnImage (brnboot image) firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_EVA_FW + bool "EVA image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_MINOR_FW + bool "Mikrotik NOR image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_JIMAGE_FW + bool "JBOOT Image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_ELF_FW + bool "ELF loader firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_H3C_VFS + bool "Parser finding rootfs appended to H3C VFS" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_SEIL_FW + bool "IIJ SEIL firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_MSTC_BOOT + bool "MSTC bootnum-based parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT diff --git a/drivers/mtd/mtdsplit/Makefile b/drivers/mtd/mtdsplit/Makefile new file mode 100644 index 000000000000..b85ce5d21f3b --- /dev/null +++ b/drivers/mtd/mtdsplit/Makefile @@ -0,0 +1,20 @@ +obj-$(CONFIG_MTD_SPLIT) += mtdsplit.o +obj-$(CONFIG_MTD_SPLIT_BCM63XX_FW) += mtdsplit_bcm63xx.o +obj-$(CONFIG_MTD_SPLIT_BCM_WFI_FW) += mtdsplit_bcm_wfi.o +obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o +obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o +obj-$(CONFIG_MTD_SPLIT_SEIL_FW) += mtdsplit_seil.o +obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o +obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o +obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o +obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o +obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o +obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o +obj-$(CONFIG_MTD_SPLIT_BRNIMAGE_FW) += mtdsplit_brnimage.o +obj-$(CONFIG_MTD_SPLIT_EVA_FW) += mtdsplit_eva.o +obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o +obj-$(CONFIG_MTD_SPLIT_MINOR_FW) += mtdsplit_minor.o +obj-$(CONFIG_MTD_SPLIT_JIMAGE_FW) += mtdsplit_jimage.o +obj-$(CONFIG_MTD_SPLIT_ELF_FW) += mtdsplit_elf.o +obj-$(CONFIG_MTD_SPLIT_H3C_VFS) += mtdsplit_h3c_vfs.o +obj-$(CONFIG_MTD_SPLIT_MSTC_BOOT) += mtdsplit_mstc_boot.o diff --git a/drivers/mtd/mtdsplit/mtdsplit.c b/drivers/mtd/mtdsplit/mtdsplit.c new file mode 100644 index 000000000000..b2e51dcfc66b --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) "mtdsplit: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define UBI_EC_MAGIC 0x55424923 /* UBI# */ + +struct squashfs_super_block { + __le32 s_magic; + __le32 pad0[9]; + __le64 bytes_used; +}; + +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + struct squashfs_super_block sb; + size_t retlen; + int err; + + err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); + if (err || (retlen != sizeof(sb))) { + pr_alert("error occured while reading from \"%s\"\n", + master->name); + return -EIO; + } + + if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { + pr_alert("no squashfs found in \"%s\"\n", master->name); + return -EINVAL; + } + + retlen = le64_to_cpu(sb.bytes_used); + if (retlen <= 0) { + pr_alert("squashfs is empty in \"%s\"\n", master->name); + return -ENODEV; + } + + if (offset + retlen > master->size) { + pr_alert("squashfs has invalid size in \"%s\"\n", + master->name); + return -EINVAL; + } + + *squashfs_len = retlen; + return 0; +} +EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); + +static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) +{ + return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; +} + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type) +{ + u32 magic; + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (ret) + return ret; + + if (retlen != sizeof(magic)) + return -EIO; + + if (le32_to_cpu(magic) == SQUASHFS_MAGIC) { + if (type) + *type = MTDSPLIT_PART_TYPE_SQUASHFS; + return 0; + } else if (magic == 0x19852003) { + if (type) + *type = MTDSPLIT_PART_TYPE_JFFS2; + return 0; + } else if (be32_to_cpu(magic) == UBI_EC_MAGIC) { + if (type) + *type = MTDSPLIT_PART_TYPE_UBI; + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type) +{ + size_t offset; + int err; + + for (offset = from; offset < limit; + offset = mtd_next_eb(mtd, offset)) { + err = mtd_check_rootfs_magic(mtd, offset, type); + if (err) + continue; + + *ret_offset = offset; + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); + diff --git a/drivers/mtd/mtdsplit/mtdsplit.h b/drivers/mtd/mtdsplit/mtdsplit.h new file mode 100644 index 000000000000..71d62a8956b2 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#ifndef _MTDSPLIT_H +#define _MTDSPLIT_H + +#define KERNEL_PART_NAME "kernel" +#define ROOTFS_PART_NAME "rootfs" +#define UBI_PART_NAME "ubi" + +#define ROOTFS_SPLIT_NAME "rootfs_data" + +enum mtdsplit_part_type { + MTDSPLIT_PART_TYPE_UNK = 0, + MTDSPLIT_PART_TYPE_SQUASHFS, + MTDSPLIT_PART_TYPE_JFFS2, + MTDSPLIT_PART_TYPE_UBI, +}; + +#ifdef CONFIG_MTD_SPLIT +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len); + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type); + +#else +static inline int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + return -ENODEV; +} + +static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type) +{ + return -EINVAL; +} + +static inline int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type) +{ + return -ENODEV; +} +#endif /* CONFIG_MTD_SPLIT */ + +#endif /* _MTDSPLIT_H */ diff --git a/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c b/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c new file mode 100644 index 000000000000..3a4b8a754fde --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c @@ -0,0 +1,186 @@ +/* + * Firmware MTD split for BCM63XX, based on bcm63xxpart.c + * + * Copyright (C) 2006-2008 Florian Fainelli + * Copyright (C) 2006-2008 Mike Albon + * Copyright (C) 2009-2010 Daniel Dickinson + * Copyright (C) 2011-2013 Jonas Gorski + * Copyright (C) 2015 Simon Arlott + * Copyright (C) 2017 Álvaro Fernández Rojas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +/* Ensure strings read from flash structs are null terminated */ +#define STR_NULL_TERMINATE(x) \ + do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) + +#define BCM63XX_NR_PARTS 2 + +static int bcm63xx_read_image_tag(struct mtd_info *master, loff_t offset, + struct bcm_tag *hdr) +{ + int ret; + size_t retlen; + u32 computed_crc; + + ret = mtd_read(master, offset, sizeof(*hdr), &retlen, (void *) hdr); + if (ret) + return ret; + + if (retlen != sizeof(*hdr)) + return -EIO; + + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)hdr, + offsetof(struct bcm_tag, header_crc)); + if (computed_crc == hdr->header_crc) { + STR_NULL_TERMINATE(hdr->board_id); + STR_NULL_TERMINATE(hdr->tag_version); + + pr_info("CFE image tag found at 0x%llx with version %s, " + "board type %s\n", offset, hdr->tag_version, + hdr->board_id); + + return 0; + } else { + pr_err("CFE image tag at 0x%llx CRC invalid " + "(expected %08x, actual %08x)\n", + offset, hdr->header_crc, computed_crc); + + return 1; + } +} + +static int bcm63xx_parse_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct bcm_tag *hdr) +{ + struct mtd_partition *parts; + unsigned int flash_image_start; + unsigned int kernel_address; + unsigned int kernel_length; + size_t kernel_offset = 0, kernel_size = 0; + size_t rootfs_offset = 0, rootfs_size = 0; + int kernel_part, rootfs_part; + + STR_NULL_TERMINATE(hdr->flash_image_start); + if (kstrtouint(hdr->flash_image_start, 10, &flash_image_start) || + flash_image_start < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid rootfs address: %*ph\n", + (int) sizeof(hdr->flash_image_start), + hdr->flash_image_start); + return -EINVAL; + } + + STR_NULL_TERMINATE(hdr->kernel_address); + if (kstrtouint(hdr->kernel_address, 10, &kernel_address) || + kernel_address < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid kernel address: %*ph\n", + (int) sizeof(hdr->kernel_address), hdr->kernel_address); + return -EINVAL; + } + + STR_NULL_TERMINATE(hdr->kernel_length); + if (kstrtouint(hdr->kernel_length, 10, &kernel_length) || + !kernel_length) { + pr_err("invalid kernel length: %*ph\n", + (int) sizeof(hdr->kernel_length), hdr->kernel_length); + return -EINVAL; + } + + kernel_offset = kernel_address - BCM963XX_EXTENDED_SIZE - + mtdpart_get_offset(master); + kernel_size = kernel_length; + + if (flash_image_start < kernel_address) { + /* rootfs first */ + rootfs_part = 0; + kernel_part = 1; + rootfs_offset = flash_image_start - BCM963XX_EXTENDED_SIZE - + mtdpart_get_offset(master); + rootfs_size = kernel_offset - rootfs_offset; + } else { + /* kernel first */ + kernel_part = 0; + rootfs_part = 1; + rootfs_offset = kernel_offset + kernel_size; + rootfs_size = master->size - rootfs_offset; + } + + if (mtd_check_rootfs_magic(master, rootfs_offset, NULL)) + pr_warn("rootfs magic not found\n"); + + parts = kzalloc(BCM63XX_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[kernel_part].name = KERNEL_PART_NAME; + parts[kernel_part].offset = kernel_offset; + parts[kernel_part].size = kernel_size; + + parts[rootfs_part].name = ROOTFS_PART_NAME; + parts[rootfs_part].offset = rootfs_offset; + parts[rootfs_part].size = rootfs_size; + + *pparts = parts; + return BCM63XX_NR_PARTS; +} + +static int mtdsplit_parse_bcm63xx(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct bcm_tag hdr; + loff_t offset; + + if (mtd_type_is_nand(master)) + return -EINVAL; + + /* find bcm63xx_cfe image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + if (!bcm63xx_read_image_tag(master, offset, (void *) &hdr)) + return bcm63xx_parse_partitions(master, pparts, + (void *) &hdr); + } + + return -EINVAL; +} + +static const struct of_device_id mtdsplit_fit_of_match_table[] = { + { .compatible = "brcm,bcm963xx-imagetag" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm63xx_parser = { + .owner = THIS_MODULE, + .name = "bcm63xx-fw", + .of_match_table = mtdsplit_fit_of_match_table, + .parse_fn = mtdsplit_parse_bcm63xx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_bcm63xx_init(void) +{ + register_mtd_parser(&mtdsplit_bcm63xx_parser); + + return 0; +} + +module_init(mtdsplit_bcm63xx_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c b/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c new file mode 100644 index 000000000000..1cafc91fded3 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c @@ -0,0 +1,535 @@ +/* + * MTD split for Broadcom Whole Flash Image + * + * Copyright (C) 2020 Álvaro Fernández Rojas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define char_to_num(c) ((c >= '0' && c <= '9') ? (c - '0') : (0)) + +#define BCM_WFI_PARTS 3 +#define BCM_WFI_SPLIT_PARTS 2 + +#define CFERAM_NAME "cferam" +#define CFERAM_NAME_LEN (sizeof(CFERAM_NAME) - 1) +#define CFERAM_NAME_MAX_LEN 32 +#define KERNEL_NAME "vmlinux.lz" +#define KERNEL_NAME_LEN (sizeof(KERNEL_NAME) - 1) +#define OPENWRT_NAME "1-openwrt" +#define OPENWRT_NAME_LEN (sizeof(OPENWRT_NAME) - 1) + +#define UBI_MAGIC 0x55424923 + +#define CFE_MAGIC_PFX "cferam." +#define CFE_MAGIC_PFX_LEN (sizeof(CFE_MAGIC_PFX) - 1) +#define CFE_MAGIC "cferam.000" +#define CFE_MAGIC_LEN (sizeof(CFE_MAGIC) - 1) +#define SERCOMM_MAGIC_PFX "eRcOmM." +#define SERCOMM_MAGIC_PFX_LEN (sizeof(SERCOMM_MAGIC_PFX) - 1) +#define SERCOMM_MAGIC "eRcOmM.000" +#define SERCOMM_MAGIC_LEN (sizeof(SERCOMM_MAGIC) - 1) + +#define PART_CFERAM "cferam" +#define PART_FIRMWARE "firmware" +#define PART_IMAGE_1 "img1" +#define PART_IMAGE_2 "img2" + +static u32 jffs2_dirent_crc(struct jffs2_raw_dirent *node) +{ + return crc32(0, node, sizeof(struct jffs2_raw_dirent) - 8); +} + +static bool jffs2_dirent_valid(struct jffs2_raw_dirent *node) +{ + return ((je16_to_cpu(node->magic) == JFFS2_MAGIC_BITMASK) && + (je16_to_cpu(node->nodetype) == JFFS2_NODETYPE_DIRENT) && + je32_to_cpu(node->ino) && + je32_to_cpu(node->node_crc) == jffs2_dirent_crc(node)); +} + +static int jffs2_find_file(struct mtd_info *mtd, uint8_t *buf, + const char *name, size_t name_len, + loff_t *offs, loff_t size, + char **out_name, size_t *out_name_len) +{ + const loff_t end = *offs + size; + struct jffs2_raw_dirent *node; + bool valid = false; + size_t retlen; + uint16_t magic; + int rc; + + for (; *offs < end; *offs += mtd->erasesize) { + unsigned int block_offs = 0; + + /* Skip CFE erased blocks */ + rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, + (void *) &magic); + if (rc || retlen != sizeof(magic)) { + continue; + } + + /* Skip blocks not starting with JFFS2 magic */ + if (magic != JFFS2_MAGIC_BITMASK) + continue; + + /* Read full block */ + rc = mtd_read(mtd, *offs, mtd->erasesize, &retlen, + (void *) buf); + if (rc) + return rc; + if (retlen != mtd->erasesize) + return -EINVAL; + + while (block_offs < mtd->erasesize) { + node = (struct jffs2_raw_dirent *) &buf[block_offs]; + + if (!jffs2_dirent_valid(node)) { + block_offs += 4; + continue; + } + + if (!memcmp(node->name, OPENWRT_NAME, + OPENWRT_NAME_LEN)) { + valid = true; + } else if (!memcmp(node->name, name, name_len)) { + if (!valid) + return -EINVAL; + + if (out_name) + *out_name = kstrndup(node->name, + node->nsize, + GFP_KERNEL); + + if (out_name_len) + *out_name_len = node->nsize; + + return 0; + } + + block_offs += je32_to_cpu(node->totlen); + block_offs = (block_offs + 0x3) & ~0x3; + } + } + + return -ENOENT; +} + +static int ubifs_find(struct mtd_info *mtd, loff_t *offs, loff_t size) +{ + const loff_t end = *offs + size; + uint32_t magic; + size_t retlen; + int rc; + + for (; *offs < end; *offs += mtd->erasesize) { + rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (rc || retlen != sizeof(magic)) + continue; + + if (be32_to_cpu(magic) == UBI_MAGIC) + return 0; + } + + return -ENOENT; +} + +static int parse_bcm_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + uint8_t *buf, loff_t off, loff_t size, bool cfe_part) +{ + struct device_node *mtd_node; + struct mtd_partition *parts; + loff_t cfe_off, kernel_off, rootfs_off; + unsigned int num_parts = BCM_WFI_PARTS, cur_part = 0; + const char *cferam_name = CFERAM_NAME; + size_t cferam_name_len; + int ret; + + mtd_node = mtd_get_of_node(master); + if (mtd_node) + of_property_read_string(mtd_node, "brcm,cferam", &cferam_name); + + cferam_name_len = strnlen(cferam_name, CFERAM_NAME_MAX_LEN); + if (cferam_name_len > 0) + cferam_name_len--; + + if (cfe_part) { + num_parts++; + cfe_off = off; + + ret = jffs2_find_file(master, buf, cferam_name, + cferam_name_len, &cfe_off, + size - (cfe_off - off), NULL, NULL); + if (ret) + return ret; + + kernel_off = cfe_off + master->erasesize; + } else { + kernel_off = off; + } + + ret = jffs2_find_file(master, buf, KERNEL_NAME, KERNEL_NAME_LEN, + &kernel_off, size - (kernel_off - off), + NULL, NULL); + if (ret) + return ret; + + rootfs_off = kernel_off + master->erasesize; + ret = ubifs_find(master, &rootfs_off, size - (rootfs_off - off)); + if (ret) + return ret; + + parts = kzalloc(num_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + if (cfe_part) { + parts[cur_part].name = PART_CFERAM; + parts[cur_part].mask_flags = MTD_WRITEABLE; + parts[cur_part].offset = cfe_off; + parts[cur_part].size = kernel_off - cfe_off; + cur_part++; + } + + parts[cur_part].name = PART_FIRMWARE; + parts[cur_part].offset = kernel_off; + parts[cur_part].size = size - (kernel_off - off); + cur_part++; + + parts[cur_part].name = KERNEL_PART_NAME; + parts[cur_part].offset = kernel_off; + parts[cur_part].size = rootfs_off - kernel_off; + cur_part++; + + parts[cur_part].name = UBI_PART_NAME; + parts[cur_part].offset = rootfs_off; + parts[cur_part].size = size - (rootfs_off - off); + cur_part++; + + *pparts = parts; + + return num_parts; +} + +static int mtdsplit_parse_bcm_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *mtd_node; + bool cfe_part = true; + uint8_t *buf; + int ret; + + mtd_node = mtd_get_of_node(master); + if (!mtd_node) + return -EINVAL; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (of_property_read_bool(mtd_node, "brcm,no-cferam")) + cfe_part = false; + + ret = parse_bcm_wfi(master, pparts, buf, 0, master->size, cfe_part); + + kfree(buf); + + return ret; +} + +static const struct of_device_id mtdsplit_bcm_wfi_of_match[] = { + { .compatible = "brcm,wfi" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm_wfi_parser = { + .owner = THIS_MODULE, + .name = "bcm-wfi-fw", + .of_match_table = mtdsplit_bcm_wfi_of_match, + .parse_fn = mtdsplit_parse_bcm_wfi, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int cferam_bootflag_value(const char *name, size_t name_len) +{ + int rc = -ENOENT; + + if (name && + (name_len >= CFE_MAGIC_LEN) && + !memcmp(name, CFE_MAGIC_PFX, CFE_MAGIC_PFX_LEN)) { + rc = char_to_num(name[CFE_MAGIC_PFX_LEN + 0]) * 100; + rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 1]) * 10; + rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 2]) * 1; + } + + return rc; +} + +static int mtdsplit_parse_bcm_wfi_split(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + loff_t cfe_off; + loff_t img1_off = 0; + loff_t img2_off = master->size / 2; + loff_t img1_size = (img2_off - img1_off); + loff_t img2_size = (master->size - img2_off); + loff_t active_off, inactive_off; + loff_t active_size, inactive_size; + const char *inactive_name; + uint8_t *buf; + char *cfe1_name = NULL, *cfe2_name = NULL; + size_t cfe1_size = 0, cfe2_size = 0; + int ret; + int bf1, bf2; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + cfe_off = img1_off; + ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, + &cfe_off, img1_size, &cfe1_name, &cfe1_size); + + cfe_off = img2_off; + ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, + &cfe_off, img2_size, &cfe2_name, &cfe2_size); + + bf1 = cferam_bootflag_value(cfe1_name, cfe1_size); + if (bf1 >= 0) + printk("cferam: bootflag1=%d\n", bf1); + + bf2 = cferam_bootflag_value(cfe2_name, cfe2_size); + if (bf2 >= 0) + printk("cferam: bootflag2=%d\n", bf2); + + kfree(cfe1_name); + kfree(cfe2_name); + + if (bf1 >= bf2) { + active_off = img1_off; + active_size = img1_size; + inactive_off = img2_off; + inactive_size = img2_size; + inactive_name = PART_IMAGE_2; + } else { + active_off = img2_off; + active_size = img2_size; + inactive_off = img1_off; + inactive_size = img1_size; + inactive_name = PART_IMAGE_1; + } + + ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, true); + + kfree(buf); + + if (ret > 0) { + parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + memcpy(parts, *pparts, ret * sizeof(*parts)); + kfree(*pparts); + + parts[ret].name = inactive_name; + parts[ret].offset = inactive_off; + parts[ret].size = inactive_size; + ret++; + + *pparts = parts; + } else { + parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); + + parts[0].name = PART_IMAGE_1; + parts[0].offset = img1_off; + parts[0].size = img1_size; + + parts[1].name = PART_IMAGE_2; + parts[1].offset = img2_off; + parts[1].size = img2_size; + + *pparts = parts; + } + + return ret; +} + +static const struct of_device_id mtdsplit_bcm_wfi_split_of_match[] = { + { .compatible = "brcm,wfi-split" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm_wfi_split_parser = { + .owner = THIS_MODULE, + .name = "bcm-wfi-split-fw", + .of_match_table = mtdsplit_bcm_wfi_split_of_match, + .parse_fn = mtdsplit_parse_bcm_wfi_split, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int sercomm_bootflag_value(struct mtd_info *mtd, uint8_t *buf) +{ + size_t retlen; + loff_t offs; + int rc; + + for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { + rc = mtd_read(mtd, offs, SERCOMM_MAGIC_LEN, &retlen, buf); + if (rc || retlen != SERCOMM_MAGIC_LEN) + continue; + + if (memcmp(buf, SERCOMM_MAGIC_PFX, SERCOMM_MAGIC_PFX_LEN)) + continue; + + rc = char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 0]) * 100; + rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 1]) * 10; + rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 2]) * 1; + + return rc; + } + + return -ENOENT; +} + +static int mtdsplit_parse_ser_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct mtd_info *mtd_bf1, *mtd_bf2; + loff_t img1_off = 0; + loff_t img2_off = master->size / 2; + loff_t img1_size = (img2_off - img1_off); + loff_t img2_size = (master->size - img2_off); + loff_t active_off, inactive_off; + loff_t active_size, inactive_size; + const char *inactive_name; + uint8_t *buf; + int bf1, bf2; + int ret; + + mtd_bf1 = get_mtd_device_nm("bootflag1"); + if (IS_ERR(mtd_bf1)) + return -ENOENT; + + mtd_bf2 = get_mtd_device_nm("bootflag2"); + if (IS_ERR(mtd_bf2)) + return -ENOENT; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + bf1 = sercomm_bootflag_value(mtd_bf1, buf); + if (bf1 >= 0) + printk("sercomm: bootflag1=%d\n", bf1); + + bf2 = sercomm_bootflag_value(mtd_bf2, buf); + if (bf2 >= 0) + printk("sercomm: bootflag2=%d\n", bf2); + + if (bf1 == bf2 && bf2 >= 0) { + struct erase_info bf_erase; + + bf2 = -ENOENT; + bf_erase.addr = 0; + bf_erase.len = mtd_bf2->size; + mtd_erase(mtd_bf2, &bf_erase); + } + + if (bf1 >= bf2) { + active_off = img1_off; + active_size = img1_size; + inactive_off = img2_off; + inactive_size = img2_size; + inactive_name = PART_IMAGE_2; + } else { + active_off = img2_off; + active_size = img2_size; + inactive_off = img1_off; + inactive_size = img1_size; + inactive_name = PART_IMAGE_1; + } + + ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, false); + + kfree(buf); + + if (ret > 0) { + parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + memcpy(parts, *pparts, ret * sizeof(*parts)); + kfree(*pparts); + + parts[ret].name = inactive_name; + parts[ret].offset = inactive_off; + parts[ret].size = inactive_size; + ret++; + + *pparts = parts; + } else { + parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); + + parts[0].name = PART_IMAGE_1; + parts[0].offset = img1_off; + parts[0].size = img1_size; + + parts[1].name = PART_IMAGE_2; + parts[1].offset = img2_off; + parts[1].size = img2_size; + + *pparts = parts; + } + + return ret; +} + +static const struct of_device_id mtdsplit_ser_wfi_of_match[] = { + { .compatible = "sercomm,wfi" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_ser_wfi_parser = { + .owner = THIS_MODULE, + .name = "ser-wfi-fw", + .of_match_table = mtdsplit_ser_wfi_of_match, + .parse_fn = mtdsplit_parse_ser_wfi, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_bcm_wfi_init(void) +{ + register_mtd_parser(&mtdsplit_bcm_wfi_parser); + register_mtd_parser(&mtdsplit_bcm_wfi_split_parser); + register_mtd_parser(&mtdsplit_ser_wfi_parser); + + return 0; +} + +module_init(mtdsplit_bcm_wfi_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_brnimage.c b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c new file mode 100644 index 000000000000..3f2d79601a14 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_brnimage.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 John Crispin + * Copyright (C) 2015 Martin Blumenstingl + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define BRNIMAGE_NR_PARTS 2 + +#define BRNIMAGE_ALIGN_BYTES 0x400 +#define BRNIMAGE_FOOTER_SIZE 12 + +#define BRNIMAGE_MIN_OVERHEAD (BRNIMAGE_FOOTER_SIZE) +#define BRNIMAGE_MAX_OVERHEAD (BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE) + +static int mtdsplit_parse_brnimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + uint32_t buf; + unsigned long rootfs_offset, rootfs_size, kernel_size; + size_t len; + int ret = 0; + + for (rootfs_offset = 0; rootfs_offset < master->size; + rootfs_offset += BRNIMAGE_ALIGN_BYTES) { + ret = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (!ret) + break; + } + + if (ret) + return ret; + + if (rootfs_offset >= master->size) + return -EINVAL; + + ret = mtd_read(master, rootfs_offset - BRNIMAGE_FOOTER_SIZE, 4, &len, + (void *)&buf); + if (ret) + return ret; + + if (len != 4) + return -EIO; + + kernel_size = le32_to_cpu(buf); + + if (kernel_size > (rootfs_offset - BRNIMAGE_MIN_OVERHEAD)) + return -EINVAL; + + if (kernel_size < (rootfs_offset - BRNIMAGE_MAX_OVERHEAD)) + return -EINVAL; + + /* + * The footer must be untouched as it contains the checksum of the + * original brnImage (kernel + squashfs)! + */ + rootfs_size = master->size - rootfs_offset - BRNIMAGE_FOOTER_SIZE; + + parts = kzalloc(BRNIMAGE_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return BRNIMAGE_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_brnimage_parser = { + .owner = THIS_MODULE, + .name = "brnimage-fw", + .parse_fn = mtdsplit_parse_brnimage, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_brnimage_init(void) +{ + register_mtd_parser(&mtdsplit_brnimage_parser); + + return 0; +} + +subsys_initcall(mtdsplit_brnimage_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c b/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c new file mode 100644 index 000000000000..a3474c9dc274 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Rafał Miłecki + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) + +#define NR_PARTS 2 + +static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct jffs2_raw_dirent node; + enum mtdsplit_part_type type; + struct mtd_partition *parts; + size_t rootfs_offset; + size_t retlen; + size_t offset; + int err; + + /* Don't parse backup partitions */ + if (strcmp(mtd->name, "firmware")) + return -EINVAL; + + /* Find the end of JFFS2 bootfs partition */ + offset = 0; + do { + err = mtd_read(mtd, offset, sizeof(node), &retlen, (void *)&node); + if (err || retlen != sizeof(node)) + break; + + if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) + break; + + offset += je32_to_cpu(node.totlen); + offset = (offset + 0x3) & ~0x3; + } while (offset < mtd->size); + + /* Find rootfs partition that follows the bootfs */ + err = mtd_find_rootfs_from(mtd, mtd->erasesize, mtd->size, &rootfs_offset, &type); + if (err) + return err; + + parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = "bootfs"; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = mtd->size - rootfs_offset; + + *pparts = parts; + + return NR_PARTS; +} + +static const struct of_device_id mtdsplit_cfe_bootfs_of_match_table[] = { + { .compatible = "brcm,bcm4908-firmware" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_cfe_bootfs_of_match_table); + +static struct mtd_part_parser mtdsplit_cfe_bootfs_parser = { + .owner = THIS_MODULE, + .name = "cfe-bootfs", + .of_match_table = mtdsplit_cfe_bootfs_of_match_table, + .parse_fn = mtdsplit_cfe_bootfs_parse, +}; + +module_mtd_part_parser(mtdsplit_cfe_bootfs_parser); diff --git a/drivers/mtd/mtdsplit/mtdsplit_elf.c b/drivers/mtd/mtdsplit/mtdsplit_elf.c new file mode 100644 index 000000000000..47818416f61c --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_elf.c @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MTD splitter for ELF loader firmware partitions + * + * Copyright (C) 2020 Sander Vanheule + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2. + * + * To parse the ELF kernel loader, a small ELF parser is used that can + * handle both ELF32 or ELF64 class loaders. The splitter assumes that the + * kernel is always located before the rootfs, whether it is embedded in the + * loader or not. + * + * The kernel image is preferably embedded inside the ELF loader, so the end + * of the loader equals the end of the kernel partition. This is due to the + * way mtd_find_rootfs_from searches for the the rootfs: + * - if the kernel image is embedded in the loader, the appended rootfs may + * follow the loader immediately, within the same erase block. + * - if the kernel image is not embedded in the loader, but placed at some + * offset behind the loader (OKLI-style loader), the rootfs must be + * aligned to an erase-block after the loader and kernel image. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define ELF_NR_PARTS 2 + +#define ELF_MAGIC 0x7f454c46 /* 0x7f E L F */ +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +struct elf_header_ident { + uint32_t magic; + uint8_t class; + uint8_t data; + uint8_t version; + uint8_t osabi; + uint8_t abiversion; + uint8_t pad[7]; +}; + +struct elf_header_32 { + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t phoff; + uint32_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +struct elf_header_64 { + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t phoff; + uint64_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +struct elf_header { + struct elf_header_ident ident; + union { + struct elf_header_32 elf32; + struct elf_header_64 elf64; + }; +}; + +struct elf_program_header_32 { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filesize; + uint32_t memsize; + uint32_t flags; +}; + +struct elf_program_header_64 { + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t vaddr; + uint64_t paddr; + uint64_t filesize; + uint64_t memsize; +}; + + +static int mtdsplit_elf_read_mtd(struct mtd_info *mtd, size_t offset, + uint8_t *dst, size_t len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, len, &retlen, dst); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int elf32_determine_size(struct mtd_info *mtd, struct elf_header *hdr, + size_t *size) +{ + struct elf_header_32 *hdr32 = &(hdr->elf32); + int err; + size_t section_end, ph_table_end, ph_entry; + struct elf_program_header_32 ph; + + *size = 0; + + if (hdr32->shoff > 0) { + *size = hdr32->shoff + hdr32->shentsize * hdr32->shnum; + return 0; + } + + ph_entry = hdr32->phoff; + ph_table_end = hdr32->phoff + hdr32->phentsize * hdr32->phnum; + + while (ph_entry < ph_table_end) { + err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), + sizeof(ph)); + if (err) + return err; + + section_end = ph.offset + ph.filesize; + if (section_end > *size) + *size = section_end; + + ph_entry += hdr32->phentsize; + } + + return 0; +} + +static int elf64_determine_size(struct mtd_info *mtd, struct elf_header *hdr, + size_t *size) +{ + struct elf_header_64 *hdr64 = &(hdr->elf64); + int err; + size_t section_end, ph_table_end, ph_entry; + struct elf_program_header_64 ph; + + *size = 0; + + if (hdr64->shoff > 0) { + *size = hdr64->shoff + hdr64->shentsize * hdr64->shnum; + return 0; + } + + ph_entry = hdr64->phoff; + ph_table_end = hdr64->phoff + hdr64->phentsize * hdr64->phnum; + + while (ph_entry < ph_table_end) { + err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), + sizeof(ph)); + if (err) + return err; + + section_end = ph.offset + ph.filesize; + if (section_end > *size) + *size = section_end; + + ph_entry += hdr64->phentsize; + } + + return 0; +} + +static int mtdsplit_parse_elf(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct elf_header hdr; + size_t loader_size, rootfs_offset; + enum mtdsplit_part_type type; + struct mtd_partition *parts; + int err; + + err = mtdsplit_elf_read_mtd(mtd, 0, (uint8_t *)&hdr, sizeof(hdr)); + if (err) + return err; + + if (be32_to_cpu(hdr.ident.magic) != ELF_MAGIC) { + pr_debug("invalid ELF magic %08x\n", + be32_to_cpu(hdr.ident.magic)); + return -EINVAL; + } + + switch (hdr.ident.class) { + case ELF_CLASS_32: + err = elf32_determine_size(mtd, &hdr, &loader_size); + break; + case ELF_CLASS_64: + err = elf64_determine_size(mtd, &hdr, &loader_size); + break; + default: + pr_debug("invalid ELF class %i\n", hdr.ident.class); + err = -EINVAL; + } + + if (err) + return err; + + err = mtd_find_rootfs_from(mtd, loader_size, mtd->size, + &rootfs_offset, &type); + if (err) + return err; + + if (rootfs_offset == mtd->size) { + pr_debug("no rootfs found in \"%s\"\n", mtd->name); + return -ENODEV; + } + + parts = kzalloc(ELF_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = mtd->size - rootfs_offset; + + *pparts = parts; + return ELF_NR_PARTS; +} + +static const struct of_device_id mtdsplit_elf_of_match_table[] = { + { .compatible = "openwrt,elf" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_elf_of_match_table); + +static struct mtd_part_parser mtdsplit_elf_parser = { + .owner = THIS_MODULE, + .name = "elf-loader-fw", + .of_match_table = mtdsplit_elf_of_match_table, + .parse_fn = mtdsplit_parse_elf, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_elf_init(void) +{ + register_mtd_parser(&mtdsplit_elf_parser); + + return 0; +} + +subsys_initcall(mtdsplit_elf_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_eva.c b/drivers/mtd/mtdsplit/mtdsplit_eva.c new file mode 100644 index 000000000000..55004a6d36d7 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_eva.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 John Crispin + * Copyright (C) 2015 Martin Blumenstingl + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define EVA_NR_PARTS 2 +#define EVA_MAGIC 0xfeed1281 +#define EVA_FOOTER_SIZE 0x18 +#define EVA_DUMMY_SQUASHFS_SIZE 0x100 + +struct eva_image_header { + uint32_t magic; + uint32_t size; +}; + +static int mtdsplit_parse_eva(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct eva_image_header hdr; + size_t retlen; + unsigned long kernel_size, rootfs_offset; + int err; + + err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != sizeof(hdr)) + return -EIO; + + if (le32_to_cpu(hdr.magic) != EVA_MAGIC) + return -EINVAL; + + kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE; + + /* rootfs starts at the next 0x10000 boundary: */ + rootfs_offset = round_up(kernel_size, 0x10000); + + /* skip the dummy EVA squashfs partition (with wrong endianness): */ + rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE; + + if (rootfs_offset >= master->size) + return -EINVAL; + + err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return EVA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_eva_of_match_table[] = { + { .compatible = "avm,eva-firmware" }, + {}, +}; + +static struct mtd_part_parser mtdsplit_eva_parser = { + .owner = THIS_MODULE, + .name = "eva-fw", + .of_match_table = mtdsplit_eva_of_match_table, + .parse_fn = mtdsplit_parse_eva, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_eva_init(void) +{ + register_mtd_parser(&mtdsplit_eva_parser); + + return 0; +} + +subsys_initcall(mtdsplit_eva_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_fit.c b/drivers/mtd/mtdsplit/mtdsplit_fit.c new file mode 100644 index 000000000000..a271a676e10e --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2015 The Linux Foundation + * Copyright (C) 2014 Gabor Juhos + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +// string macros from git://git.denx.de/u-boot.git/include/image.h + +#define FIT_IMAGES_PATH "/images" +#define FIT_DATA_PROP "data" +#define FIT_DATA_POSITION_PROP "data-position" +#define FIT_DATA_OFFSET_PROP "data-offset" +#define FIT_DATA_SIZE_PROP "data-size" + +// functions from git://git.denx.de/u-boot.git/common/image-fit.c + +/** + * fit_image_get_data - get data property and its size for a given component image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @data: double pointer to void, will hold data property's data address + * @size: pointer to size_t, will hold data property's data size + * + * fit_image_get_data() finds data property in a given component image node. + * If the property is found its data start address and size are returned to + * the caller. + * + * returns: + * 0, on success + * -1, on failure + */ +static int fit_image_get_data(const void *fit, int noffset, + const void **data, size_t *size) +{ + int len; + + *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); + if (*data == NULL) { + *size = 0; + return -1; + } + + *size = len; + return 0; +} + + +/** + * Get 'data-offset' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_offset: holds the data-offset property + * + * returns: + * 0, on success + * -ENOENT if the property could not be found + */ +static int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset) +{ + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_OFFSET_PROP, NULL); + if (!val) + return -ENOENT; + + *data_offset = fdt32_to_cpu(*val); + + return 0; +} + +/** + * Get 'data-position' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_position: holds the data-position property + * + * returns: + * 0, on success + * -ENOENT if the property could not be found + */ +static int fit_image_get_data_position(const void *fit, int noffset, + int *data_position) +{ + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_POSITION_PROP, NULL); + if (!val) + return -ENOENT; + + *data_position = fdt32_to_cpu(*val); + + return 0; +} + +/** + * Get 'data-size' property from a given image node. + * + * @fit: pointer to the FIT image header + * @noffset: component image node offset + * @data_size: holds the data-size property + * + * returns: + * 0, on success + * -ENOENT if the property could not be found + */ +static int fit_image_get_data_size(const void *fit, int noffset, int *data_size) +{ + const fdt32_t *val; + + val = fdt_getprop(fit, noffset, FIT_DATA_SIZE_PROP, NULL); + if (!val) + return -ENOENT; + + *data_size = fdt32_to_cpu(*val); + + return 0; +} + +/** + * fit_image_get_data_and_size - get data and its size including + * both embedded and external data + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @data: double pointer to void, will hold data property's data address + * @size: pointer to size_t, will hold data property's data size + * + * fit_image_get_data_and_size() finds data and its size including + * both embedded and external data. If the property is found + * its data start address and size are returned to the caller. + * + * returns: + * 0, on success + * otherwise, on failure + */ +static int fit_image_get_data_and_size(const void *fit, int noffset, + const void **data, size_t *size) +{ + bool external_data = false; + int offset; + int len; + int ret; + + if (!fit_image_get_data_position(fit, noffset, &offset)) { + external_data = true; + } else if (!fit_image_get_data_offset(fit, noffset, &offset)) { + external_data = true; + /* + * For FIT with external data, figure out where + * the external images start. This is the base + * for the data-offset properties in each image. + */ + offset += ((fdt_totalsize(fit) + 3) & ~3); + } + + if (external_data) { + ret = fit_image_get_data_size(fit, noffset, &len); + if (!ret) { + *data = fit + offset; + *size = len; + } + } else { + ret = fit_image_get_data(fit, noffset, data, size); + } + + return ret; +} + +static int +mtdsplit_fit_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *np = mtd_get_of_node(mtd); + const char *cmdline_match = NULL; + struct fdt_header hdr; + size_t hdr_len, retlen; + size_t offset; + u32 offset_start = 0; + size_t fit_offset, fit_size; + size_t rootfs_offset, rootfs_size; + size_t data_size, img_total, max_size = 0; + struct mtd_partition *parts; + int ret, ndepth, noffset, images_noffset; + const void *img_data; + void *fit; + + of_property_read_string(np, "openwrt,cmdline-match", &cmdline_match); + if (cmdline_match && !strstr(saved_command_line, cmdline_match)) + return -ENODEV; + + of_property_read_u32(np, "openwrt,fit-offset", &offset_start); + + hdr_len = sizeof(struct fdt_header); + + /* Parse the MTD device & search for the FIT image location */ + for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) { + ret = mtd_read(mtd, offset + offset_start, hdr_len, &retlen, (void*) &hdr); + if (ret) { + pr_err("read error in \"%s\" at offset 0x%llx\n", + mtd->name, (unsigned long long) offset); + return ret; + } + + if (retlen != hdr_len) { + pr_err("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + /* Check the magic - see if this is a FIT image */ + if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) { + pr_debug("no valid FIT image found in \"%s\" at offset %llx\n", + mtd->name, (unsigned long long) offset); + continue; + } + + /* We found a FIT image. Let's keep going */ + break; + } + + fit_offset = offset; + fit_size = be32_to_cpu(hdr.totalsize); + + if (fit_size == 0) { + pr_err("FIT image in \"%s\" at offset %llx has null size\n", + mtd->name, (unsigned long long) fit_offset); + return -ENODEV; + } + + /* + * Classic uImage.FIT has all data embedded into the FDT + * data structure. Hence the total size of the image equals + * the total size of the FDT structure. + * Modern uImage.FIT may have only references to data in FDT, + * hence we need to parse FDT structure to find the end of the + * last external data refernced. + */ + if (fit_size > 0x1000) { + enum mtdsplit_part_type type; + + /* Search for the rootfs partition after the FIT image */ + ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size + offset_start, mtd->size, + &rootfs_offset, &type); + if (ret) { + pr_info("no rootfs found after FIT image in \"%s\"\n", + mtd->name); + return ret; + } + + rootfs_size = mtd->size - rootfs_offset; + + parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = fit_offset; + parts[0].size = mtd_roundup_to_eb(fit_size + offset_start, mtd); + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + + return 2; + } else { + /* Search for rootfs_data after FIT external data */ + fit = kzalloc(fit_size, GFP_KERNEL); + ret = mtd_read(mtd, offset, fit_size + offset_start, &retlen, fit); + if (ret) { + pr_err("read error in \"%s\" at offset 0x%llx\n", + mtd->name, (unsigned long long) offset); + return ret; + } + + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images_noffset < 0) { + pr_err("Can't find images parent node '%s' (%s)\n", + FIT_IMAGES_PATH, fdt_strerror(images_noffset)); + return -ENODEV; + } + + for (ndepth = 0, + noffset = fdt_next_node(fit, images_noffset, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(fit, noffset, &ndepth)) { + if (ndepth == 1) { + ret = fit_image_get_data_and_size(fit, noffset, &img_data, &data_size); + if (ret) + return 0; + + img_total = data_size + (img_data - fit); + + max_size = (max_size > img_total) ? max_size : img_total; + } + } + + parts = kzalloc(sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = ROOTFS_SPLIT_NAME; + parts[0].offset = fit_offset + mtd_roundup_to_eb(max_size, mtd); + parts[0].size = mtd->size - parts[0].offset; + + *pparts = parts; + + kfree(fit); + + return 1; + } +} + +static const struct of_device_id mtdsplit_fit_of_match_table[] = { + { .compatible = "denx,fit" }, + {}, +}; + +static struct mtd_part_parser uimage_parser = { + .owner = THIS_MODULE, + .name = "fit-fw", + .of_match_table = mtdsplit_fit_of_match_table, + .parse_fn = mtdsplit_fit_parse, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_fit_init(void) +{ + register_mtd_parser(&uimage_parser); + + return 0; +} + +module_init(mtdsplit_fit_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c b/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c new file mode 100644 index 000000000000..25993e762bf9 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_h3c_vfs.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Some devices made by H3C use a "VFS" filesystem to store firmware images. + * This parses the start of the filesystem to read the length of the first + * file (the kernel image). It then searches for the rootfs after the end of + * the file data. This driver assumes that the filesystem was generated by + * mkh3cvfs, and only works if the filesystem matches the expected layout, + * which includes the file name of the kernel image. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define VFS_ERASEBLOCK_SIZE 0x10000 +#define VFS_BLOCK_SIZE 0x400 +#define VFS_BLOCKS_PER_ERASEBLOCK (VFS_ERASEBLOCK_SIZE / VFS_BLOCK_SIZE) + +#define FORMAT_FLAG_OFFSET 0x0 + +#define FORMAT_FLAG (VFS_ERASEBLOCK_SIZE << 12 | VFS_BLOCK_SIZE) + +#define FILE_ENTRY_OFFSET 0x800 + +#define FILE_ENTRY_FLAGS 0x3f +#define FILE_ENTRY_PARENT_BLOCK 0 +#define FILE_ENTRY_PARENT_INDEX 0 +#define FILE_ENTRY_DATA_BLOCK 2 +#define FILE_ENTRY_NAME "openwrt-kernel.bin" + +#define NR_PARTS 2 + +struct file_entry { + uint8_t flags; + + uint8_t res0[5]; + + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + + uint8_t res1[3]; + + uint32_t length; + + uint32_t parent_block; + uint16_t parent_index; + + uint8_t res2[2]; + + uint32_t data_block; + + char name[96]; +} __attribute__ ((packed)); + +static inline size_t block_offset(int block) +{ + return VFS_ERASEBLOCK_SIZE * (block / (VFS_BLOCKS_PER_ERASEBLOCK-1)) + + VFS_BLOCK_SIZE * (1 + (block % (VFS_BLOCKS_PER_ERASEBLOCK-1))); +} + +static inline int block_count(size_t size) +{ + return (size + VFS_BLOCK_SIZE - 1) / VFS_BLOCK_SIZE; +} + +static int mtdsplit_h3c_vfs_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + uint32_t format_flag; + struct file_entry file_entry; + size_t retlen; + int err; + size_t kernel_size; + size_t expected_offset; + size_t rootfs_offset; + + if (mtd->erasesize != VFS_ERASEBLOCK_SIZE) + return -EINVAL; + + /* Check format flag */ + err = mtd_read(mtd, FORMAT_FLAG_OFFSET, sizeof(format_flag), &retlen, + (void *) &format_flag); + if (err) + return err; + + if (retlen != sizeof(format_flag)) + return -EIO; + + if (format_flag != FORMAT_FLAG) { + pr_info("mtdsplit_h3c_vfs: unexpected format flag %08x\n", + format_flag); + return 0; + } + + /* Check file entry */ + err = mtd_read(mtd, FILE_ENTRY_OFFSET, sizeof(file_entry), &retlen, + (void *) &file_entry); + if (err) + return err; + + if (retlen != sizeof(file_entry)) + return -EIO; + + if (file_entry.flags != FILE_ENTRY_FLAGS || + file_entry.parent_block != FILE_ENTRY_PARENT_BLOCK || + file_entry.parent_index != FILE_ENTRY_PARENT_INDEX || + file_entry.data_block != FILE_ENTRY_DATA_BLOCK || + strncmp(file_entry.name, FILE_ENTRY_NAME, sizeof(file_entry.name)) != 0) { + pr_info("mtdsplit_h3c_vfs: unexpected file entry - OpenWrt probably not installed\n"); + return 0; + } + + /* Find rootfs offset */ + kernel_size = block_offset(file_entry.data_block + + block_count(file_entry.length) - 1) + + VFS_BLOCK_SIZE; + + expected_offset = mtd_roundup_to_eb(kernel_size, mtd); + + err = mtd_find_rootfs_from(mtd, expected_offset, mtd->size, + &rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = mtd->size - rootfs_offset; + + *pparts = parts; + return NR_PARTS; +} + +static const struct of_device_id mtdsplit_h3c_vfs_of_match_table[] = { + { .compatible = "h3c,vfs-firmware" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_h3c_vfs_of_match_table); + +static struct mtd_part_parser mtdsplit_h3c_vfs_parser = { + .owner = THIS_MODULE, + .name = "h3c-vfs", + .of_match_table = mtdsplit_h3c_vfs_of_match_table, + .parse_fn = mtdsplit_h3c_vfs_parse, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +module_mtd_part_parser(mtdsplit_h3c_vfs_parser); diff --git a/drivers/mtd/mtdsplit/mtdsplit_jimage.c b/drivers/mtd/mtdsplit/mtdsplit_jimage.c new file mode 100644 index 000000000000..1244bbdb06e5 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_jimage.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2018 Paweł Dembicki + * + * Based on: mtdsplit_uimage.c + * Copyright (C) 2013 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE ) + +#define STAG_SIZE 16 +#define STAG_ID 0x04 +#define STAG_MAGIC 0x2B24 + +#define SCH2_SIZE 40 +#define SCH2_MAGIC 0x2124 +#define SCH2_VER 0x02 + +/* + * Jboot image header, + * all data in little endian. + */ + +struct jimage_header //stag + sch2 jboot joined headers +{ + uint8_t stag_cmark; // in factory 0xFF , in sysupgrade must be the same as stag_id + uint8_t stag_id; // 0x04 + uint16_t stag_magic; //magic 0x2B24 + uint32_t stag_time_stamp; // timestamp calculated in jboot way + uint32_t stag_image_length; // lentgh of kernel + sch2 header + uint16_t stag_image_checksum; // negated jboot_checksum of sch2 + kernel + uint16_t stag_tag_checksum; // negated jboot_checksum of stag header data + uint16_t sch2_magic; // magic 0x2124 + uint8_t sch2_cp_type; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma + uint8_t sch2_version; // 0x02 for sch2 + uint32_t sch2_ram_addr; // ram entry address + uint32_t sch2_image_len; // kernel image length + uint32_t sch2_image_crc32; // kernel image crc + uint32_t sch2_start_addr; // ram start address + uint32_t sch2_rootfs_addr; // rootfs flash address + uint32_t sch2_rootfs_len; // rootfls length + uint32_t sch2_rootfs_crc32; // rootfs crc32 + uint32_t sch2_header_crc32; // sch2 header crc32, durring calculation this area is replaced by zero + uint16_t sch2_header_length; // sch2 header length: 0x28 + uint16_t sch2_cmd_line_length; // cmd line length, known zeros +}; + +static int +read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, + size_t header_len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, header_len, &retlen, buf); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +/** + * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts + * + * @find_header: function to call for a block of data that will return offset + * of a valid jImage header if found + */ +static int __mtdsplit_parse_jimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data, + ssize_t (*find_header)(u_char *buf, size_t len)) +{ + struct mtd_partition *parts; + u_char *buf; + int nr_parts; + size_t offset; + size_t jimage_offset; + size_t jimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int jimage_part, rf_part; + int ret; + enum mtdsplit_part_type type; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + buf = vmalloc(MAX_HEADER_LEN); + if (!buf) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find jImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + struct jimage_header *header; + + jimage_size = 0; + + ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN); + if (ret) + continue; + + ret = find_header(buf, MAX_HEADER_LEN); + if (ret < 0) { + pr_debug("no valid jImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + header = (struct jimage_header *)(buf + ret); + + jimage_size = sizeof(*header) + header->sch2_image_len + ret; + if ((offset + jimage_size) > master->size) { + pr_debug("jImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (jimage_size == 0) { + pr_debug("no jImage found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + jimage_offset = offset; + + if (jimage_offset == 0) { + jimage_part = 0; + rf_part = 1; + + /* find the roots after the jImage */ + ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size, + master->size, &rootfs_offset, &type); + if (ret) { + pr_debug("no rootfs after jImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_size = master->size - rootfs_offset; + jimage_size = rootfs_offset - jimage_offset; + } else { + rf_part = 0; + jimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0, &type); + if (ret) { + pr_debug("no rootfs before jImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_offset = 0; + rootfs_size = jimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + parts[jimage_part].name = KERNEL_PART_NAME; + parts[jimage_part].offset = jimage_offset; + parts[jimage_part].size = jimage_size; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[rf_part].name = UBI_PART_NAME; + else + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(buf); + + *pparts = parts; + return nr_parts; + +err_free_buf: + vfree(buf); + +err_free_parts: + kfree(parts); + return ret; +} + +static ssize_t jimage_verify_default(u_char *buf, size_t len) +{ + struct jimage_header *header = (struct jimage_header *)buf; + + /* default sanity checks */ + if (header->stag_magic != STAG_MAGIC) { + pr_debug("invalid jImage stag header magic: %04x\n", + header->stag_magic); + return -EINVAL; + } + if (header->sch2_magic != SCH2_MAGIC) { + pr_debug("invalid jImage sch2 header magic: %04x\n", + header->stag_magic); + return -EINVAL; + } + if (header->stag_cmark != header->stag_id) { + pr_debug("invalid jImage stag header cmark: %02x\n", + header->stag_magic); + return -EINVAL; + } + if (header->stag_id != STAG_ID) { + pr_debug("invalid jImage stag header id: %02x\n", + header->stag_magic); + return -EINVAL; + } + if (header->sch2_version != SCH2_VER) { + pr_debug("invalid jImage sch2 header version: %02x\n", + header->stag_magic); + return -EINVAL; + } + + return 0; +} + +static int +mtdsplit_jimage_parse_generic(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_jimage(master, pparts, data, + jimage_verify_default); +} + +static const struct of_device_id mtdsplit_jimage_of_match_table[] = { + { .compatible = "amit,jimage" }, + {}, +}; + +static struct mtd_part_parser jimage_generic_parser = { + .owner = THIS_MODULE, + .name = "jimage-fw", + .of_match_table = mtdsplit_jimage_of_match_table, + .parse_fn = mtdsplit_jimage_parse_generic, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_jimage_init(void) +{ + register_mtd_parser(&jimage_generic_parser); + + return 0; +} + +module_init(mtdsplit_jimage_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/drivers/mtd/mtdsplit/mtdsplit_lzma.c new file mode 100644 index 000000000000..6dcffd04203d --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_lzma.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,12,0) +#include +#else +#include +#endif + +#include "mtdsplit.h" + +#define LZMA_NR_PARTS 2 +#define LZMA_PROPERTIES_SIZE 5 + +struct lzma_header { + u8 props[LZMA_PROPERTIES_SIZE]; + u8 size_low[4]; + u8 size_high[4]; +}; + +static int mtdsplit_parse_lzma(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct lzma_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + u32 t; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* verify LZMA properties */ + if (hdr.props[0] >= (9 * 5 * 5)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.props[1]); + if (!is_power_of_2(t)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.size_high); + if (t) + return -EINVAL; + + err = mtd_find_rootfs_from(master, master->erasesize, master->size, + &rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return LZMA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_lzma_of_match_table[] = { + { .compatible = "lzma" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_lzma_of_match_table); + +static struct mtd_part_parser mtdsplit_lzma_parser = { + .owner = THIS_MODULE, + .name = "lzma-fw", + .of_match_table = mtdsplit_lzma_of_match_table, + .parse_fn = mtdsplit_parse_lzma, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_lzma_init(void) +{ + register_mtd_parser(&mtdsplit_lzma_parser); + + return 0; +} + +subsys_initcall(mtdsplit_lzma_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_minor.c b/drivers/mtd/mtdsplit/mtdsplit_minor.c new file mode 100644 index 000000000000..053cba6272da --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_minor.c @@ -0,0 +1,142 @@ +/* + * MTD splitter for MikroTik NOR devices + * + * Copyright (C) 2017 Thibaut VARENE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * The rootfs is expected at erase-block boundary due to the use of + * mtd_find_rootfs_from(). We use a trimmed down version of the yaffs header + * for two main reasons: + * - the original header uses weakly defined types (int, enum...) which can + * vary in length depending on build host (and the struct is not packed), + * and the name field can have a different total length depending on + * whether or not the yaffs code was _built_ with unicode support. + * - the only field that could be of real use here (file_size_low) contains + * invalid data in the header generated by kernel2minor, so we cannot use + * it to infer the exact position of the rootfs and do away with + * mtd_find_rootfs_from() (and thus have non-EB-aligned rootfs). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define YAFFS_OBJECT_TYPE_FILE 0x1 +#define YAFFS_OBJECTID_ROOT 0x1 +#define YAFFS_SUM_UNUSED 0xFFFF +#define YAFFS_MAX_NAME_LENGTH 127 +#define YAFFS_NAME_KERNEL "kernel" +#define YAFFS_NAME_BOOTIMAGE "bootimage" + +#define MINOR_NR_PARTS 2 + +/* + * This structure is based on yaffs_obj_hdr from yaffs_guts.h + * The weak types match upstream. The fields have cpu-endianness + */ +struct minor_header { + int yaffs_type; + int yaffs_obj_id; + u16 yaffs_sum_unused; + char yaffs_name[YAFFS_MAX_NAME_LENGTH]; +}; + +static int mtdsplit_parse_minor(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct minor_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) { + pr_err("MiNOR mtd_read error: %d\n", err); + return err; + } + + if (retlen != hdr_len) { + pr_err("MiNOR mtd_read too short\n"); + return -EIO; + } + + /* match header */ + if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE) { + pr_info("MiNOR YAFFS first type not matched\n"); + return 0; + } + + if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT) { + pr_info("MiNOR YAFFS first objectid not matched\n"); + return 0; + } + + if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED) { + pr_info("MiNOR YAFFS first sum not matched\n"); + return 0; + } + + if ((memcmp(hdr.yaffs_name, YAFFS_NAME_KERNEL, sizeof(YAFFS_NAME_KERNEL))) && + (memcmp(hdr.yaffs_name, YAFFS_NAME_BOOTIMAGE, sizeof(YAFFS_NAME_BOOTIMAGE)))) { + pr_info("MiNOR YAFFS first name not matched\n"); + return 0; + } + + err = mtd_find_rootfs_from(master, master->erasesize, master->size, + &rootfs_offset, NULL); + if (err) { + pr_info("MiNOR mtd_find_rootfs_from error: %d\n", err); + return 0; + } + + parts = kzalloc(MINOR_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return MINOR_NR_PARTS; +} + +static const struct of_device_id mtdsplit_minor_of_match_table[] = { + { .compatible = "mikrotik,minor" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_minor_of_match_table); + +static struct mtd_part_parser mtdsplit_minor_parser = { + .owner = THIS_MODULE, + .name = "minor-fw", + .of_match_table = mtdsplit_minor_of_match_table, + .parse_fn = mtdsplit_parse_minor, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_minor_init(void) +{ + register_mtd_parser(&mtdsplit_minor_parser); + + return 0; +} + +subsys_initcall(mtdsplit_minor_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c b/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c new file mode 100644 index 000000000000..6d7980792aed --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_mstc_boot.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * a mtdsplit parser using "bootnum" value in the "persist" partition + * for the devices manufactured by MSTC (MitraStar Technology Corp.) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define PERSIST_BOOTNUM_OFFSET 0x4 +#define NR_PARTS_MAX 2 + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ + struct uimage_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +}; + +/* check whether the current mtd device is active or not */ +static int +mstcboot_is_active(struct mtd_info *mtd, u32 *bootnum_dt) +{ + struct device_node *np = mtd_get_of_node(mtd); + struct device_node *persist_np; + size_t retlen; + u32 persist_offset; + u_char bootnum; + int ret; + + ret = of_property_read_u32(np, "mstc,bootnum", bootnum_dt); + if (ret) + return ret; + + persist_np = of_parse_phandle(np, "mstc,persist", 0); + if (!persist_np) + return -ENODATA; + /* is "persist" under the same node? */ + if (persist_np->parent != np->parent) { + of_node_put(persist_np); + return -EINVAL; + } + + ret = of_property_read_u32(persist_np, "reg", &persist_offset); + of_node_put(persist_np); + if (ret) + return ret; + ret = mtd_read(mtd->parent, persist_offset + PERSIST_BOOTNUM_OFFSET, + 1, &retlen, &bootnum); + if (ret) + return ret; + if (retlen != 1) + return -EIO; + + return (bootnum == *bootnum_dt) ? 1 : 0; +} + +/* + * mainly for NOR devices that uses raw kernel and squashfs + * + * example: + * + * partition@5a0000 { + * compatible = "mstc,boot"; + * label = "firmware1"; + * reg = <0x5a0000 0x3200000>; + * mstc,bootnum = <1>; + * mstc,persist = <&mtd_persist>; + * }; + */ +static int +mstcboot_parse_image_parts(struct mtd_info *mtd, + const struct mtd_partition **pparts) +{ + struct mtd_partition *parts; + size_t retlen, kern_len = 0; + size_t rootfs_offset; + enum mtdsplit_part_type type; + u_char buf[0x40]; + int ret, nr_parts = 1, index = 0; + + ret = mtd_read(mtd, 0, sizeof(struct uimage_header), &retlen, buf); + if (ret) + return ret; + if (retlen != sizeof(struct uimage_header)) + return -EIO; + + if (be32_to_cpu(*(u32 *)buf) == OF_DT_HEADER) { + /* Flattened Image Tree (FIT) */ + struct fdt_header *fdthdr = (void *)buf; + kern_len = be32_to_cpu(fdthdr->totalsize); + } else if (be32_to_cpu(*(u32 *)buf) == IH_MAGIC) { + /* Legacy uImage */ + struct uimage_header *uimghdr = (void *)buf; + kern_len = sizeof(*uimghdr) + be32_to_cpu(uimghdr->ih_size); + } + + ret = mtd_find_rootfs_from(mtd, kern_len, mtd->size, &rootfs_offset, &type); + if (ret) { + pr_debug("no rootfs in \"%s\"\n", mtd->name); + return ret; + } + + if (kern_len > 0) + nr_parts++; + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + if (kern_len) { + parts[index].name = KERNEL_PART_NAME; + parts[index].offset = 0; + parts[index++].size = rootfs_offset; + } + + parts[index].name = (type == MTDSPLIT_PART_TYPE_UBI) + ? UBI_PART_NAME : ROOTFS_PART_NAME; + parts[index].offset = rootfs_offset; + parts[index].size = mtd->size - rootfs_offset; + + *pparts = parts; + return nr_parts; +} + +/* + * mainly for NAND devices that uses raw-kernel and UBI and needs + * splitted kernel/ubi partitions when sysupgrade + * + * example: + * + * partition@3c0000 { + * compatible = "mstc,boot"; + * reg = <0x3c0000 0x3240000>; + * label = "firmware1"; + * mstc,bootnum = <1>; + * mstc,persist = <&mtd_persist>; + * #address-cells = <1>; + * #size-cells = <1>; + * + * partition@0 { + * reg = <0x0 0x800000>; + * label-base = "kernel"; + * }; + * + * partition@800000 { + * reg = <0x800000 0x2a40000>; + * label-base = "ubi"; + * }; +}; + */ +static int +mstcboot_parse_fixed_parts(struct mtd_info *mtd, + const struct mtd_partition **pparts, + int active, u32 bootnum_dt) +{ + struct device_node *np = mtd_get_of_node(mtd); + struct device_node *child; + struct mtd_partition *parts; + int ret, nr_parts, index = 0; + + nr_parts = of_get_child_count(np); + if (nr_parts > NR_PARTS_MAX) { + pr_err("too many partitions found!\n"); + return -EINVAL; + } + + parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + for_each_child_of_node(np, child) { + u32 reg[2]; + if (of_n_addr_cells(child) != 1 || + of_n_size_cells(child) != 1) + { + ret = -EINVAL; + break; + } + + ret = of_property_read_u32_array(child, "reg", reg, 2); + if (ret) + break; + ret = of_property_read_string(child, "label-base", + &parts[index].name); + if (ret) + break; + + if (!active) { + parts[index].name = devm_kasprintf(&mtd->dev, GFP_KERNEL, + "%s%u", + parts[index].name, bootnum_dt); + if (!parts[index].name) { + ret = -ENOMEM; + break; + } + } + parts[index].offset = reg[0]; + parts[index].size = reg[1]; + index++; + } + of_node_put(child); + + if (ret) + kfree(parts); + else + *pparts = parts; + return ret ? ret : nr_parts; +} + +static int +mtdsplit_mstcboot_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *np = mtd_get_of_node(mtd); + u32 bootnum_dt; + int ret; + + ret = mstcboot_is_active(mtd, &bootnum_dt); + if (ret < 0) + goto exit; + + if (of_get_child_count(np)) + ret = mstcboot_parse_fixed_parts(mtd, pparts, ret, bootnum_dt); + else if (ret != 0) + ret = mstcboot_parse_image_parts(mtd, pparts); + +exit: + /* + * return 0 when ret=-ENODEV, to prevent deletion of + * parent mtd partitions on Linux 6.7 and later + */ + return ret == -ENODEV ? 0 : ret; +} + +static const struct of_device_id mtdsplit_mstcboot_of_match_table[] = { + { .compatible = "mstc,boot" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_mstcboot_of_match_table); + +static struct mtd_part_parser mtdsplit_mstcboot_parser = { + .owner = THIS_MODULE, + .name = "mstc-boot", + .of_match_table = mtdsplit_mstcboot_of_match_table, + .parse_fn = mtdsplit_mstcboot_parse, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; +module_mtd_part_parser(mtdsplit_mstcboot_parser) diff --git a/drivers/mtd/mtdsplit/mtdsplit_seama.c b/drivers/mtd/mtdsplit/mtdsplit_seama.c new file mode 100644 index 000000000000..5d49171b1f74 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_seama.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define SEAMA_MAGIC 0x5EA3A417 +#define SEAMA_NR_PARTS 2 +#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +struct seama_header { + __be32 magic; /* should always be SEAMA_MAGIC. */ + __be16 reserved; /* reserved for */ + __be16 metasize; /* size of the META data */ + __be32 size; /* size of the image */ + u8 md5[16]; /* digest */ +}; + +static int mtdsplit_parse_seama(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct seama_header hdr; + size_t hdr_len, retlen, kernel_ent_size; + size_t rootfs_offset; + struct mtd_partition *parts; + enum mtdsplit_part_type type; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) + return -EINVAL; + + kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) + + be16_to_cpu(hdr.metasize); + if (kernel_ent_size > master->size) + return -EINVAL; + + /* Check for the rootfs right after Seama entity with a kernel. */ + err = mtd_check_rootfs_magic(master, kernel_ent_size, &type); + if (!err) { + rootfs_offset = kernel_ent_size; + } else { + /* + * On some devices firmware entity might contain both: kernel + * and rootfs. We can't determine kernel size so we just have to + * look for rootfs magic. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, &type); + if (err) + return err; + } + + parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = sizeof hdr + be16_to_cpu(hdr.metasize); + parts[0].size = rootfs_offset - parts[0].offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return SEAMA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_seama_of_match_table[] = { + { .compatible = "seama" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_seama_of_match_table); + +static struct mtd_part_parser mtdsplit_seama_parser = { + .owner = THIS_MODULE, + .name = "seama-fw", + .of_match_table = mtdsplit_seama_of_match_table, + .parse_fn = mtdsplit_parse_seama, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_seama_init(void) +{ + register_mtd_parser(&mtdsplit_seama_parser); + + return 0; +} + +subsys_initcall(mtdsplit_seama_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_seil.c b/drivers/mtd/mtdsplit/mtdsplit_seil.c new file mode 100644 index 000000000000..e58bb49b23fc --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_seil.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* a mtdsplit driver for IIJ SEIL devices */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define NR_PARTS 2 +#define SEIL_VFMT 1 +#define LDR_ENV_PART_NAME "bootloader-env" +#define LDR_ENV_KEY_BOOTDEV "BOOTDEV" + +struct seil_header { + uint64_t id; /* Identifier */ + uint8_t copy[80]; /* Copyright */ + uint32_t dcrc; /* Data CRC Checksum */ + uint32_t vfmt; /* Image Version Format */ + uint32_t vmjr; /* Image Version Major */ + uint32_t vmnr; /* Image Version Minor */ + uint8_t vrel[32]; /* Image Version Release */ + uint32_t dxor; /* xor value for Data? */ + uint32_t dlen; /* Data Length */ +}; + +/* + * check whether the current mtd device is active or not + * + * example of BOOTDEV value (IIJ SA-W2): + * - "flash" : primary image on flash + * - "rescue" : secondary image on flash + * - "usb" : usb storage + * - "lan0/1" : network + */ +static bool seil_bootdev_is_active(struct device_node *np) +{ + struct mtd_info *env_mtd; + char *buf, *var, *value, *eq; + const char *devnm; + size_t rdlen; + int ret; + + /* + * read bootdev name of the partition + * if doesn't exist, return true and skip checking of active device + */ + ret = of_property_read_string(np, "iij,bootdev-name", &devnm); + if (ret == -EINVAL) + return true; + else if (ret < 0) + return false; + + env_mtd = get_mtd_device_nm(LDR_ENV_PART_NAME); + if (IS_ERR(env_mtd)) { + pr_err("failed to get mtd device \"%s\"", LDR_ENV_PART_NAME); + return false; + } + + buf = vmalloc(env_mtd->size); + if (!buf) + return false; + + ret = mtd_read(env_mtd, 0, env_mtd->size, &rdlen, buf); + if (ret || rdlen != env_mtd->size) { + pr_err("failed to read from mtd (%d)\n", ret); + ret = 0; + goto exit_vfree; + } + + for (var = buf, ret = false; + var < buf + env_mtd->size && *var; + var = value + strlen(value) + 1) { + eq = strchr(var, '='); + if (!eq) + break; + *eq = '\0'; + value = eq + 1; + + pr_debug("ENV: %s=%s\n", var, value); + if (!strcmp(var, LDR_ENV_KEY_BOOTDEV)) { + ret = !strcmp(devnm, value); + break; + } + } + +exit_vfree: + vfree(buf); + + return ret; +} + +static int mtdsplit_parse_seil_fw(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *np = mtd_get_of_node(master); + struct mtd_partition *parts; + struct seil_header header; + size_t image_size = 0; + size_t rootfs_offset; + size_t hdrlen = sizeof(header); + size_t retlen; + int ret; + u64 id; + + if (!seil_bootdev_is_active(np)) + return -ENODEV; + + ret = of_property_read_u64(np, "iij,seil-id", &id); + if (ret) { + pr_err("failed to get iij,seil-id from dt\n"); + return ret; + } + pr_debug("got seil-id=0x%016llx from dt\n", id); + + parts = kcalloc(NR_PARTS, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + ret = mtd_read(master, 0, hdrlen, &retlen, (void *)&header); + if (ret) + goto err_free_parts; + + if (retlen != hdrlen) { + ret = -EIO; + goto err_free_parts; + } + + if (be64_to_cpu(header.id) != id || + be32_to_cpu(header.vfmt) != SEIL_VFMT) { + pr_debug("no valid seil image found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_parts; + } + + image_size = hdrlen + be32_to_cpu(header.dlen); + if (image_size > master->size) { + pr_err("seil image exceeds MTD device \"%s\"\n", master->name); + ret = -EINVAL; + goto err_free_parts; + } + + /* find the roots after the seil image */ + ret = mtd_find_rootfs_from(master, image_size, + master->size, &rootfs_offset, NULL); + if (ret || (master->size - rootfs_offset) == 0) { + pr_debug("no rootfs after seil image in \"%s\"\n", + master->name); + ret = -ENODEV; + goto err_free_parts; + } + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return NR_PARTS; + +err_free_parts: + kfree(parts); + return ret; +} + +static const struct of_device_id mtdsplit_seil_fw_of_match_table[] = { + { .compatible = "iij,seil-firmware" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_seil_fw_of_match_table); + +static struct mtd_part_parser mtdsplit_seil_fw_parser = { + .owner = THIS_MODULE, + .name = "seil-fw", + .of_match_table = mtdsplit_seil_fw_of_match_table, + .parse_fn = mtdsplit_parse_seil_fw, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +module_mtd_part_parser(mtdsplit_seil_fw_parser); diff --git a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c new file mode 100644 index 000000000000..f6353da65b0e --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +static int +mtdsplit_parse_squashfs(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *part; + struct mtd_info *parent_mtd; + size_t part_offset; + size_t squashfs_len; + int err; + + err = mtd_get_squashfs_len(master, 0, &squashfs_len); + if (err) + return err; + + parent_mtd = mtd_get_master(master); + part_offset = mtdpart_get_offset(master); + + part = kzalloc(sizeof(*part), GFP_KERNEL); + if (!part) { + pr_alert("unable to allocate memory for \"%s\" partition\n", + ROOTFS_SPLIT_NAME); + return -ENOMEM; + } + + part->name = ROOTFS_SPLIT_NAME; + part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, + parent_mtd) - part_offset; + part->size = mtd_rounddown_to_eb(master->size - part->offset, master); + + *pparts = part; + return 1; +} + +static struct mtd_part_parser mtdsplit_squashfs_parser = { + .owner = THIS_MODULE, + .name = "squashfs-split", + .parse_fn = mtdsplit_parse_squashfs, + .type = MTD_PARSER_TYPE_ROOTFS, +}; + +static int __init mtdsplit_squashfs_init(void) +{ + register_mtd_parser(&mtdsplit_squashfs_parser); + + return 0; +} + +subsys_initcall(mtdsplit_squashfs_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/drivers/mtd/mtdsplit/mtdsplit_tplink.c new file mode 100644 index 000000000000..8909c107a094 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_tplink.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TPLINK_NR_PARTS 2 +#define TPLINK_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +#define MD5SUM_LEN 16 + +struct fw_v1 { + char vendor_name[24]; + char fw_version[36]; + uint32_t hw_id; /* hardware id */ + uint32_t hw_rev; /* hardware revision */ + uint32_t unk1; + uint8_t md5sum1[MD5SUM_LEN]; + uint32_t unk2; + uint8_t md5sum2[MD5SUM_LEN]; + uint32_t unk3; + uint32_t kernel_la; /* kernel load address */ + uint32_t kernel_ep; /* kernel entry point */ + uint32_t fw_length; /* total length of the firmware */ + uint32_t kernel_ofs; /* kernel data offset */ + uint32_t kernel_len; /* kernel data length */ + uint32_t rootfs_ofs; /* rootfs data offset */ + uint32_t rootfs_len; /* rootfs data length */ + uint32_t boot_ofs; /* bootloader data offset */ + uint32_t boot_len; /* bootloader data length */ + uint8_t pad[360]; +} __attribute__ ((packed)); + +struct fw_v2 { + char fw_version[48]; /* 0x04: fw version string */ + uint32_t hw_id; /* 0x34: hardware id */ + uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */ + uint32_t unk1; /* 0x3c: 0x00000000 */ + uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */ + uint32_t unk2; /* 0x50: 0x00000000 */ + uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */ + uint32_t unk3; /* 0x64: 0xffffffff */ + + uint32_t kernel_la; /* 0x68: kernel load address */ + uint32_t kernel_ep; /* 0x6c: kernel entry point */ + uint32_t fw_length; /* 0x70: total length of the image */ + uint32_t kernel_ofs; /* 0x74: kernel data offset */ + uint32_t kernel_len; /* 0x78: kernel data length */ + uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */ + uint32_t rootfs_len; /* 0x80: rootfs data length */ + uint32_t boot_ofs; /* 0x84: FIXME: seems to be unused */ + uint32_t boot_len; /* 0x88: FIXME: seems to be unused */ + uint16_t unk4; /* 0x8c: 0x55aa */ + uint8_t sver_hi; /* 0x8e */ + uint8_t sver_lo; /* 0x8f */ + uint8_t unk5; /* 0x90: magic: 0xa5 */ + uint8_t ver_hi; /* 0x91 */ + uint8_t ver_mid; /* 0x92 */ + uint8_t ver_lo; /* 0x93 */ + uint8_t pad[364]; +} __attribute__ ((packed)); + +struct tplink_fw_header { + uint32_t version; + union { + struct fw_v1 v1; + struct fw_v2 v2; + }; +}; + +static int mtdsplit_parse_tplink(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct tplink_fw_header hdr; + size_t hdr_len, retlen, kernel_size; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + switch (le32_to_cpu(hdr.version)) { + case 1: + if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len); + rootfs_offset = be32_to_cpu(hdr.v1.rootfs_ofs); + break; + case 2: + case 3: + if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len); + rootfs_offset = be32_to_cpu(hdr.v2.rootfs_ofs); + break; + default: + return -EINVAL; + } + + if (kernel_size > master->size) + return -EINVAL; + + /* Find the rootfs */ + err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (err) { + /* + * The size in the header might cover the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, NULL); + if (err) + return err; + } + + parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return TPLINK_NR_PARTS; +} + +static const struct of_device_id mtdsplit_tplink_of_match_table[] = { + { .compatible = "tplink,firmware" }, + {}, +}; + +static struct mtd_part_parser mtdsplit_tplink_parser = { + .owner = THIS_MODULE, + .name = "tplink-fw", + .of_match_table = mtdsplit_tplink_of_match_table, + .parse_fn = mtdsplit_parse_tplink, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_tplink_init(void) +{ + register_mtd_parser(&mtdsplit_tplink_parser); + + return 0; +} + +subsys_initcall(mtdsplit_tplink_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_trx.c b/drivers/mtd/mtdsplit/mtdsplit_trx.c new file mode 100644 index 000000000000..b853ec9e5283 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_trx.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ + +struct trx_header { + __le32 magic; + __le32 len; + __le32 crc32; + __le32 flag_version; + __le32 offset[4]; +}; + +static int +read_trx_header(struct mtd_info *mtd, size_t offset, + struct trx_header *header) +{ + size_t header_len; + size_t retlen; + int ret; + + header_len = sizeof(*header); + ret = mtd_read(mtd, offset, header_len, &retlen, + (unsigned char *) header); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int +mtdsplit_parse_trx(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct trx_header hdr; + int nr_parts; + size_t offset; + size_t trx_offset; + size_t trx_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* find trx image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + trx_size = 0; + + ret = read_trx_header(master, offset, &hdr); + if (ret) + continue; + + if (hdr.magic != cpu_to_le32(TRX_MAGIC)) { + pr_debug("no valid trx header found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + trx_size = le32_to_cpu(hdr.len); + if ((offset + trx_size) > master->size) { + pr_debug("trx image exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (trx_size == 0) { + pr_debug("no trx header found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + trx_offset = offset + hdr.offset[0]; + rootfs_offset = offset + hdr.offset[1]; + rootfs_size = master->size - rootfs_offset; + trx_size = rootfs_offset - trx_offset; + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = trx_offset; + parts[0].size = trx_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return nr_parts; + +err: + kfree(parts); + return ret; +} + +static const struct of_device_id trx_parser_of_match_table[] = { + { .compatible = "openwrt,trx" }, + {}, +}; +MODULE_DEVICE_TABLE(of, trx_parser_of_match_table); + +static struct mtd_part_parser trx_parser = { + .owner = THIS_MODULE, + .name = "trx-fw", + .of_match_table = trx_parser_of_match_table, + .parse_fn = mtdsplit_parse_trx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_trx_init(void) +{ + register_mtd_parser(&trx_parser); + + return 0; +} + +module_init(mtdsplit_trx_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/drivers/mtd/mtdsplit/mtdsplit_uimage.c new file mode 100644 index 000000000000..0d9685490030 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ +struct uimage_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +}; + +static int +read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, + size_t header_len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, header_len, &retlen, buf); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static void uimage_parse_dt(struct mtd_info *master, int *extralen, + u32 *ih_magic, u32 *ih_type, + u32 *header_offset, u32 *part_magic) +{ + struct device_node *np = mtd_get_of_node(master); + + if (!np || !of_device_is_compatible(np, "openwrt,uimage")) + return; + + if (!of_property_read_u32(np, "openwrt,padding", extralen)) + pr_debug("got openwrt,padding=%d from device-tree\n", *extralen); + if (!of_property_read_u32(np, "openwrt,ih-magic", ih_magic)) + pr_debug("got openwrt,ih-magic=%08x from device-tree\n", *ih_magic); + if (!of_property_read_u32(np, "openwrt,ih-type", ih_type)) + pr_debug("got openwrt,ih-type=%08x from device-tree\n", *ih_type); + if (!of_property_read_u32(np, "openwrt,offset", header_offset)) + pr_debug("got ih-start=%u from device-tree\n", *header_offset); + if (!of_property_read_u32(np, "openwrt,partition-magic", part_magic)) + pr_debug("got openwrt,partition-magic=%08x from device-tree\n", *part_magic); +} + +static ssize_t uimage_verify_default(u_char *buf, u32 ih_magic, u32 ih_type) +{ + struct uimage_header *header = (struct uimage_header *)buf; + + /* default sanity checks */ + if (be32_to_cpu(header->ih_magic) != ih_magic) { + pr_debug("invalid uImage magic: %08x != %08x\n", + be32_to_cpu(header->ih_magic), ih_magic); + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX) { + pr_debug("invalid uImage OS: %08x != %08x\n", + be32_to_cpu(header->ih_os), IH_OS_LINUX); + return -EINVAL; + } + + if (header->ih_type != ih_type) { + pr_debug("invalid uImage type: %08x != %08x\n", + be32_to_cpu(header->ih_type), ih_type); + return -EINVAL; + } + + return 0; +} + +/** + * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts + * + * @find_header: function to call for a block of data that will return offset + * and tail padding length of a valid uImage header if found + */ +static int __mtdsplit_parse_uimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + u_char *buf; + int nr_parts; + size_t offset; + size_t uimage_offset; + size_t uimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + size_t buflen; + int uimage_part, rf_part; + int ret; + int extralen = 0; + u32 ih_magic = IH_MAGIC; + u32 ih_type = IH_TYPE_KERNEL; + u32 header_offset = 0; + u32 part_magic = 0; + enum mtdsplit_part_type type; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + uimage_parse_dt(master, &extralen, &ih_magic, &ih_type, &header_offset, &part_magic); + buflen = sizeof(struct uimage_header) + header_offset; + buf = vmalloc(buflen); + if (!buf) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find uImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + struct uimage_header *header; + + uimage_size = 0; + + ret = read_uimage_header(master, offset, buf, buflen); + if (ret) + continue; + + /* verify optional partition magic before uimage header */ + if (header_offset && part_magic && (be32_to_cpu(*(u32 *)buf) != part_magic)) + continue; + + ret = uimage_verify_default(buf + header_offset, ih_magic, ih_type); + if (ret < 0) { + pr_debug("no valid uImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + header = (struct uimage_header *)(buf + header_offset); + + uimage_size = sizeof(*header) + + be32_to_cpu(header->ih_size) + header_offset + extralen; + + if ((offset + uimage_size) > master->size) { + pr_debug("uImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (uimage_size == 0) { + pr_info("no uImage found in \"%s\"\n", master->name); + ret = 0; + goto err_free_buf; + } + + uimage_offset = offset; + + if (uimage_offset == 0) { + uimage_part = 0; + rf_part = 1; + + /* find the roots after the uImage */ + ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size, + master->size, &rootfs_offset, &type); + if (ret) { + pr_info("no rootfs after uImage in \"%s\"\n", master->name); + ret = 0; + goto err_free_buf; + } + + rootfs_size = master->size - rootfs_offset; + uimage_size = rootfs_offset - uimage_offset; + } else { + rf_part = 0; + uimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0, &type); + if (ret) { + pr_info("no rootfs before uImage in \"%s\"\n", master->name); + ret = 0; + goto err_free_buf; + } + + rootfs_offset = 0; + rootfs_size = uimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + parts[uimage_part].name = KERNEL_PART_NAME; + parts[uimage_part].offset = uimage_offset; + parts[uimage_part].size = uimage_size; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[rf_part].name = UBI_PART_NAME; + else + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(buf); + + *pparts = parts; + return nr_parts; + +err_free_buf: + vfree(buf); + +err_free_parts: + kfree(parts); + return ret; +} + +static const struct of_device_id mtdsplit_uimage_of_match_table[] = { + { .compatible = "denx,uimage" }, + { .compatible = "openwrt,uimage" }, + {}, +}; + +static struct mtd_part_parser uimage_generic_parser = { + .owner = THIS_MODULE, + .name = "uimage-fw", + .of_match_table = mtdsplit_uimage_of_match_table, + .parse_fn = __mtdsplit_parse_uimage, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_uimage_init(void) +{ + register_mtd_parser(&uimage_generic_parser); + + return 0; +} + +module_init(mtdsplit_uimage_init); diff --git a/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c new file mode 100644 index 000000000000..dfd6058ae7e4 --- /dev/null +++ b/drivers/mtd/mtdsplit/mtdsplit_wrgg.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * Copyright (C) 2016 Stijn Tintel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define WRGG_NR_PARTS 2 +#define WRGG_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ +#define WRGG03_MAGIC 0x20080321 +#define WRG_MAGIC 0x20040220 + +struct wrgg03_header { + char signature[32]; + uint32_t magic1; + uint32_t magic2; + char version[16]; + char model[16]; + uint32_t flag[2]; + uint32_t reserve[2]; + char buildno[16]; + uint32_t size; + uint32_t offset; + char devname[32]; + char digest[16]; +} __attribute__ ((packed)); + +struct wrg_header { + char signature[32]; + uint32_t magic1; + uint32_t magic2; + uint32_t size; + uint32_t offset; + char devname[32]; + char digest[16]; +} __attribute__ ((packed)); + + +static int mtdsplit_parse_wrgg(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct wrgg03_header hdr; + size_t hdr_len, retlen, kernel_ent_size; + size_t rootfs_offset; + struct mtd_partition *parts; + enum mtdsplit_part_type type; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) { + kernel_ent_size = hdr_len + be32_to_cpu(hdr.size); + /* + * If this becomes silly big it's probably because the + * WRGG image is little-endian. + */ + if (kernel_ent_size > master->size) + kernel_ent_size = hdr_len + le32_to_cpu(hdr.size); + + /* Now what ?! It's neither */ + if (kernel_ent_size > master->size) + return -EINVAL; + } else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) { + kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu( + ((struct wrg_header*)&hdr)->size); + } else { + return -EINVAL; + } + + if (kernel_ent_size > master->size) + return -EINVAL; + + /* + * The size in the header covers the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, &type); + if (err) + return err; + + parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return WRGG_NR_PARTS; +} + +static const struct of_device_id mtdsplit_wrgg_of_match_table[] = { + { .compatible = "wrg" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table); + +static struct mtd_part_parser mtdsplit_wrgg_parser = { + .owner = THIS_MODULE, + .name = "wrgg-fw", + .of_match_table = mtdsplit_wrgg_of_match_table, + .parse_fn = mtdsplit_parse_wrgg, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_wrgg_init(void) +{ + register_mtd_parser(&mtdsplit_wrgg_parser); + + return 0; +} + +subsys_initcall(mtdsplit_wrgg_init); diff --git a/drivers/mtd/nand/mtk_bmt.c b/drivers/mtd/nand/mtk_bmt.c new file mode 100644 index 000000000000..063adb50fb60 --- /dev/null +++ b/drivers/mtd/nand/mtk_bmt.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Xiangsheng Hou + * Copyright (c) 2020-2022 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "mtk_bmt.h" + +struct bmt_desc bmtd = {}; + +/* -------- Nand operations wrapper -------- */ +int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset) +{ + int pages = bmtd.blk_size >> bmtd.pg_shift; + loff_t src = (loff_t)src_blk << bmtd.blk_shift; + loff_t dest = (loff_t)dest_blk << bmtd.blk_shift; + loff_t offset = 0; + uint8_t oob[64]; + int i, ret; + + for (i = 0; i < pages; i++) { + struct mtd_oob_ops rd_ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = oob, + .ooblen = min_t(int, bmtd.mtd->oobsize / pages, sizeof(oob)), + .datbuf = bmtd.data_buf, + .len = bmtd.pg_size, + }; + struct mtd_oob_ops wr_ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = oob, + .datbuf = bmtd.data_buf, + .len = bmtd.pg_size, + }; + + if (offset >= max_offset) + break; + + ret = bmtd._read_oob(bmtd.mtd, src + offset, &rd_ops); + if (ret < 0 && !mtd_is_bitflip(ret)) + return ret; + + if (!rd_ops.retlen) + break; + + ret = bmtd._write_oob(bmtd.mtd, dest + offset, &wr_ops); + if (ret < 0) + return ret; + + wr_ops.ooblen = rd_ops.oobretlen; + offset += rd_ops.retlen; + } + + return 0; +} + +/* -------- Bad Blocks Management -------- */ +bool mapping_block_in_range(int block, int *start, int *end) +{ + const __be32 *cur = bmtd.remap_range; + u32 addr = block << bmtd.blk_shift; + int i; + + if (!cur || !bmtd.remap_range_len) { + *start = 0; + *end = bmtd.total_blks; + return true; + } + + for (i = 0; i < bmtd.remap_range_len; i++, cur += 2) { + if (addr < be32_to_cpu(cur[0]) || addr >= be32_to_cpu(cur[1])) + continue; + + *start = be32_to_cpu(cur[0]); + *end = be32_to_cpu(cur[1]); + return true; + } + + return false; +} + +static bool +mtk_bmt_remap_block(u32 block, u32 mapped_block, int copy_len) +{ + int start, end; + + if (!mapping_block_in_range(block, &start, &end)) + return false; + + return bmtd.ops->remap_block(block, mapped_block, copy_len); +} + +static int +mtk_bmt_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct mtd_oob_ops cur_ops = *ops; + int retry_count = 0; + loff_t cur_from; + int ret = 0; + int max_bitflips = 0; + + ops->retlen = 0; + ops->oobretlen = 0; + + while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { + int cur_ret; + + u32 offset = from & (bmtd.blk_size - 1); + u32 block = from >> bmtd.blk_shift; + int cur_block; + + cur_block = bmtd.ops->get_mapping_block(block); + if (cur_block < 0) + return -EIO; + + cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; + + cur_ops.oobretlen = 0; + cur_ops.retlen = 0; + cur_ops.len = min_t(u32, mtd->erasesize - offset, + ops->len - ops->retlen); + cur_ret = bmtd._read_oob(mtd, cur_from, &cur_ops); + if (cur_ret < 0) + ret = cur_ret; + else + max_bitflips = max_t(int, max_bitflips, cur_ret); + if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) { + if (mtk_bmt_remap_block(block, cur_block, mtd->erasesize) && + retry_count++ < 10) + continue; + + goto out; + } + + if (mtd->bitflip_threshold && cur_ret >= mtd->bitflip_threshold) + mtk_bmt_remap_block(block, cur_block, mtd->erasesize); + + ops->retlen += cur_ops.retlen; + ops->oobretlen += cur_ops.oobretlen; + + cur_ops.ooboffs = 0; + cur_ops.datbuf += cur_ops.retlen; + cur_ops.oobbuf += cur_ops.oobretlen; + cur_ops.ooblen -= cur_ops.oobretlen; + + if (!cur_ops.len) + cur_ops.len = mtd->erasesize - offset; + + from += cur_ops.len; + retry_count = 0; + } + +out: + if (ret < 0) + return ret; + + return max_bitflips; +} + +static int +mtk_bmt_write(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + struct mtd_oob_ops cur_ops = *ops; + int retry_count = 0; + loff_t cur_to; + int ret; + + ops->retlen = 0; + ops->oobretlen = 0; + + while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { + u32 offset = to & (bmtd.blk_size - 1); + u32 block = to >> bmtd.blk_shift; + int cur_block; + + cur_block = bmtd.ops->get_mapping_block(block); + if (cur_block < 0) + return -EIO; + + cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; + + cur_ops.oobretlen = 0; + cur_ops.retlen = 0; + cur_ops.len = min_t(u32, bmtd.blk_size - offset, + ops->len - ops->retlen); + ret = bmtd._write_oob(mtd, cur_to, &cur_ops); + if (ret < 0) { + if (mtk_bmt_remap_block(block, cur_block, offset) && + retry_count++ < 10) + continue; + + return ret; + } + + ops->retlen += cur_ops.retlen; + ops->oobretlen += cur_ops.oobretlen; + + cur_ops.ooboffs = 0; + cur_ops.datbuf += cur_ops.retlen; + cur_ops.oobbuf += cur_ops.oobretlen; + cur_ops.ooblen -= cur_ops.oobretlen; + + if (!cur_ops.len) + cur_ops.len = mtd->erasesize - offset; + + to += cur_ops.len; + retry_count = 0; + } + + return 0; +} + +static int +mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct erase_info mapped_instr = { + .len = bmtd.blk_size, + }; + int retry_count = 0; + u64 start_addr, end_addr; + int ret; + u16 orig_block; + int block; + + start_addr = instr->addr & (~mtd->erasesize_mask); + end_addr = instr->addr + instr->len; + + while (start_addr < end_addr) { + orig_block = start_addr >> bmtd.blk_shift; + block = bmtd.ops->get_mapping_block(orig_block); + if (block < 0) + return -EIO; + mapped_instr.addr = (loff_t)block << bmtd.blk_shift; + ret = bmtd._erase(mtd, &mapped_instr); + if (ret) { + if (mtk_bmt_remap_block(orig_block, block, 0) && + retry_count++ < 10) + continue; + instr->fail_addr = start_addr; + break; + } + start_addr += mtd->erasesize; + retry_count = 0; + } + + return ret; +} +static int +mtk_bmt_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + int retry_count = 0; + u16 orig_block = ofs >> bmtd.blk_shift; + u16 block; + int ret; + +retry: + block = bmtd.ops->get_mapping_block(orig_block); + ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); + if (ret) { + if (mtk_bmt_remap_block(orig_block, block, bmtd.blk_size) && + retry_count++ < 10) + goto retry; + } + return ret; +} + +static int +mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + u16 orig_block = ofs >> bmtd.blk_shift; + int block; + + block = bmtd.ops->get_mapping_block(orig_block); + if (block < 0) + return -EIO; + + mtk_bmt_remap_block(orig_block, block, bmtd.blk_size); + + return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); +} + +static void +mtk_bmt_replace_ops(struct mtd_info *mtd) +{ + bmtd._read_oob = mtd->_read_oob; + bmtd._write_oob = mtd->_write_oob; + bmtd._erase = mtd->_erase; + bmtd._block_isbad = mtd->_block_isbad; + bmtd._block_markbad = mtd->_block_markbad; + + mtd->_read_oob = mtk_bmt_read; + mtd->_write_oob = mtk_bmt_write; + mtd->_erase = mtk_bmt_mtd_erase; + mtd->_block_isbad = mtk_bmt_block_isbad; + mtd->_block_markbad = mtk_bmt_block_markbad; +} + +static int mtk_bmt_debug_repair(void *data, u64 val) +{ + int block = val >> bmtd.blk_shift; + int prev_block, new_block; + + prev_block = bmtd.ops->get_mapping_block(block); + if (prev_block < 0) + return -EIO; + + bmtd.ops->unmap_block(block); + new_block = bmtd.ops->get_mapping_block(block); + if (new_block < 0) + return -EIO; + + if (prev_block == new_block) + return 0; + + bbt_nand_erase(new_block); + bbt_nand_copy(new_block, prev_block, bmtd.blk_size); + + return 0; +} + +static int mtk_bmt_debug_mark_good(void *data, u64 val) +{ + bmtd.ops->unmap_block(val >> bmtd.blk_shift); + + return 0; +} + +static int mtk_bmt_debug_mark_bad(void *data, u64 val) +{ + u32 block = val >> bmtd.blk_shift; + int cur_block; + + cur_block = bmtd.ops->get_mapping_block(block); + if (cur_block < 0) + return -EIO; + + mtk_bmt_remap_block(block, cur_block, bmtd.blk_size); + + return 0; +} + +static int mtk_bmt_debug(void *data, u64 val) +{ + return bmtd.ops->debug(data, val); +} + + +DEFINE_DEBUGFS_ATTRIBUTE(fops_repair, NULL, mtk_bmt_debug_repair, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_debug, NULL, mtk_bmt_debug, "%llu\n"); + +static void +mtk_bmt_add_debugfs(void) +{ + struct dentry *dir; + + dir = bmtd.debugfs_dir = debugfs_create_dir("mtk-bmt", NULL); + if (!dir) + return; + + debugfs_create_file_unsafe("repair", S_IWUSR, dir, NULL, &fops_repair); + debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); + debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); + debugfs_create_file_unsafe("debug", S_IWUSR, dir, NULL, &fops_debug); +} + +void mtk_bmt_detach(struct mtd_info *mtd) +{ + if (bmtd.mtd != mtd) + return; + + if (bmtd.debugfs_dir) + debugfs_remove_recursive(bmtd.debugfs_dir); + bmtd.debugfs_dir = NULL; + + kfree(bmtd.bbt_buf); + kfree(bmtd.data_buf); + + mtd->_read_oob = bmtd._read_oob; + mtd->_write_oob = bmtd._write_oob; + mtd->_erase = bmtd._erase; + mtd->_block_isbad = bmtd._block_isbad; + mtd->_block_markbad = bmtd._block_markbad; + mtd->size = bmtd.total_blks << bmtd.blk_shift; + + memset(&bmtd, 0, sizeof(bmtd)); +} + + +int mtk_bmt_attach(struct mtd_info *mtd) +{ + struct device_node *np; + int ret = 0; + u32 overridden_oobsize = 0; + + if (bmtd.mtd) + return -ENOSPC; + + np = mtd_get_of_node(mtd); + if (!np) + return 0; + + if (of_property_read_bool(np, "mediatek,bmt-v2")) + bmtd.ops = &mtk_bmt_v2_ops; + else if (of_property_read_bool(np, "mediatek,nmbm")) + bmtd.ops = &mtk_bmt_nmbm_ops; + else if (of_property_read_bool(np, "mediatek,bbt")) + bmtd.ops = &mtk_bmt_bbt_ops; + else + return 0; + + bmtd.remap_range = of_get_property(np, "mediatek,bmt-remap-range", + &bmtd.remap_range_len); + bmtd.remap_range_len /= 8; + + bmtd.mtd = mtd; + mtk_bmt_replace_ops(mtd); + + if (!of_property_read_u32(np, "mediatek,bmt-mtd-overridden-oobsize", + &overridden_oobsize)) + if (overridden_oobsize < bmtd.mtd->oobsize) { + bmtd.mtd->oobsize = overridden_oobsize; + pr_info("NMBM: mtd OOB size has been overridden to %luB\n", + (long unsigned int)bmtd.mtd->oobsize); + } + + bmtd.blk_size = mtd->erasesize; + bmtd.blk_shift = ffs(bmtd.blk_size) - 1; + bmtd.pg_size = mtd->writesize; + bmtd.pg_shift = ffs(bmtd.pg_size) - 1; + bmtd.total_blks = mtd->size >> bmtd.blk_shift; + + bmtd.data_buf = kzalloc(bmtd.pg_size + bmtd.mtd->oobsize, GFP_KERNEL); + if (!bmtd.data_buf) { + pr_info("nand: FATAL ERR: allocate buffer failed!\n"); + ret = -1; + goto error; + } + + memset(bmtd.data_buf, 0xff, bmtd.pg_size + bmtd.mtd->oobsize); + + ret = bmtd.ops->init(np); + if (ret) + goto error; + + mtk_bmt_add_debugfs(); + return 0; + +error: + mtk_bmt_detach(mtd); + return ret; +} + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); +MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); + diff --git a/drivers/mtd/nand/mtk_bmt.h b/drivers/mtd/nand/mtk_bmt.h new file mode 100644 index 000000000000..517ff7414f34 --- /dev/null +++ b/drivers/mtd/nand/mtk_bmt.h @@ -0,0 +1,137 @@ +#ifndef __MTK_BMT_PRIV_H +#define __MTK_BMT_PRIV_H + +#include +#include +#include +#include +#include +#include + +#define MAIN_SIGNATURE_OFFSET 0 +#define OOB_SIGNATURE_OFFSET 1 + +#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) + +struct mtk_bmt_ops { + char *sig; + unsigned int sig_len; + int (*init)(struct device_node *np); + bool (*remap_block)(u16 block, u16 mapped_block, int copy_len); + void (*unmap_block)(u16 block); + int (*get_mapping_block)(int block); + int (*debug)(void *data, u64 val); +}; + +struct bbbt; +struct nmbm_instance; + +struct bmt_desc { + struct mtd_info *mtd; + unsigned char *bbt_buf; + unsigned char *data_buf; + + int (*_read_oob) (struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); + int (*_write_oob) (struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops); + int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); + int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); + int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); + + const struct mtk_bmt_ops *ops; + + union { + struct bbbt *bbt; + struct nmbm_instance *ni; + }; + + struct dentry *debugfs_dir; + + u32 table_size; + u32 pg_size; + u32 blk_size; + u16 pg_shift; + u16 blk_shift; + /* bbt logical address */ + u16 pool_lba; + /* bbt physical address */ + u16 pool_pba; + /* Maximum count of bad blocks that the vendor guaranteed */ + u16 bb_max; + /* Total blocks of the Nand Chip */ + u16 total_blks; + /* The block(n) BMT is located at (bmt_tbl[n]) */ + u16 bmt_blk_idx; + /* How many pages needs to store 'struct bbbt' */ + u32 bmt_pgs; + + const __be32 *remap_range; + int remap_range_len; + + /* to compensate for driver level remapping */ + u8 oob_offset; +}; + +extern struct bmt_desc bmtd; +extern const struct mtk_bmt_ops mtk_bmt_v2_ops; +extern const struct mtk_bmt_ops mtk_bmt_bbt_ops; +extern const struct mtk_bmt_ops mtk_bmt_nmbm_ops; + +static inline u32 blk_pg(u16 block) +{ + return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift)); +} + +static inline int +bbt_nand_read(u32 page, unsigned char *dat, int dat_len, + unsigned char *fdm, int fdm_len) +{ + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .ooboffs = bmtd.oob_offset, + .oobbuf = fdm, + .ooblen = fdm_len, + .datbuf = dat, + .len = dat_len, + }; + int ret; + + ret = bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); + if (ret < 0) + return ret; + if (ret) + pr_info("%s: %d bitflips\n", __func__, ret); + return 0; +} + +static inline int bbt_nand_erase(u16 block) +{ + struct mtd_info *mtd = bmtd.mtd; + struct erase_info instr = { + .addr = (loff_t)block << bmtd.blk_shift, + .len = bmtd.blk_size, + }; + + return bmtd._erase(mtd, &instr); +} + +static inline int write_bmt(u16 block, unsigned char *dat) +{ + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, + .oobbuf = bmtd.ops->sig, + .ooblen = bmtd.ops->sig_len, + .datbuf = dat, + .len = bmtd.bmt_pgs << bmtd.pg_shift, + }; + loff_t addr = (loff_t)block << bmtd.blk_shift; + + return bmtd._write_oob(bmtd.mtd, addr, &ops); +} + +int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset); +bool mapping_block_in_range(int block, int *start, int *end); + +#endif diff --git a/drivers/mtd/nand/mtk_bmt_bbt.c b/drivers/mtd/nand/mtk_bmt_bbt.c new file mode 100644 index 000000000000..519e1ed70c7b --- /dev/null +++ b/drivers/mtd/nand/mtk_bmt_bbt.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Xiangsheng Hou + * Copyright (c) 2020-2022 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "mtk_bmt.h" + +static bool +bbt_block_is_bad(u16 block) +{ + u8 cur = bmtd.bbt_buf[block / 4]; + + return cur & (3 << ((block % 4) * 2)); +} + +static void +bbt_set_block_state(u16 block, bool bad) +{ + u8 mask = (3 << ((block % 4) * 2)); + + if (bad) + bmtd.bbt_buf[block / 4] |= mask; + else + bmtd.bbt_buf[block / 4] &= ~mask; + + bbt_nand_erase(bmtd.bmt_blk_idx); + write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf); +} + +static int +get_mapping_block_index_bbt(int block) +{ + int start, end, ofs; + int bad_blocks = 0; + int i; + + if (!mapping_block_in_range(block, &start, &end)) + return block; + + start >>= bmtd.blk_shift; + end >>= bmtd.blk_shift; + /* skip bad blocks within the mapping range */ + ofs = block - start; + for (i = start; i < end; i++) { + if (bbt_block_is_bad(i)) + bad_blocks++; + else if (ofs) + ofs--; + else + break; + } + + if (i < end) + return i; + + /* when overflowing, remap remaining blocks to bad ones */ + for (i = end - 1; bad_blocks > 0; i--) { + if (!bbt_block_is_bad(i)) + continue; + + bad_blocks--; + if (bad_blocks <= ofs) + return i; + } + + return block; +} + +static bool remap_block_bbt(u16 block, u16 mapped_blk, int copy_len) +{ + int start, end; + u16 new_blk; + + if (!mapping_block_in_range(block, &start, &end)) + return false; + + bbt_set_block_state(mapped_blk, true); + + new_blk = get_mapping_block_index_bbt(block); + bbt_nand_erase(new_blk); + if (copy_len > 0) + bbt_nand_copy(new_blk, mapped_blk, copy_len); + + return true; +} + +static void +unmap_block_bbt(u16 block) +{ + bbt_set_block_state(block, false); +} + +static int +mtk_bmt_read_bbt(void) +{ + u8 oob_buf[8]; + int i; + + for (i = bmtd.total_blks - 1; i >= bmtd.total_blks - 5; i--) { + u32 page = i << (bmtd.blk_shift - bmtd.pg_shift); + + if (bbt_nand_read(page, bmtd.bbt_buf, bmtd.pg_size, + oob_buf, sizeof(oob_buf))) { + pr_info("read_bbt: could not read block %d\n", i); + continue; + } + + if (oob_buf[0] != 0xff) { + pr_info("read_bbt: bad block at %d\n", i); + continue; + } + + if (memcmp(&oob_buf[1], "mtknand", 7) != 0) { + pr_info("read_bbt: signature mismatch in block %d\n", i); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, oob_buf, 8, 1); + continue; + } + + pr_info("read_bbt: found bbt at block %d\n", i); + bmtd.bmt_blk_idx = i; + return 0; + } + + return -EIO; +} + + +static int +mtk_bmt_init_bbt(struct device_node *np) +{ + int buf_size = round_up(bmtd.total_blks >> 2, bmtd.blk_size); + int ret; + + bmtd.bbt_buf = kmalloc(buf_size, GFP_KERNEL); + if (!bmtd.bbt_buf) + return -ENOMEM; + + memset(bmtd.bbt_buf, 0xff, buf_size); + bmtd.mtd->size -= 4 * bmtd.mtd->erasesize; + + ret = mtk_bmt_read_bbt(); + if (ret) + return ret; + + bmtd.bmt_pgs = buf_size / bmtd.pg_size; + + return 0; +} + +static int mtk_bmt_debug_bbt(void *data, u64 val) +{ + char buf[5]; + int i, k; + + switch (val) { + case 0: + for (i = 0; i < bmtd.total_blks; i += 4) { + u8 cur = bmtd.bbt_buf[i / 4]; + + for (k = 0; k < 4; k++, cur >>= 2) + buf[k] = (cur & 3) ? 'B' : '.'; + + buf[4] = 0; + printk("[%06x] %s\n", i * bmtd.blk_size, buf); + } + break; + case 100: +#if 0 + for (i = bmtd.bmt_blk_idx; i < bmtd.total_blks - 1; i++) + bbt_nand_erase(bmtd.bmt_blk_idx); +#endif + + bmtd.bmt_blk_idx = bmtd.total_blks - 1; + bbt_nand_erase(bmtd.bmt_blk_idx); + write_bmt(bmtd.bmt_blk_idx, bmtd.bbt_buf); + break; + default: + break; + } + return 0; +} + +const struct mtk_bmt_ops mtk_bmt_bbt_ops = { + .sig = "mtknand", + .sig_len = 7, + .init = mtk_bmt_init_bbt, + .remap_block = remap_block_bbt, + .unmap_block = unmap_block_bbt, + .get_mapping_block = get_mapping_block_index_bbt, + .debug = mtk_bmt_debug_bbt, +}; diff --git a/drivers/mtd/nand/mtk_bmt_nmbm.c b/drivers/mtd/nand/mtk_bmt_nmbm.c new file mode 100644 index 000000000000..a896e49ec047 --- /dev/null +++ b/drivers/mtd/nand/mtk_bmt_nmbm.c @@ -0,0 +1,2348 @@ +#include +#include +#include "mtk_bmt.h" + +#define nlog_err(ni, ...) printk(KERN_ERR __VA_ARGS__) +#define nlog_info(ni, ...) printk(KERN_INFO __VA_ARGS__) +#define nlog_debug(ni, ...) printk(KERN_INFO __VA_ARGS__) +#define nlog_warn(ni, ...) printk(KERN_WARNING __VA_ARGS__) + +#define NMBM_MAGIC_SIGNATURE 0x304d4d4e /* NMM0 */ +#define NMBM_MAGIC_INFO_TABLE 0x314d4d4e /* NMM1 */ + +#define NMBM_VERSION_MAJOR_S 0 +#define NMBM_VERSION_MAJOR_M 0xffff +#define NMBM_VERSION_MINOR_S 16 +#define NMBM_VERSION_MINOR_M 0xffff +#define NMBM_VERSION_MAKE(major, minor) (((major) & NMBM_VERSION_MAJOR_M) | \ + (((minor) & NMBM_VERSION_MINOR_M) << \ + NMBM_VERSION_MINOR_S)) +#define NMBM_VERSION_MAJOR_GET(ver) (((ver) >> NMBM_VERSION_MAJOR_S) & \ + NMBM_VERSION_MAJOR_M) +#define NMBM_VERSION_MINOR_GET(ver) (((ver) >> NMBM_VERSION_MINOR_S) & \ + NMBM_VERSION_MINOR_M) + +#define NMBM_BITMAP_UNIT_SIZE (sizeof(u32)) +#define NMBM_BITMAP_BITS_PER_BLOCK 2 +#define NMBM_BITMAP_BITS_PER_UNIT (8 * sizeof(u32)) +#define NMBM_BITMAP_BLOCKS_PER_UNIT (NMBM_BITMAP_BITS_PER_UNIT / \ + NMBM_BITMAP_BITS_PER_BLOCK) + +#define NMBM_SPARE_BLOCK_MULTI 1 +#define NMBM_SPARE_BLOCK_DIV 2 +#define NMBM_SPARE_BLOCK_MIN 2 + +#define NMBM_MGMT_DIV 16 +#define NMBM_MGMT_BLOCKS_MIN 32 + +#define NMBM_TRY_COUNT 3 + +#define BLOCK_ST_BAD 0 +#define BLOCK_ST_NEED_REMAP 2 +#define BLOCK_ST_GOOD 3 +#define BLOCK_ST_MASK 3 + +#define NMBM_VER_MAJOR 1 +#define NMBM_VER_MINOR 0 +#define NMBM_VER NMBM_VERSION_MAKE(NMBM_VER_MAJOR, \ + NMBM_VER_MINOR) + +struct nmbm_header { + u32 magic; + u32 version; + u32 size; + u32 checksum; +}; + +struct nmbm_signature { + struct nmbm_header header; + uint64_t nand_size; + u32 block_size; + u32 page_size; + u32 spare_size; + u32 mgmt_start_pb; + u8 max_try_count; + u8 padding[3]; +}; + +struct nmbm_info_table_header { + struct nmbm_header header; + u32 write_count; + u32 state_table_off; + u32 mapping_table_off; + u32 padding; +}; + +struct nmbm_instance { + u32 rawpage_size; + u32 rawblock_size; + u32 rawchip_size; + + struct nmbm_signature signature; + + u8 *info_table_cache; + u32 info_table_size; + u32 info_table_spare_blocks; + struct nmbm_info_table_header info_table; + + u32 *block_state; + u32 block_state_changed; + u32 state_table_size; + + int32_t *block_mapping; + u32 block_mapping_changed; + u32 mapping_table_size; + + u8 *page_cache; + + int protected; + + u32 block_count; + u32 data_block_count; + + u32 mgmt_start_ba; + u32 main_table_ba; + u32 backup_table_ba; + u32 mapping_blocks_ba; + u32 mapping_blocks_top_ba; + u32 signature_ba; + + u32 max_ratio; + u32 max_reserved_blocks; + bool empty_page_ecc_ok; + bool force_create; +}; + +static inline u32 nmbm_crc32(u32 crcval, const void *buf, size_t size) +{ + unsigned int chksz; + const unsigned char *p = buf; + + while (size) { + if (size > UINT_MAX) + chksz = UINT_MAX; + else + chksz = (uint)size; + + crcval = crc32_le(crcval, p, chksz); + size -= chksz; + p += chksz; + } + + return crcval; +} +/* + * nlog_table_creation - Print log of table creation event + * @ni: NMBM instance structure + * @main_table: whether the table is main info table + * @start_ba: start block address of the table + * @end_ba: block address after the end of the table + */ +static void nlog_table_creation(struct nmbm_instance *ni, bool main_table, + uint32_t start_ba, uint32_t end_ba) +{ + if (start_ba == end_ba - 1) + nlog_info(ni, "%s info table has been written to block %u\n", + main_table ? "Main" : "Backup", start_ba); + else + nlog_info(ni, "%s info table has been written to block %u-%u\n", + main_table ? "Main" : "Backup", start_ba, end_ba - 1); +} + +/* + * nlog_table_update - Print log of table update event + * @ni: NMBM instance structure + * @main_table: whether the table is main info table + * @start_ba: start block address of the table + * @end_ba: block address after the end of the table + */ +static void nlog_table_update(struct nmbm_instance *ni, bool main_table, + uint32_t start_ba, uint32_t end_ba) +{ + if (start_ba == end_ba - 1) + nlog_debug(ni, "%s info table has been updated in block %u\n", + main_table ? "Main" : "Backup", start_ba); + else + nlog_debug(ni, "%s info table has been updated in block %u-%u\n", + main_table ? "Main" : "Backup", start_ba, end_ba - 1); +} + +/* + * nlog_table_found - Print log of table found event + * @ni: NMBM instance structure + * @first_table: whether the table is first found info table + * @write_count: write count of the info table + * @start_ba: start block address of the table + * @end_ba: block address after the end of the table + */ +static void nlog_table_found(struct nmbm_instance *ni, bool first_table, + uint32_t write_count, uint32_t start_ba, + uint32_t end_ba) +{ + if (start_ba == end_ba - 1) + nlog_info(ni, "%s info table with writecount %u found in block %u\n", + first_table ? "First" : "Second", write_count, + start_ba); + else + nlog_info(ni, "%s info table with writecount %u found in block %u-%u\n", + first_table ? "First" : "Second", write_count, + start_ba, end_ba - 1); +} + +/*****************************************************************************/ +/* Address conversion functions */ +/*****************************************************************************/ + +/* + * ba2addr - Convert a block address to linear address + * @ni: NMBM instance structure + * @ba: Block address + */ +static uint64_t ba2addr(struct nmbm_instance *ni, uint32_t ba) +{ + return (uint64_t)ba << bmtd.blk_shift; +} +/* + * size2blk - Get minimum required blocks for storing specific size of data + * @ni: NMBM instance structure + * @size: size for storing + */ +static uint32_t size2blk(struct nmbm_instance *ni, uint64_t size) +{ + return (size + bmtd.blk_size - 1) >> bmtd.blk_shift; +} + +/*****************************************************************************/ +/* High level NAND chip APIs */ +/*****************************************************************************/ + +/* + * nmbm_read_phys_page - Read page with retry + * @ni: NMBM instance structure + * @addr: linear address where the data will be read from + * @data: the main data to be read + * @oob: the oob data to be read + * + * Read a page for at most NMBM_TRY_COUNT times. + * + * Return 0 for success, positive value for corrected bitflip count, + * -EBADMSG for ecc error, other negative values for other errors + */ +static int nmbm_read_phys_page(struct nmbm_instance *ni, uint64_t addr, + void *data, void *oob) +{ + int tries, ret; + + for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = oob, + .datbuf = data, + }; + + if (data) + ops.len = bmtd.pg_size; + if (oob) + ops.ooblen = mtd_oobavail(bmtd.mtd, &ops); + + ret = bmtd._read_oob(bmtd.mtd, addr, &ops); + if (ret == -EUCLEAN) + return min_t(u32, bmtd.mtd->bitflip_threshold + 1, + bmtd.mtd->ecc_strength); + if (ret >= 0) + return 0; + } + + if (ret != -EBADMSG) + nlog_err(ni, "Page read failed at address 0x%08llx\n", addr); + + return ret; +} + +/* + * nmbm_write_phys_page - Write page with retry + * @ni: NMBM instance structure + * @addr: linear address where the data will be written to + * @data: the main data to be written + * @oob: the oob data to be written + * + * Write a page for at most NMBM_TRY_COUNT times. + */ +static bool nmbm_write_phys_page(struct nmbm_instance *ni, uint64_t addr, + const void *data, const void *oob) +{ + int tries, ret; + + for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = (void *)oob, + .datbuf = (void *)data, + }; + + if (data) + ops.len = bmtd.pg_size; + if (oob) + ops.ooblen = mtd_oobavail(bmtd.mtd, &ops); + + ret = bmtd._write_oob(bmtd.mtd, addr, &ops); + if (!ret) + return true; + } + + nlog_err(ni, "Page write failed at address 0x%08llx\n", addr); + + return false; +} + +/* + * nmbm_erase_phys_block - Erase a block with retry + * @ni: NMBM instance structure + * @addr: Linear address + * + * Erase a block for at most NMBM_TRY_COUNT times. + */ +static bool nmbm_erase_phys_block(struct nmbm_instance *ni, uint64_t addr) +{ + int tries, ret; + + for (tries = 0; tries < NMBM_TRY_COUNT; tries++) { + struct erase_info ei = { + .addr = addr, + .len = bmtd.mtd->erasesize, + }; + + ret = bmtd._erase(bmtd.mtd, &ei); + if (!ret) + return true; + } + + nlog_err(ni, "Block erasure failed at address 0x%08llx\n", addr); + + return false; +} + +/* + * nmbm_check_bad_phys_block - Check whether a block is marked bad in OOB + * @ni: NMBM instance structure + * @ba: block address + */ +static bool nmbm_check_bad_phys_block(struct nmbm_instance *ni, uint32_t ba) +{ + uint64_t addr = ba2addr(ni, ba); + + return bmtd._block_isbad(bmtd.mtd, addr); +} + +/* + * nmbm_mark_phys_bad_block - Mark a block bad + * @ni: NMBM instance structure + * @addr: Linear address + */ +static int nmbm_mark_phys_bad_block(struct nmbm_instance *ni, uint32_t ba) +{ + uint64_t addr = ba2addr(ni, ba); + + nlog_info(ni, "Block %u [0x%08llx] will be marked bad\n", ba, addr); + + return bmtd._block_markbad(bmtd.mtd, addr); +} + +/*****************************************************************************/ +/* NMBM related functions */ +/*****************************************************************************/ + +/* + * nmbm_check_header - Check whether a NMBM structure is valid + * @data: pointer to a NMBM structure with a NMBM header at beginning + * @size: Size of the buffer pointed by @header + * + * The size of the NMBM structure may be larger than NMBM header, + * e.g. block mapping table and block state table. + */ +static bool nmbm_check_header(const void *data, uint32_t size) +{ + const struct nmbm_header *header = data; + struct nmbm_header nhdr; + uint32_t new_checksum; + + /* + * Make sure expected structure size is equal or smaller than + * buffer size. + */ + if (header->size > size) + return false; + + memcpy(&nhdr, data, sizeof(nhdr)); + + nhdr.checksum = 0; + new_checksum = nmbm_crc32(0, &nhdr, sizeof(nhdr)); + if (header->size > sizeof(nhdr)) + new_checksum = nmbm_crc32(new_checksum, + (const uint8_t *)data + sizeof(nhdr), + header->size - sizeof(nhdr)); + + if (header->checksum != new_checksum) + return false; + + return true; +} + +/* + * nmbm_update_checksum - Update checksum of a NMBM structure + * @header: pointer to a NMBM structure with a NMBM header at beginning + * + * The size of the NMBM structure must be specified by @header->size + */ +static void nmbm_update_checksum(struct nmbm_header *header) +{ + header->checksum = 0; + header->checksum = nmbm_crc32(0, header, header->size); +} + +/* + * nmbm_get_spare_block_count - Calculate number of blocks should be reserved + * @block_count: number of blocks of data + * + * Calculate number of blocks should be reserved for data + */ +static uint32_t nmbm_get_spare_block_count(uint32_t block_count) +{ + uint32_t val; + + val = (block_count + NMBM_SPARE_BLOCK_DIV / 2) / NMBM_SPARE_BLOCK_DIV; + val *= NMBM_SPARE_BLOCK_MULTI; + + if (val < NMBM_SPARE_BLOCK_MIN) + val = NMBM_SPARE_BLOCK_MIN; + + return val; +} + +/* + * nmbm_get_block_state_raw - Get state of a block from raw block state table + * @block_state: pointer to raw block state table (bitmap) + * @ba: block address + */ +static uint32_t nmbm_get_block_state_raw(u32 *block_state, + uint32_t ba) +{ + uint32_t unit, shift; + + unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT; + shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK; + + return (block_state[unit] >> shift) & BLOCK_ST_MASK; +} + +/* + * nmbm_get_block_state - Get state of a block from block state table + * @ni: NMBM instance structure + * @ba: block address + */ +static uint32_t nmbm_get_block_state(struct nmbm_instance *ni, uint32_t ba) +{ + return nmbm_get_block_state_raw(ni->block_state, ba); +} + +/* + * nmbm_set_block_state - Set state of a block to block state table + * @ni: NMBM instance structure + * @ba: block address + * @state: block state + * + * Set state of a block. If the block state changed, ni->block_state_changed + * will be increased. + */ +static bool nmbm_set_block_state(struct nmbm_instance *ni, uint32_t ba, + uint32_t state) +{ + uint32_t unit, shift, orig; + u32 uv; + + unit = ba / NMBM_BITMAP_BLOCKS_PER_UNIT; + shift = (ba % NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_BITS_PER_BLOCK; + + orig = (ni->block_state[unit] >> shift) & BLOCK_ST_MASK; + state &= BLOCK_ST_MASK; + + uv = ni->block_state[unit] & (~(BLOCK_ST_MASK << shift)); + uv |= state << shift; + ni->block_state[unit] = uv; + + if (orig != state) { + ni->block_state_changed++; + return true; + } + + return false; +} + +/* + * nmbm_block_walk_asc - Skip specified number of good blocks, ascending addr. + * @ni: NMBM instance structure + * @ba: start physical block address + * @nba: return physical block address after walk + * @count: number of good blocks to be skipped + * @limit: highest block address allowed for walking + * + * Start from @ba, skipping any bad blocks, counting @count good blocks, and + * return the next good block address. + * + * If no enough good blocks counted while @limit reached, false will be returned. + * + * If @count == 0, nearest good block address will be returned. + * @limit is not counted in walking. + */ +static bool nmbm_block_walk_asc(struct nmbm_instance *ni, uint32_t ba, + uint32_t *nba, uint32_t count, + uint32_t limit) +{ + int32_t nblock = count; + + if (limit >= ni->block_count) + limit = ni->block_count - 1; + + while (ba < limit) { + if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD) + nblock--; + + if (nblock < 0) { + *nba = ba; + return true; + } + + ba++; + } + + return false; +} + +/* + * nmbm_block_walk_desc - Skip specified number of good blocks, descending addr + * @ni: NMBM instance structure + * @ba: start physical block address + * @nba: return physical block address after walk + * @count: number of good blocks to be skipped + * @limit: lowest block address allowed for walking + * + * Start from @ba, skipping any bad blocks, counting @count good blocks, and + * return the next good block address. + * + * If no enough good blocks counted while @limit reached, false will be returned. + * + * If @count == 0, nearest good block address will be returned. + * @limit is not counted in walking. + */ +static bool nmbm_block_walk_desc(struct nmbm_instance *ni, uint32_t ba, + uint32_t *nba, uint32_t count, uint32_t limit) +{ + int32_t nblock = count; + + if (limit >= ni->block_count) + limit = ni->block_count - 1; + + while (ba > limit) { + if (nmbm_get_block_state(ni, ba) == BLOCK_ST_GOOD) + nblock--; + + if (nblock < 0) { + *nba = ba; + return true; + } + + ba--; + } + + return false; +} + +/* + * nmbm_block_walk - Skip specified number of good blocks from curr. block addr + * @ni: NMBM instance structure + * @ascending: whether to walk ascending + * @ba: start physical block address + * @nba: return physical block address after walk + * @count: number of good blocks to be skipped + * @limit: highest/lowest block address allowed for walking + * + * Start from @ba, skipping any bad blocks, counting @count good blocks, and + * return the next good block address. + * + * If no enough good blocks counted while @limit reached, false will be returned. + * + * If @count == 0, nearest good block address will be returned. + * @limit can be set to negative if no limit required. + * @limit is not counted in walking. + */ +static bool nmbm_block_walk(struct nmbm_instance *ni, bool ascending, + uint32_t ba, uint32_t *nba, int32_t count, + int32_t limit) +{ + if (ascending) + return nmbm_block_walk_asc(ni, ba, nba, count, limit); + + return nmbm_block_walk_desc(ni, ba, nba, count, limit); +} + +/* + * nmbm_scan_badblocks - Scan and record all bad blocks + * @ni: NMBM instance structure + * + * Scan the entire lower NAND chip and record all bad blocks in to block state + * table. + */ +static void nmbm_scan_badblocks(struct nmbm_instance *ni) +{ + uint32_t ba; + + for (ba = 0; ba < ni->block_count; ba++) { + if (nmbm_check_bad_phys_block(ni, ba)) { + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + nlog_info(ni, "Bad block %u [0x%08llx]\n", ba, + ba2addr(ni, ba)); + } + } +} + +/* + * nmbm_build_mapping_table - Build initial block mapping table + * @ni: NMBM instance structure + * + * The initial mapping table will be compatible with the stratage of + * factory production. + */ +static void nmbm_build_mapping_table(struct nmbm_instance *ni) +{ + uint32_t pb, lb; + + for (pb = 0, lb = 0; pb < ni->mgmt_start_ba; pb++) { + if (nmbm_get_block_state(ni, pb) == BLOCK_ST_BAD) + continue; + + /* Always map to the next good block */ + ni->block_mapping[lb++] = pb; + } + + ni->data_block_count = lb; + + /* Unusable/Management blocks */ + for (pb = lb; pb < ni->block_count; pb++) + ni->block_mapping[pb] = -1; +} + +/* + * nmbm_erase_block_and_check - Erase a block and check its usability + * @ni: NMBM instance structure + * @ba: block address to be erased + * + * Erase a block anc check its usability + * + * Return true if the block is usable, false if erasure failure or the block + * has too many bitflips. + */ +static bool nmbm_erase_block_and_check(struct nmbm_instance *ni, uint32_t ba) +{ + uint64_t addr, off; + bool success; + int ret; + + success = nmbm_erase_phys_block(ni, ba2addr(ni, ba)); + if (!success) + return false; + + if (!ni->empty_page_ecc_ok) + return true; + + /* Check every page to make sure there aren't too many bitflips */ + + addr = ba2addr(ni, ba); + + for (off = 0; off < bmtd.blk_size; off += bmtd.pg_size) { + ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL); + if (ret == -EBADMSG) { + /* + * empty_page_ecc_ok means the empty page is + * still protected by ECC. So reading pages with ECC + * enabled and -EBADMSG means there are too many + * bitflips that can't be recovered, and the block + * containing the page should be marked bad. + */ + nlog_err(ni, + "Too many bitflips in empty page at 0x%llx\n", + addr + off); + return false; + } + } + + return true; +} + +/* + * nmbm_erase_range - Erase a range of blocks + * @ni: NMBM instance structure + * @ba: block address where the erasure will start + * @limit: top block address allowed for erasure + * + * Erase blocks within the specific range. Newly-found bad blocks will be + * marked. + * + * @limit is not counted into the allowed erasure address. + */ +static void nmbm_erase_range(struct nmbm_instance *ni, uint32_t ba, + uint32_t limit) +{ + bool success; + + while (ba < limit) { + if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) + goto next_block; + + /* Insurance to detect unexpected bad block marked by user */ + if (nmbm_check_bad_phys_block(ni, ba)) { + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + goto next_block; + } + + success = nmbm_erase_block_and_check(ni, ba); + if (success) + goto next_block; + + nmbm_mark_phys_bad_block(ni, ba); + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + + next_block: + ba++; + } +} + +/* + * nmbm_write_repeated_data - Write critical data to a block with retry + * @ni: NMBM instance structure + * @ba: block address where the data will be written to + * @data: the data to be written + * @size: size of the data + * + * Write data to every page of the block. Success only if all pages within + * this block have been successfully written. + * + * Make sure data size is not bigger than one page. + * + * This function will write and verify every page for at most + * NMBM_TRY_COUNT times. + */ +static bool nmbm_write_repeated_data(struct nmbm_instance *ni, uint32_t ba, + const void *data, uint32_t size) +{ + uint64_t addr, off; + bool success; + int ret; + + if (size > bmtd.pg_size) + return false; + + addr = ba2addr(ni, ba); + + for (off = 0; off < bmtd.blk_size; off += bmtd.pg_size) { + /* Prepare page data. fill 0xff to unused region */ + memcpy(ni->page_cache, data, size); + memset(ni->page_cache + size, 0xff, ni->rawpage_size - size); + + success = nmbm_write_phys_page(ni, addr + off, ni->page_cache, NULL); + if (!success) + return false; + + /* Verify the data just written. ECC error indicates failure */ + ret = nmbm_read_phys_page(ni, addr + off, ni->page_cache, NULL); + if (ret < 0) + return false; + + if (memcmp(ni->page_cache, data, size)) + return false; + } + + return true; +} + +/* + * nmbm_write_signature - Write signature to NAND chip + * @ni: NMBM instance structure + * @limit: top block address allowed for writing + * @signature: the signature to be written + * @signature_ba: the actual block address where signature is written to + * + * Write signature within a specific range, from chip bottom to limit. + * At most one block will be written. + * + * @limit is not counted into the allowed write address. + */ +static bool nmbm_write_signature(struct nmbm_instance *ni, uint32_t limit, + const struct nmbm_signature *signature, + uint32_t *signature_ba) +{ + uint32_t ba = ni->block_count - 1; + bool success; + + while (ba > limit) { + if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) + goto next_block; + + /* Insurance to detect unexpected bad block marked by user */ + if (nmbm_check_bad_phys_block(ni, ba)) { + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + goto next_block; + } + + success = nmbm_erase_block_and_check(ni, ba); + if (!success) + goto skip_bad_block; + + success = nmbm_write_repeated_data(ni, ba, signature, + sizeof(*signature)); + if (success) { + *signature_ba = ba; + return true; + } + + skip_bad_block: + nmbm_mark_phys_bad_block(ni, ba); + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + + next_block: + ba--; + }; + + return false; +} + +/* + * nmbn_read_data - Read data + * @ni: NMBM instance structure + * @addr: linear address where the data will be read from + * @data: the data to be read + * @size: the size of data + * + * Read data range. + * Every page will be tried for at most NMBM_TRY_COUNT times. + * + * Return 0 for success, positive value for corrected bitflip count, + * -EBADMSG for ecc error, other negative values for other errors + */ +static int nmbn_read_data(struct nmbm_instance *ni, uint64_t addr, void *data, + uint32_t size) +{ + uint64_t off = addr; + uint8_t *ptr = data; + uint32_t sizeremain = size, chunksize, leading; + int ret; + + while (sizeremain) { + leading = off & (bmtd.pg_size - 1); + chunksize = bmtd.pg_size - leading; + if (chunksize > sizeremain) + chunksize = sizeremain; + + if (chunksize == bmtd.pg_size) { + ret = nmbm_read_phys_page(ni, off - leading, ptr, NULL); + if (ret < 0) + return ret; + } else { + ret = nmbm_read_phys_page(ni, off - leading, + ni->page_cache, NULL); + if (ret < 0) + return ret; + + memcpy(ptr, ni->page_cache + leading, chunksize); + } + + off += chunksize; + ptr += chunksize; + sizeremain -= chunksize; + } + + return 0; +} + +/* + * nmbn_write_verify_data - Write data with validation + * @ni: NMBM instance structure + * @addr: linear address where the data will be written to + * @data: the data to be written + * @size: the size of data + * + * Write data and verify. + * Every page will be tried for at most NMBM_TRY_COUNT times. + */ +static bool nmbn_write_verify_data(struct nmbm_instance *ni, uint64_t addr, + const void *data, uint32_t size) +{ + uint64_t off = addr; + const uint8_t *ptr = data; + uint32_t sizeremain = size, chunksize, leading; + bool success; + int ret; + + while (sizeremain) { + leading = off & (bmtd.pg_size - 1); + chunksize = bmtd.pg_size - leading; + if (chunksize > sizeremain) + chunksize = sizeremain; + + /* Prepare page data. fill 0xff to unused region */ + memset(ni->page_cache, 0xff, ni->rawpage_size); + memcpy(ni->page_cache + leading, ptr, chunksize); + + success = nmbm_write_phys_page(ni, off - leading, + ni->page_cache, NULL); + if (!success) + return false; + + /* Verify the data just written. ECC error indicates failure */ + ret = nmbm_read_phys_page(ni, off - leading, ni->page_cache, NULL); + if (ret < 0) + return false; + + if (memcmp(ni->page_cache + leading, ptr, chunksize)) + return false; + + off += chunksize; + ptr += chunksize; + sizeremain -= chunksize; + } + + return true; +} + +/* + * nmbm_write_mgmt_range - Write management data into NAND within a range + * @ni: NMBM instance structure + * @addr: preferred start block address for writing + * @limit: highest block address allowed for writing + * @data: the data to be written + * @size: the size of data + * @actual_start_ba: actual start block address of data + * @actual_end_ba: block address after the end of data + * + * @limit is not counted into the allowed write address. + */ +static bool nmbm_write_mgmt_range(struct nmbm_instance *ni, uint32_t ba, + uint32_t limit, const void *data, + uint32_t size, uint32_t *actual_start_ba, + uint32_t *actual_end_ba) +{ + const uint8_t *ptr = data; + uint32_t sizeremain = size, chunksize; + bool success; + + while (sizeremain && ba < limit) { + chunksize = sizeremain; + if (chunksize > bmtd.blk_size) + chunksize = bmtd.blk_size; + + if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) + goto next_block; + + /* Insurance to detect unexpected bad block marked by user */ + if (nmbm_check_bad_phys_block(ni, ba)) { + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + goto next_block; + } + + success = nmbm_erase_block_and_check(ni, ba); + if (!success) + goto skip_bad_block; + + success = nmbn_write_verify_data(ni, ba2addr(ni, ba), ptr, + chunksize); + if (!success) + goto skip_bad_block; + + if (sizeremain == size) + *actual_start_ba = ba; + + ptr += chunksize; + sizeremain -= chunksize; + + goto next_block; + + skip_bad_block: + nmbm_mark_phys_bad_block(ni, ba); + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + + next_block: + ba++; + } + + if (sizeremain) + return false; + + *actual_end_ba = ba; + + return true; +} + +/* + * nmbm_generate_info_table_cache - Generate info table cache data + * @ni: NMBM instance structure + * + * Generate info table cache data to be written into flash. + */ +static bool nmbm_generate_info_table_cache(struct nmbm_instance *ni) +{ + bool changed = false; + + memset(ni->info_table_cache, 0xff, ni->info_table_size); + + memcpy(ni->info_table_cache + ni->info_table.state_table_off, + ni->block_state, ni->state_table_size); + + memcpy(ni->info_table_cache + ni->info_table.mapping_table_off, + ni->block_mapping, ni->mapping_table_size); + + ni->info_table.header.magic = NMBM_MAGIC_INFO_TABLE; + ni->info_table.header.version = NMBM_VER; + ni->info_table.header.size = ni->info_table_size; + + if (ni->block_state_changed || ni->block_mapping_changed) { + ni->info_table.write_count++; + changed = true; + } + + memcpy(ni->info_table_cache, &ni->info_table, sizeof(ni->info_table)); + + nmbm_update_checksum((struct nmbm_header *)ni->info_table_cache); + + return changed; +} + +/* + * nmbm_write_info_table - Write info table into NAND within a range + * @ni: NMBM instance structure + * @ba: preferred start block address for writing + * @limit: highest block address allowed for writing + * @actual_start_ba: actual start block address of info table + * @actual_end_ba: block address after the end of info table + * + * @limit is counted into the allowed write address. + */ +static bool nmbm_write_info_table(struct nmbm_instance *ni, uint32_t ba, + uint32_t limit, uint32_t *actual_start_ba, + uint32_t *actual_end_ba) +{ + return nmbm_write_mgmt_range(ni, ba, limit, ni->info_table_cache, + ni->info_table_size, actual_start_ba, + actual_end_ba); +} + +/* + * nmbm_mark_tables_clean - Mark info table `clean' + * @ni: NMBM instance structure + */ +static void nmbm_mark_tables_clean(struct nmbm_instance *ni) +{ + ni->block_state_changed = 0; + ni->block_mapping_changed = 0; +} + +/* + * nmbm_try_reserve_blocks - Reserve blocks with compromisation + * @ni: NMBM instance structure + * @ba: start physical block address + * @nba: return physical block address after reservation + * @count: number of good blocks to be skipped + * @min_count: minimum number of good blocks to be skipped + * @limit: highest/lowest block address allowed for walking + * + * Reserve specific blocks. If failed, try to reserve as many as possible. + */ +static bool nmbm_try_reserve_blocks(struct nmbm_instance *ni, uint32_t ba, + uint32_t *nba, uint32_t count, + int32_t min_count, int32_t limit) +{ + int32_t nblocks = count; + bool success; + + while (nblocks >= min_count) { + success = nmbm_block_walk(ni, true, ba, nba, nblocks, limit); + if (success) + return true; + + nblocks--; + } + + return false; +} + +/* + * nmbm_rebuild_info_table - Build main & backup info table from scratch + * @ni: NMBM instance structure + * @allow_no_gap: allow no spare blocks between two tables + */ +static bool nmbm_rebuild_info_table(struct nmbm_instance *ni) +{ + uint32_t table_start_ba, table_end_ba, next_start_ba; + uint32_t main_table_end_ba; + bool success; + + /* Set initial value */ + ni->main_table_ba = 0; + ni->backup_table_ba = 0; + ni->mapping_blocks_ba = ni->mapping_blocks_top_ba; + + /* Write main table */ + success = nmbm_write_info_table(ni, ni->mgmt_start_ba, + ni->mapping_blocks_top_ba, + &table_start_ba, &table_end_ba); + if (!success) { + /* Failed to write main table, data will be lost */ + nlog_err(ni, "Unable to write at least one info table!\n"); + nlog_err(ni, "Please save your data before power off!\n"); + ni->protected = 1; + return false; + } + + /* Main info table is successfully written, record its offset */ + ni->main_table_ba = table_start_ba; + main_table_end_ba = table_end_ba; + + /* Adjust mapping_blocks_ba */ + ni->mapping_blocks_ba = table_end_ba; + + nmbm_mark_tables_clean(ni); + + nlog_table_creation(ni, true, table_start_ba, table_end_ba); + + /* Reserve spare blocks for main info table. */ + success = nmbm_try_reserve_blocks(ni, table_end_ba, + &next_start_ba, + ni->info_table_spare_blocks, 0, + ni->mapping_blocks_top_ba - + size2blk(ni, ni->info_table_size)); + if (!success) { + /* There is no spare block. */ + nlog_debug(ni, "No room for backup info table\n"); + return true; + } + + /* Write backup info table. */ + success = nmbm_write_info_table(ni, next_start_ba, + ni->mapping_blocks_top_ba, + &table_start_ba, &table_end_ba); + if (!success) { + /* There is no enough blocks for backup table. */ + nlog_debug(ni, "No room for backup info table\n"); + return true; + } + + /* Backup table is successfully written, record its offset */ + ni->backup_table_ba = table_start_ba; + + /* Adjust mapping_blocks_off */ + ni->mapping_blocks_ba = table_end_ba; + + /* Erase spare blocks of main table to clean possible interference data */ + nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba); + + nlog_table_creation(ni, false, table_start_ba, table_end_ba); + + return true; +} + +/* + * nmbm_rescue_single_info_table - Rescue when there is only one info table + * @ni: NMBM instance structure + * + * This function is called when there is only one info table exists. + * This function may fail if we can't write new info table + */ +static bool nmbm_rescue_single_info_table(struct nmbm_instance *ni) +{ + uint32_t table_start_ba, table_end_ba, write_ba; + bool success; + + /* Try to write new info table in front of existing table */ + success = nmbm_write_info_table(ni, ni->mgmt_start_ba, + ni->main_table_ba, + &table_start_ba, + &table_end_ba); + if (success) { + /* + * New table becomes the main table, existing table becomes + * the backup table. + */ + ni->backup_table_ba = ni->main_table_ba; + ni->main_table_ba = table_start_ba; + + nmbm_mark_tables_clean(ni); + + /* Erase spare blocks of main table to clean possible interference data */ + nmbm_erase_range(ni, table_end_ba, ni->backup_table_ba); + + nlog_table_creation(ni, true, table_start_ba, table_end_ba); + + return true; + } + + /* Try to reserve spare blocks for existing table */ + success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba, + ni->info_table_spare_blocks, 0, + ni->mapping_blocks_top_ba - + size2blk(ni, ni->info_table_size)); + if (!success) { + nlog_warn(ni, "Failed to rescue single info table\n"); + return false; + } + + /* Try to write new info table next to the existing table */ + while (write_ba >= ni->mapping_blocks_ba) { + success = nmbm_write_info_table(ni, write_ba, + ni->mapping_blocks_top_ba, + &table_start_ba, + &table_end_ba); + if (success) + break; + + write_ba--; + } + + if (success) { + /* Erase spare blocks of main table to clean possible interference data */ + nmbm_erase_range(ni, ni->mapping_blocks_ba, table_start_ba); + + /* New table becomes the backup table */ + ni->backup_table_ba = table_start_ba; + ni->mapping_blocks_ba = table_end_ba; + + nmbm_mark_tables_clean(ni); + + nlog_table_creation(ni, false, table_start_ba, table_end_ba); + + return true; + } + + nlog_warn(ni, "Failed to rescue single info table\n"); + return false; +} + +/* + * nmbm_update_single_info_table - Update specific one info table + * @ni: NMBM instance structure + */ +static bool nmbm_update_single_info_table(struct nmbm_instance *ni, + bool update_main_table) +{ + uint32_t write_start_ba, write_limit, table_start_ba, table_end_ba; + bool success; + + /* Determine the write range */ + if (update_main_table) { + write_start_ba = ni->main_table_ba; + write_limit = ni->backup_table_ba; + } else { + write_start_ba = ni->backup_table_ba; + write_limit = ni->mapping_blocks_top_ba; + } + + success = nmbm_write_info_table(ni, write_start_ba, write_limit, + &table_start_ba, &table_end_ba); + if (success) { + if (update_main_table) { + ni->main_table_ba = table_start_ba; + } else { + ni->backup_table_ba = table_start_ba; + ni->mapping_blocks_ba = table_end_ba; + } + + nmbm_mark_tables_clean(ni); + + nlog_table_update(ni, update_main_table, table_start_ba, + table_end_ba); + + return true; + } + + if (update_main_table) { + /* + * If failed to update main table, make backup table the new + * main table, and call nmbm_rescue_single_info_table() + */ + nlog_warn(ni, "Unable to update %s info table\n", + update_main_table ? "Main" : "Backup"); + + ni->main_table_ba = ni->backup_table_ba; + ni->backup_table_ba = 0; + return nmbm_rescue_single_info_table(ni); + } + + /* Only one table left */ + ni->mapping_blocks_ba = ni->backup_table_ba; + ni->backup_table_ba = 0; + + return false; +} + +/* + * nmbm_rescue_main_info_table - Rescue when failed to write main info table + * @ni: NMBM instance structure + * + * This function is called when main info table failed to be written, and + * backup info table exists. + */ +static bool nmbm_rescue_main_info_table(struct nmbm_instance *ni) +{ + uint32_t tmp_table_start_ba, tmp_table_end_ba, main_table_start_ba; + uint32_t main_table_end_ba, write_ba; + uint32_t info_table_erasesize = size2blk(ni, ni->info_table_size); + bool success; + + /* Try to reserve spare blocks for existing backup info table */ + success = nmbm_try_reserve_blocks(ni, ni->mapping_blocks_ba, &write_ba, + ni->info_table_spare_blocks, 0, + ni->mapping_blocks_top_ba - + info_table_erasesize); + if (!success) { + /* There is no spare block. Backup info table becomes the main table. */ + nlog_err(ni, "No room for temporary info table\n"); + ni->main_table_ba = ni->backup_table_ba; + ni->backup_table_ba = 0; + return true; + } + + /* Try to write temporary info table into spare unmapped blocks */ + while (write_ba >= ni->mapping_blocks_ba) { + success = nmbm_write_info_table(ni, write_ba, + ni->mapping_blocks_top_ba, + &tmp_table_start_ba, + &tmp_table_end_ba); + if (success) + break; + + write_ba--; + } + + if (!success) { + /* Backup info table becomes the main table */ + nlog_err(ni, "Failed to update main info table\n"); + ni->main_table_ba = ni->backup_table_ba; + ni->backup_table_ba = 0; + return true; + } + + /* Adjust mapping_blocks_off */ + ni->mapping_blocks_ba = tmp_table_end_ba; + + /* + * Now write main info table at the beginning of management area. + * This operation will generally destroy the original backup info + * table. + */ + success = nmbm_write_info_table(ni, ni->mgmt_start_ba, + tmp_table_start_ba, + &main_table_start_ba, + &main_table_end_ba); + if (!success) { + /* Temporary info table becomes the main table */ + ni->main_table_ba = tmp_table_start_ba; + ni->backup_table_ba = 0; + + nmbm_mark_tables_clean(ni); + + nlog_err(ni, "Failed to update main info table\n"); + + return true; + } + + /* Main info table has been successfully written, record its offset */ + ni->main_table_ba = main_table_start_ba; + + nmbm_mark_tables_clean(ni); + + nlog_table_creation(ni, true, main_table_start_ba, main_table_end_ba); + + /* + * Temporary info table becomes the new backup info table if it's + * not overwritten. + */ + if (main_table_end_ba <= tmp_table_start_ba) { + ni->backup_table_ba = tmp_table_start_ba; + + nlog_table_creation(ni, false, tmp_table_start_ba, + tmp_table_end_ba); + + return true; + } + + /* Adjust mapping_blocks_off */ + ni->mapping_blocks_ba = main_table_end_ba; + + /* Try to reserve spare blocks for new main info table */ + success = nmbm_try_reserve_blocks(ni, main_table_end_ba, &write_ba, + ni->info_table_spare_blocks, 0, + ni->mapping_blocks_top_ba - + info_table_erasesize); + if (!success) { + /* There is no spare block. Only main table exists. */ + nlog_err(ni, "No room for backup info table\n"); + ni->backup_table_ba = 0; + return true; + } + + /* Write new backup info table. */ + while (write_ba >= main_table_end_ba) { + success = nmbm_write_info_table(ni, write_ba, + ni->mapping_blocks_top_ba, + &tmp_table_start_ba, + &tmp_table_end_ba); + if (success) + break; + + write_ba--; + } + + if (!success) { + nlog_err(ni, "No room for backup info table\n"); + ni->backup_table_ba = 0; + return true; + } + + /* Backup info table has been successfully written, record its offset */ + ni->backup_table_ba = tmp_table_start_ba; + + /* Adjust mapping_blocks_off */ + ni->mapping_blocks_ba = tmp_table_end_ba; + + /* Erase spare blocks of main table to clean possible interference data */ + nmbm_erase_range(ni, main_table_end_ba, ni->backup_table_ba); + + nlog_table_creation(ni, false, tmp_table_start_ba, tmp_table_end_ba); + + return true; +} + +/* + * nmbm_update_info_table_once - Update info table once + * @ni: NMBM instance structure + * @force: force update + * + * Update both main and backup info table. Return true if at least one info + * table has been successfully written. + * This function only try to update info table once regard less of the result. + */ +static bool nmbm_update_info_table_once(struct nmbm_instance *ni, bool force) +{ + uint32_t table_start_ba, table_end_ba; + uint32_t main_table_limit; + bool success; + + /* Do nothing if there is no change */ + if (!nmbm_generate_info_table_cache(ni) && !force) + return true; + + /* Check whether both two tables exist */ + if (!ni->backup_table_ba) { + main_table_limit = ni->mapping_blocks_top_ba; + goto write_main_table; + } + + /* + * Write backup info table in its current range. + * Note that limit is set to mapping_blocks_top_off to provide as many + * spare blocks as possible for the backup table. If at last + * unmapped blocks are used by backup table, mapping_blocks_off will + * be adjusted. + */ + success = nmbm_write_info_table(ni, ni->backup_table_ba, + ni->mapping_blocks_top_ba, + &table_start_ba, &table_end_ba); + if (!success) { + /* + * There is nothing to do if failed to write backup table. + * Write the main table now. + */ + nlog_err(ni, "No room for backup table\n"); + ni->mapping_blocks_ba = ni->backup_table_ba; + ni->backup_table_ba = 0; + main_table_limit = ni->mapping_blocks_top_ba; + goto write_main_table; + } + + /* Backup table is successfully written, record its offset */ + ni->backup_table_ba = table_start_ba; + + /* Adjust mapping_blocks_off */ + ni->mapping_blocks_ba = table_end_ba; + + nmbm_mark_tables_clean(ni); + + /* The normal limit of main table */ + main_table_limit = ni->backup_table_ba; + + nlog_table_update(ni, false, table_start_ba, table_end_ba); + +write_main_table: + if (!ni->main_table_ba) + goto rebuild_tables; + + /* Write main info table in its current range */ + success = nmbm_write_info_table(ni, ni->main_table_ba, + main_table_limit, &table_start_ba, + &table_end_ba); + if (!success) { + /* If failed to write main table, go rescue procedure */ + if (!ni->backup_table_ba) + goto rebuild_tables; + + return nmbm_rescue_main_info_table(ni); + } + + /* Main info table is successfully written, record its offset */ + ni->main_table_ba = table_start_ba; + + /* Adjust mapping_blocks_off */ + if (!ni->backup_table_ba) + ni->mapping_blocks_ba = table_end_ba; + + nmbm_mark_tables_clean(ni); + + nlog_table_update(ni, true, table_start_ba, table_end_ba); + + return true; + +rebuild_tables: + return nmbm_rebuild_info_table(ni); +} + +/* + * nmbm_update_info_table - Update info table + * @ni: NMBM instance structure + * + * Update both main and backup info table. Return true if at least one table + * has been successfully written. + * This function will try to update info table repeatedly until no new bad + * block found during updating. + */ +static bool nmbm_update_info_table(struct nmbm_instance *ni) +{ + bool success; + + if (ni->protected) + return true; + + while (ni->block_state_changed || ni->block_mapping_changed) { + success = nmbm_update_info_table_once(ni, false); + if (!success) { + nlog_err(ni, "Failed to update info table\n"); + return false; + } + } + + return true; +} + +/* + * nmbm_map_block - Map a bad block to a unused spare block + * @ni: NMBM instance structure + * @lb: logic block addr to map + */ +static bool nmbm_map_block(struct nmbm_instance *ni, uint32_t lb) +{ + uint32_t pb; + bool success; + + if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) { + nlog_warn(ni, "No spare unmapped blocks.\n"); + return false; + } + + success = nmbm_block_walk(ni, false, ni->mapping_blocks_top_ba, &pb, 0, + ni->mapping_blocks_ba); + if (!success) { + nlog_warn(ni, "No spare unmapped blocks.\n"); + nmbm_update_info_table(ni); + ni->mapping_blocks_top_ba = ni->mapping_blocks_ba; + return false; + } + + ni->block_mapping[lb] = pb; + ni->mapping_blocks_top_ba--; + ni->block_mapping_changed++; + + nlog_info(ni, "Logic block %u mapped to physical block %u\n", lb, pb); + + return true; +} + +/* + * nmbm_create_info_table - Create info table(s) + * @ni: NMBM instance structure + * + * This function assumes that the chip has no existing info table(s) + */ +static bool nmbm_create_info_table(struct nmbm_instance *ni) +{ + uint32_t lb; + bool success; + + /* Set initial mapping_blocks_top_off */ + success = nmbm_block_walk(ni, false, ni->signature_ba, + &ni->mapping_blocks_top_ba, 1, + ni->mgmt_start_ba); + if (!success) { + nlog_err(ni, "No room for spare blocks\n"); + return false; + } + + /* Generate info table cache */ + nmbm_generate_info_table_cache(ni); + + /* Write info table */ + success = nmbm_rebuild_info_table(ni); + if (!success) { + nlog_err(ni, "Failed to build info tables\n"); + return false; + } + + /* Remap bad block(s) at end of data area */ + for (lb = ni->data_block_count; lb < ni->mgmt_start_ba; lb++) { + success = nmbm_map_block(ni, lb); + if (!success) + break; + + ni->data_block_count++; + } + + /* If state table and/or mapping table changed, update info table. */ + success = nmbm_update_info_table(ni); + if (!success) + return false; + + return true; +} + +/* + * nmbm_create_new - Create NMBM on a new chip + * @ni: NMBM instance structure + */ +static bool nmbm_create_new(struct nmbm_instance *ni) +{ + bool success; + + /* Determine the boundary of management blocks */ + ni->mgmt_start_ba = ni->block_count * (NMBM_MGMT_DIV - ni->max_ratio) / NMBM_MGMT_DIV; + + if (ni->max_reserved_blocks && ni->block_count - ni->mgmt_start_ba > ni->max_reserved_blocks) + ni->mgmt_start_ba = ni->block_count - ni->max_reserved_blocks; + + nlog_info(ni, "NMBM management region starts at block %u [0x%08llx]\n", + ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba)); + + /* Fill block state table & mapping table */ + nmbm_scan_badblocks(ni); + nmbm_build_mapping_table(ni); + + /* Write signature */ + ni->signature.header.magic = NMBM_MAGIC_SIGNATURE; + ni->signature.header.version = NMBM_VER; + ni->signature.header.size = sizeof(ni->signature); + ni->signature.nand_size = bmtd.total_blks << bmtd.blk_shift; + ni->signature.block_size = bmtd.blk_size; + ni->signature.page_size = bmtd.pg_size; + ni->signature.spare_size = bmtd.mtd->oobsize; + ni->signature.mgmt_start_pb = ni->mgmt_start_ba; + ni->signature.max_try_count = NMBM_TRY_COUNT; + nmbm_update_checksum(&ni->signature.header); + + success = nmbm_write_signature(ni, ni->mgmt_start_ba, + &ni->signature, &ni->signature_ba); + if (!success) { + nlog_err(ni, "Failed to write signature to a proper offset\n"); + return false; + } + + nlog_info(ni, "Signature has been written to block %u [0x%08llx]\n", + ni->signature_ba, ba2addr(ni, ni->signature_ba)); + + /* Write info table(s) */ + success = nmbm_create_info_table(ni); + if (success) { + nlog_info(ni, "NMBM has been successfully created\n"); + return true; + } + + return false; +} + +/* + * nmbm_check_info_table_header - Check if a info table header is valid + * @ni: NMBM instance structure + * @data: pointer to the info table header + */ +static bool nmbm_check_info_table_header(struct nmbm_instance *ni, void *data) +{ + struct nmbm_info_table_header *ifthdr = data; + + if (ifthdr->header.magic != NMBM_MAGIC_INFO_TABLE) + return false; + + if (ifthdr->header.size != ni->info_table_size) + return false; + + if (ifthdr->mapping_table_off - ifthdr->state_table_off < ni->state_table_size) + return false; + + if (ni->info_table_size - ifthdr->mapping_table_off < ni->mapping_table_size) + return false; + + return true; +} + +/* + * nmbm_check_info_table - Check if a whole info table is valid + * @ni: NMBM instance structure + * @start_ba: start block address of this table + * @end_ba: end block address of this table + * @data: pointer to the info table header + * @mapping_blocks_top_ba: return the block address of top remapped block + */ +static bool nmbm_check_info_table(struct nmbm_instance *ni, uint32_t start_ba, + uint32_t end_ba, void *data, + uint32_t *mapping_blocks_top_ba) +{ + struct nmbm_info_table_header *ifthdr = data; + int32_t *block_mapping = (int32_t *)((uintptr_t)data + ifthdr->mapping_table_off); + u32 *block_state = (u32 *)((uintptr_t)data + ifthdr->state_table_off); + uint32_t minimum_mapping_pb = ni->signature_ba; + uint32_t ba; + + for (ba = 0; ba < ni->data_block_count; ba++) { + if ((block_mapping[ba] >= ni->data_block_count && block_mapping[ba] < end_ba) || + block_mapping[ba] == ni->signature_ba) + return false; + + if (block_mapping[ba] >= end_ba && block_mapping[ba] < minimum_mapping_pb) + minimum_mapping_pb = block_mapping[ba]; + } + + for (ba = start_ba; ba < end_ba; ba++) { + if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) + continue; + + if (nmbm_get_block_state_raw(block_state, ba) != BLOCK_ST_GOOD) + return false; + } + + *mapping_blocks_top_ba = minimum_mapping_pb - 1; + + return true; +} + +/* + * nmbm_try_load_info_table - Try to load info table from a address + * @ni: NMBM instance structure + * @ba: start block address of the info table + * @eba: return the block address after end of the table + * @write_count: return the write count of this table + * @mapping_blocks_top_ba: return the block address of top remapped block + * @table_loaded: used to record whether ni->info_table has valid data + */ +static bool nmbm_try_load_info_table(struct nmbm_instance *ni, uint32_t ba, + uint32_t *eba, uint32_t *write_count, + uint32_t *mapping_blocks_top_ba, + bool table_loaded) +{ + struct nmbm_info_table_header *ifthdr = (void *)ni->info_table_cache; + uint8_t *off = ni->info_table_cache; + uint32_t limit = ba + size2blk(ni, ni->info_table_size); + uint32_t start_ba = 0, chunksize, sizeremain = ni->info_table_size; + bool success, checkhdr = true; + int ret; + + while (sizeremain && ba < limit) { + if (nmbm_get_block_state(ni, ba) != BLOCK_ST_GOOD) + goto next_block; + + if (nmbm_check_bad_phys_block(ni, ba)) { + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + goto next_block; + } + + chunksize = sizeremain; + if (chunksize > bmtd.blk_size) + chunksize = bmtd.blk_size; + + /* Assume block with ECC error has no info table data */ + ret = nmbn_read_data(ni, ba2addr(ni, ba), off, chunksize); + if (ret < 0) + goto skip_bad_block; + else if (ret > 0) + return false; + + if (checkhdr) { + success = nmbm_check_info_table_header(ni, off); + if (!success) + return false; + + start_ba = ba; + checkhdr = false; + } + + off += chunksize; + sizeremain -= chunksize; + + goto next_block; + + skip_bad_block: + /* Only mark bad in memory */ + nmbm_set_block_state(ni, ba, BLOCK_ST_BAD); + + next_block: + ba++; + } + + if (sizeremain) + return false; + + success = nmbm_check_header(ni->info_table_cache, ni->info_table_size); + if (!success) + return false; + + *eba = ba; + *write_count = ifthdr->write_count; + + success = nmbm_check_info_table(ni, start_ba, ba, ni->info_table_cache, + mapping_blocks_top_ba); + if (!success) + return false; + + if (!table_loaded || ifthdr->write_count > ni->info_table.write_count) { + memcpy(&ni->info_table, ifthdr, sizeof(ni->info_table)); + memcpy(ni->block_state, + (uint8_t *)ifthdr + ifthdr->state_table_off, + ni->state_table_size); + memcpy(ni->block_mapping, + (uint8_t *)ifthdr + ifthdr->mapping_table_off, + ni->mapping_table_size); + ni->info_table.write_count = ifthdr->write_count; + } + + return true; +} + +/* + * nmbm_search_info_table - Search info table from specific address + * @ni: NMBM instance structure + * @ba: start block address to search + * @limit: highest block address allowed for searching + * @table_start_ba: return the start block address of this table + * @table_end_ba: return the block address after end of this table + * @write_count: return the write count of this table + * @mapping_blocks_top_ba: return the block address of top remapped block + * @table_loaded: used to record whether ni->info_table has valid data + */ +static bool nmbm_search_info_table(struct nmbm_instance *ni, uint32_t ba, + uint32_t limit, uint32_t *table_start_ba, + uint32_t *table_end_ba, + uint32_t *write_count, + uint32_t *mapping_blocks_top_ba, + bool table_loaded) +{ + bool success; + + while (ba < limit - size2blk(ni, ni->info_table_size)) { + success = nmbm_try_load_info_table(ni, ba, table_end_ba, + write_count, + mapping_blocks_top_ba, + table_loaded); + if (success) { + *table_start_ba = ba; + return true; + } + + ba++; + } + + return false; +} + +/* + * nmbm_load_info_table - Load info table(s) from a chip + * @ni: NMBM instance structure + * @ba: start block address to search info table + * @limit: highest block address allowed for searching + */ +static bool nmbm_load_info_table(struct nmbm_instance *ni, uint32_t ba, + uint32_t limit) +{ + uint32_t main_table_end_ba, backup_table_end_ba, table_end_ba; + uint32_t main_mapping_blocks_top_ba, backup_mapping_blocks_top_ba; + uint32_t main_table_write_count, backup_table_write_count; + uint32_t i; + bool success; + + /* Set initial value */ + ni->main_table_ba = 0; + ni->backup_table_ba = 0; + ni->info_table.write_count = 0; + ni->mapping_blocks_top_ba = ni->signature_ba - 1; + ni->data_block_count = ni->signature.mgmt_start_pb; + + /* Find first info table */ + success = nmbm_search_info_table(ni, ba, limit, &ni->main_table_ba, + &main_table_end_ba, &main_table_write_count, + &main_mapping_blocks_top_ba, false); + if (!success) { + nlog_warn(ni, "No valid info table found\n"); + return false; + } + + table_end_ba = main_table_end_ba; + + nlog_table_found(ni, true, main_table_write_count, ni->main_table_ba, + main_table_end_ba); + + /* Find second info table */ + success = nmbm_search_info_table(ni, main_table_end_ba, limit, + &ni->backup_table_ba, &backup_table_end_ba, + &backup_table_write_count, &backup_mapping_blocks_top_ba, true); + if (!success) { + nlog_warn(ni, "Second info table not found\n"); + } else { + table_end_ba = backup_table_end_ba; + + nlog_table_found(ni, false, backup_table_write_count, + ni->backup_table_ba, backup_table_end_ba); + } + + /* Pick mapping_blocks_top_ba */ + if (!ni->backup_table_ba) { + ni->mapping_blocks_top_ba= main_mapping_blocks_top_ba; + } else { + if (main_table_write_count >= backup_table_write_count) + ni->mapping_blocks_top_ba = main_mapping_blocks_top_ba; + else + ni->mapping_blocks_top_ba = backup_mapping_blocks_top_ba; + } + + /* Set final mapping_blocks_ba */ + ni->mapping_blocks_ba = table_end_ba; + + /* Set final data_block_count */ + for (i = ni->signature.mgmt_start_pb; i > 0; i--) { + if (ni->block_mapping[i - 1] >= 0) { + ni->data_block_count = i; + break; + } + } + + /* Regenerate the info table cache from the final selected info table */ + nmbm_generate_info_table_cache(ni); + + /* + * If only one table exists, try to write another table. + * If two tables have different write count, try to update info table + */ + if (!ni->backup_table_ba) { + success = nmbm_rescue_single_info_table(ni); + } else if (main_table_write_count != backup_table_write_count) { + /* Mark state & mapping tables changed */ + ni->block_state_changed = 1; + ni->block_mapping_changed = 1; + + success = nmbm_update_single_info_table(ni, + main_table_write_count < backup_table_write_count); + } else { + success = true; + } + + /* + * If there is no spare unmapped blocks, or still only one table + * exists, set the chip to read-only + */ + if (ni->mapping_blocks_ba == ni->mapping_blocks_top_ba) { + nlog_warn(ni, "No spare unmapped blocks. Device is now read-only\n"); + ni->protected = 1; + } else if (!success) { + nlog_warn(ni, "Only one info table found. Device is now read-only\n"); + ni->protected = 1; + } + + return true; +} + +/* + * nmbm_load_existing - Load NMBM from a new chip + * @ni: NMBM instance structure + */ +static bool nmbm_load_existing(struct nmbm_instance *ni) +{ + bool success; + + /* Calculate the boundary of management blocks */ + ni->mgmt_start_ba = ni->signature.mgmt_start_pb; + + nlog_debug(ni, "NMBM management region starts at block %u [0x%08llx]\n", + ni->mgmt_start_ba, ba2addr(ni, ni->mgmt_start_ba)); + + /* Look for info table(s) */ + success = nmbm_load_info_table(ni, ni->mgmt_start_ba, + ni->signature_ba); + if (success) { + nlog_info(ni, "NMBM has been successfully attached\n"); + return true; + } + + if (!ni->force_create) { + printk("not creating NMBM table\n"); + return false; + } + + /* Fill block state table & mapping table */ + nmbm_scan_badblocks(ni); + nmbm_build_mapping_table(ni); + + /* Write info table(s) */ + success = nmbm_create_info_table(ni); + if (success) { + nlog_info(ni, "NMBM has been successfully created\n"); + return true; + } + + return false; +} + +/* + * nmbm_find_signature - Find signature in the lower NAND chip + * @ni: NMBM instance structure + * @signature_ba: used for storing block address of the signature + * @signature_ba: return the actual block address of signature block + * + * Find a valid signature from a specific range in the lower NAND chip, + * from bottom (highest address) to top (lowest address) + * + * Return true if found. + */ +static bool nmbm_find_signature(struct nmbm_instance *ni, + struct nmbm_signature *signature, + uint32_t *signature_ba) +{ + struct nmbm_signature sig; + uint64_t off, addr; + uint32_t block_count, ba, limit; + bool success; + int ret; + + /* Calculate top and bottom block address */ + block_count = bmtd.total_blks; + ba = block_count; + limit = (block_count / NMBM_MGMT_DIV) * (NMBM_MGMT_DIV - ni->max_ratio); + if (ni->max_reserved_blocks && block_count - limit > ni->max_reserved_blocks) + limit = block_count - ni->max_reserved_blocks; + + while (ba >= limit) { + ba--; + addr = ba2addr(ni, ba); + + if (nmbm_check_bad_phys_block(ni, ba)) + continue; + + /* Check every page. + * As long as at leaset one page contains valid signature, + * the block is treated as a valid signature block. + */ + for (off = 0; off < bmtd.blk_size; + off += bmtd.pg_size) { + ret = nmbn_read_data(ni, addr + off, &sig, + sizeof(sig)); + if (ret) + continue; + + /* Check for header size and checksum */ + success = nmbm_check_header(&sig, sizeof(sig)); + if (!success) + continue; + + /* Check for header magic */ + if (sig.header.magic == NMBM_MAGIC_SIGNATURE) { + /* Found it */ + memcpy(signature, &sig, sizeof(sig)); + *signature_ba = ba; + return true; + } + } + }; + + return false; +} + +/* + * nmbm_calc_structure_size - Calculate the instance structure size + * @nld: NMBM lower device structure + */ +static size_t nmbm_calc_structure_size(void) +{ + uint32_t state_table_size, mapping_table_size, info_table_size; + uint32_t block_count; + + block_count = bmtd.total_blks; + + /* Calculate info table size */ + state_table_size = ((block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) / + NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE; + mapping_table_size = block_count * sizeof(int32_t); + + info_table_size = ALIGN(sizeof(struct nmbm_info_table_header), + bmtd.pg_size); + info_table_size += ALIGN(state_table_size, bmtd.pg_size); + info_table_size += ALIGN(mapping_table_size, bmtd.pg_size); + + return info_table_size + state_table_size + mapping_table_size + + sizeof(struct nmbm_instance); +} + +/* + * nmbm_init_structure - Initialize members of instance structure + * @ni: NMBM instance structure + */ +static void nmbm_init_structure(struct nmbm_instance *ni) +{ + uint32_t pages_per_block, blocks_per_chip; + uintptr_t ptr; + + pages_per_block = bmtd.blk_size / bmtd.pg_size; + blocks_per_chip = bmtd.total_blks; + + ni->rawpage_size = bmtd.pg_size + bmtd.mtd->oobsize; + ni->rawblock_size = pages_per_block * ni->rawpage_size; + ni->rawchip_size = blocks_per_chip * ni->rawblock_size; + + /* Calculate number of block this chip */ + ni->block_count = blocks_per_chip; + + /* Calculate info table size */ + ni->state_table_size = ((ni->block_count + NMBM_BITMAP_BLOCKS_PER_UNIT - 1) / + NMBM_BITMAP_BLOCKS_PER_UNIT) * NMBM_BITMAP_UNIT_SIZE; + ni->mapping_table_size = ni->block_count * sizeof(*ni->block_mapping); + + ni->info_table_size = ALIGN(sizeof(ni->info_table), + bmtd.pg_size); + ni->info_table.state_table_off = ni->info_table_size; + + ni->info_table_size += ALIGN(ni->state_table_size, + bmtd.pg_size); + ni->info_table.mapping_table_off = ni->info_table_size; + + ni->info_table_size += ALIGN(ni->mapping_table_size, + bmtd.pg_size); + + ni->info_table_spare_blocks = nmbm_get_spare_block_count( + size2blk(ni, ni->info_table_size)); + + /* Assign memory to members */ + ptr = (uintptr_t)ni + sizeof(*ni); + + ni->info_table_cache = (void *)ptr; + ptr += ni->info_table_size; + + ni->block_state = (void *)ptr; + ptr += ni->state_table_size; + + ni->block_mapping = (void *)ptr; + ptr += ni->mapping_table_size; + + ni->page_cache = bmtd.data_buf; + + /* Initialize block state table */ + ni->block_state_changed = 0; + memset(ni->block_state, 0xff, ni->state_table_size); + + /* Initialize block mapping table */ + ni->block_mapping_changed = 0; +} + +/* + * nmbm_attach - Attach to a lower device + * @ni: NMBM instance structure + */ +static int nmbm_attach(struct nmbm_instance *ni) +{ + bool success; + + if (!ni) + return -EINVAL; + + /* Initialize NMBM instance */ + nmbm_init_structure(ni); + + success = nmbm_find_signature(ni, &ni->signature, &ni->signature_ba); + if (!success) { + if (!ni->force_create) { + nlog_err(ni, "Signature not found\n"); + return -ENODEV; + } + + success = nmbm_create_new(ni); + if (!success) + return -ENODEV; + + return 0; + } + + nlog_info(ni, "Signature found at block %u [0x%08llx]\n", + ni->signature_ba, ba2addr(ni, ni->signature_ba)); + + if (ni->signature.header.version != NMBM_VER) { + nlog_err(ni, "NMBM version %u.%u is not supported\n", + NMBM_VERSION_MAJOR_GET(ni->signature.header.version), + NMBM_VERSION_MINOR_GET(ni->signature.header.version)); + return -EINVAL; + } + + if (ni->signature.nand_size != bmtd.total_blks << bmtd.blk_shift || + ni->signature.block_size != bmtd.blk_size || + ni->signature.page_size != bmtd.pg_size || + ni->signature.spare_size != bmtd.mtd->oobsize) { + nlog_err(ni, "NMBM configuration mismatch\n"); + return -EINVAL; + } + + success = nmbm_load_existing(ni); + if (!success) + return -ENODEV; + + return 0; +} + +static bool remap_block_nmbm(u16 block, u16 mapped_block, int copy_len) +{ + struct nmbm_instance *ni = bmtd.ni; + int new_block; + + if (block >= ni->data_block_count) + return false; + + nmbm_set_block_state(ni, mapped_block, BLOCK_ST_BAD); + if (!nmbm_map_block(ni, block)) + return false; + + new_block = ni->block_mapping[block]; + bbt_nand_erase(new_block); + if (copy_len > 0) + bbt_nand_copy(new_block, mapped_block, copy_len); + nmbm_update_info_table(ni); + + return true; +} + +static int get_mapping_block_index_nmbm(int block) +{ + struct nmbm_instance *ni = bmtd.ni; + + if (block >= ni->data_block_count) + return -1; + + return ni->block_mapping[block]; +} + +static int mtk_bmt_init_nmbm(struct device_node *np) +{ + struct nmbm_instance *ni; + int ret; + + ni = kzalloc(nmbm_calc_structure_size(), GFP_KERNEL); + if (!ni) + return -ENOMEM; + + bmtd.ni = ni; + + if (of_property_read_u32(np, "mediatek,bmt-max-ratio", &ni->max_ratio)) + ni->max_ratio = 1; + if (of_property_read_u32(np, "mediatek,bmt-max-reserved-blocks", + &ni->max_reserved_blocks)) + ni->max_reserved_blocks = 256; + if (of_property_read_bool(np, "mediatek,empty-page-ecc-protected")) + ni->empty_page_ecc_ok = true; + if (of_property_read_bool(np, "mediatek,bmt-force-create")) + ni->force_create = true; + + ret = nmbm_attach(ni); + if (ret) + goto out; + + bmtd.mtd->size = ni->data_block_count << bmtd.blk_shift; + + return 0; + +out: + kfree(ni); + bmtd.ni = NULL; + + return ret; +} + +static int mtk_bmt_debug_nmbm(void *data, u64 val) +{ + struct nmbm_instance *ni = bmtd.ni; + int i; + + switch (val) { + case 0: + for (i = 1; i < ni->data_block_count; i++) { + if (ni->block_mapping[i] < ni->mapping_blocks_ba) + continue; + + printk("remap [%x->%x]\n", i, ni->block_mapping[i]); + } + } + + return 0; +} + +static void unmap_block_nmbm(u16 block) +{ + struct nmbm_instance *ni = bmtd.ni; + int start, offset; + int new_block; + + if (block >= ni->data_block_count) + return; + + start = block; + offset = 0; + while (ni->block_mapping[start] >= ni->mapping_blocks_ba) { + start--; + offset++; + if (start < 0) + return; + } + + if (!offset) + return; + + new_block = ni->block_mapping[start] + offset; + nmbm_set_block_state(ni, new_block, BLOCK_ST_GOOD); + ni->block_mapping[block] = new_block; + ni->block_mapping_changed++; + + new_block = ni->signature_ba - 1; + for (block = 0; block < ni->data_block_count; block++) { + int cur = ni->block_mapping[block]; + + if (cur < ni->mapping_blocks_ba) + continue; + + if (cur <= new_block) + new_block = cur - 1; + } + + ni->mapping_blocks_top_ba = new_block; + + nmbm_update_info_table(ni); +} + +const struct mtk_bmt_ops mtk_bmt_nmbm_ops = { + .init = mtk_bmt_init_nmbm, + .remap_block = remap_block_nmbm, + .unmap_block = unmap_block_nmbm, + .get_mapping_block = get_mapping_block_index_nmbm, + .debug = mtk_bmt_debug_nmbm, +}; diff --git a/drivers/mtd/nand/mtk_bmt_v2.c b/drivers/mtd/nand/mtk_bmt_v2.c new file mode 100644 index 000000000000..a17b7290260b --- /dev/null +++ b/drivers/mtd/nand/mtk_bmt_v2.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Xiangsheng Hou + * Copyright (c) 2020-2022 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "mtk_bmt.h" + +struct bbbt { + char signature[3]; + /* This version is used to distinguish the legacy and new algorithm */ +#define BBMT_VERSION 2 + unsigned char version; + /* Below 2 tables will be written in SLC */ + u16 bb_tbl[]; +}; + +struct bbmt { + u16 block; +#define NO_MAPPED 0 +#define NORMAL_MAPPED 1 +#define BMT_MAPPED 2 + u16 mapped; +}; + +/* Maximum 8k blocks */ +#define BBPOOL_RATIO 2 +#define BB_TABLE_MAX bmtd.table_size +#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) +#define BMT_TBL_DEF_VAL 0x0 + +static inline struct bbmt *bmt_tbl(struct bbbt *bbbt) +{ + return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size]; +} + +static u16 find_valid_block(u16 block) +{ + u8 fdm[4]; + int ret; + int loop = 0; + +retry: + if (block >= bmtd.total_blks) + return 0; + + ret = bbt_nand_read(blk_pg(block), bmtd.data_buf, bmtd.pg_size, + fdm, sizeof(fdm)); + /* Read the 1st byte of FDM to judge whether it's a bad + * or not + */ + if (ret || fdm[0] != 0xff) { + pr_info("nand: found bad block 0x%x\n", block); + if (loop >= bmtd.bb_max) { + pr_info("nand: FATAL ERR: too many bad blocks!!\n"); + return 0; + } + + loop++; + block++; + goto retry; + } + + return block; +} + +/* Find out all bad blocks, and fill in the mapping table */ +static int scan_bad_blocks(struct bbbt *bbt) +{ + int i; + u16 block = 0; + + /* First time download, the block0 MUST NOT be a bad block, + * this is guaranteed by vendor + */ + bbt->bb_tbl[0] = 0; + + /* + * Construct the mapping table of Normal data area(non-PMT/BMTPOOL) + * G - Good block; B - Bad block + * --------------------------- + * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| + * --------------------------- + * What bb_tbl[i] looks like: + * physical block(i): + * 0 1 2 3 4 5 6 7 8 9 a b c + * mapped block(bb_tbl[i]): + * 0 1 3 6 7 8 9 b ...... + * ATTENTION: + * If new bad block ocurred(n), search bmt_tbl to find + * a available block(x), and fill in the bb_tbl[n] = x; + */ + for (i = 1; i < bmtd.pool_lba; i++) { + bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1); + BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]); + if (bbt->bb_tbl[i] == 0) + return -1; + } + + /* Physical Block start Address of BMT pool */ + bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1; + if (bmtd.pool_pba >= bmtd.total_blks - 2) { + pr_info("nand: FATAL ERR: Too many bad blocks!!\n"); + return -1; + } + + BBT_LOG("pool_pba=0x%x", bmtd.pool_pba); + i = 0; + block = bmtd.pool_pba; + /* + * The bmt table is used for runtime bad block mapping + * G - Good block; B - Bad block + * --------------------------- + * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| + * --------------------------- + * block: 0 1 2 3 4 5 6 7 8 9 a b c + * What bmt_tbl[i] looks like in initial state: + * i: + * 0 1 2 3 4 5 6 7 + * bmt_tbl[i].block: + * 0 1 3 6 7 8 9 b + * bmt_tbl[i].mapped: + * N N N N N N N B + * N - Not mapped(Available) + * M - Mapped + * B - BMT + * ATTENTION: + * BMT always in the last valid block in pool + */ + while ((block = find_valid_block(block)) != 0) { + bmt_tbl(bbt)[i].block = block; + bmt_tbl(bbt)[i].mapped = NO_MAPPED; + BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block); + block++; + i++; + } + + /* i - How many available blocks in pool, which is the length of bmt_tbl[] + * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block + */ + bmtd.bmt_blk_idx = i - 1; + bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED; + + if (i < 1) { + pr_info("nand: FATAL ERR: no space to store BMT!!\n"); + return -1; + } + + pr_info("[BBT] %d available blocks in BMT pool\n", i); + + return 0; +} + +static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm) +{ + struct bbbt *bbt = (struct bbbt *)buf; + u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET; + + + if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 && + memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) { + if (bbt->version == BBMT_VERSION) + return true; + } + BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x", + sig[0], sig[1], sig[2], + fdm[1], fdm[2], fdm[3]); + return false; +} + +static u16 get_bmt_index(struct bbmt *bmt) +{ + int i = 0; + + while (bmt[i].block != BMT_TBL_DEF_VAL) { + if (bmt[i].mapped == BMT_MAPPED) + return i; + i++; + } + return 0; +} + +/* Write the Burner Bad Block Table to Nand Flash + * n - write BMT to bmt_tbl[n] + */ +static u16 upload_bmt(struct bbbt *bbt, int n) +{ + u16 block; + +retry: + if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) { + pr_info("nand: FATAL ERR: no space to store BMT!\n"); + return (u16)-1; + } + + block = bmt_tbl(bbt)[n].block; + BBT_LOG("n = 0x%x, block = 0x%x", n, block); + if (bbt_nand_erase(block)) { + bmt_tbl(bbt)[n].block = 0; + /* erase failed, try the previous block: bmt_tbl[n - 1].block */ + n--; + goto retry; + } + + /* The signature offset is fixed set to 0, + * oob signature offset is fixed set to 1 + */ + memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3); + bbt->version = BBMT_VERSION; + + if (write_bmt(block, (unsigned char *)bbt)) { + bmt_tbl(bbt)[n].block = 0; + + /* write failed, try the previous block in bmt_tbl[n - 1] */ + n--; + goto retry; + } + + /* Return the current index(n) of BMT pool (bmt_tbl[n]) */ + return n; +} + +static u16 find_valid_block_in_pool(struct bbbt *bbt) +{ + int i; + + if (bmtd.bmt_blk_idx == 0) + goto error; + + for (i = 0; i < bmtd.bmt_blk_idx; i++) { + if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) { + bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED; + return bmt_tbl(bbt)[i].block; + } + } + +error: + pr_info("nand: FATAL ERR: BMT pool is run out!\n"); + return 0; +} + +/* We met a bad block, mark it as bad and map it to a valid block in pool, + * if it's a write failure, we need to write the data to mapped block + */ +static bool remap_block_v2(u16 block, u16 mapped_block, int copy_len) +{ + u16 new_block; + struct bbbt *bbt; + + bbt = bmtd.bbt; + new_block = find_valid_block_in_pool(bbt); + if (new_block == 0) + return false; + + /* Map new bad block to available block in pool */ + bbt->bb_tbl[block] = new_block; + + /* Erase new block */ + bbt_nand_erase(new_block); + if (copy_len > 0) + bbt_nand_copy(new_block, mapped_block, copy_len); + + bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); + + return true; +} + +static int get_mapping_block_index_v2(int block) +{ + int start, end; + + if (block >= bmtd.pool_lba) + return block; + + if (!mapping_block_in_range(block, &start, &end)) + return block; + + return bmtd.bbt->bb_tbl[block]; +} + +static void +unmap_block_v2(u16 block) +{ + bmtd.bbt->bb_tbl[block] = block; + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); +} + +static unsigned long * +mtk_bmt_get_mapping_mask(void) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + int main_blocks = bmtd.mtd->size >> bmtd.blk_shift; + unsigned long *used; + int i, k; + + used = kcalloc(BIT_WORD(bmtd.bmt_blk_idx) + 1, sizeof(unsigned long), GFP_KERNEL); + if (!used) + return NULL; + + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + for (k = 0; k < bmtd.bmt_blk_idx; k++) { + if (bmtd.bbt->bb_tbl[i] != bbmt[k].block) + continue; + + set_bit(k, used); + break; + } + } + + return used; +} + +static int mtk_bmt_debug_v2(void *data, u64 val) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + struct mtd_info *mtd = bmtd.mtd; + unsigned long *used; + int main_blocks = mtd->size >> bmtd.blk_shift; + int n_remap = 0; + int i; + + used = mtk_bmt_get_mapping_mask(); + if (!used) + return -ENOMEM; + + switch (val) { + case 0: + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + printk("remap [%x->%x]\n", i, bmtd.bbt->bb_tbl[i]); + n_remap++; + } + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + char c; + + switch (bbmt[i].mapped) { + case NO_MAPPED: + continue; + case NORMAL_MAPPED: + c = 'm'; + if (test_bit(i, used)) + c = 'M'; + break; + case BMT_MAPPED: + c = 'B'; + break; + default: + c = 'X'; + break; + } + printk("[%x:%c] = 0x%x\n", i, c, bbmt[i].block); + } + break; + case 100: + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + if (bbmt[i].mapped != NORMAL_MAPPED) + continue; + + if (test_bit(i, used)) + continue; + + n_remap++; + bbmt[i].mapped = NO_MAPPED; + printk("free block [%d:%x]\n", i, bbmt[i].block); + } + if (n_remap) + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + break; + } + + kfree(used); + + return 0; +} + +static int mtk_bmt_init_v2(struct device_node *np) +{ + u32 bmt_pool_size, bmt_table_size; + u32 bufsz, block; + u16 pmt_block; + + if (of_property_read_u32(np, "mediatek,bmt-pool-size", + &bmt_pool_size) != 0) + bmt_pool_size = 80; + + if (of_property_read_u8(np, "mediatek,bmt-oob-offset", + &bmtd.oob_offset) != 0) + bmtd.oob_offset = 0; + + if (of_property_read_u32(np, "mediatek,bmt-table-size", + &bmt_table_size) != 0) + bmt_table_size = 0x2000U; + + bmtd.table_size = bmt_table_size; + + pmt_block = bmtd.total_blks - bmt_pool_size - 2; + + bmtd.mtd->size = pmt_block << bmtd.blk_shift; + + /* + * --------------------------------------- + * | PMT(2blks) | BMT POOL(totalblks * 2%) | + * --------------------------------------- + * ^ ^ + * | | + * pmt_block pmt_block + 2blocks(pool_lba) + * + * ATTETION!!!!!! + * The blocks ahead of the boundary block are stored in bb_tbl + * and blocks behind are stored in bmt_tbl + */ + + bmtd.pool_lba = (u16)(pmt_block + 2); + bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; + + bufsz = round_up(sizeof(struct bbbt) + + bmt_table_size * sizeof(struct bbmt), bmtd.pg_size); + bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; + + bmtd.bbt_buf = kzalloc(bufsz, GFP_KERNEL); + if (!bmtd.bbt_buf) + return -ENOMEM; + + memset(bmtd.bbt_buf, 0xff, bufsz); + + /* Scanning start from the first page of the last block + * of whole flash + */ + bmtd.bbt = NULL; + for (u16 block = bmtd.total_blks - 1; !bmtd.bbt && block >= bmtd.pool_lba; block--) { + u8 fdm[4]; + + if (bbt_nand_read(blk_pg(block), bmtd.bbt_buf, bufsz, fdm, sizeof(fdm))) { + /* Read failed, try the previous block */ + continue; + } + + if (!is_valid_bmt(bmtd.bbt_buf, fdm)) { + /* No valid BMT found, try the previous block */ + continue; + } + + bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)bmtd.bbt_buf)); + if (bmtd.bmt_blk_idx == 0) { + pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); + break; + } + + pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); + bmtd.bbt = (struct bbbt *)bmtd.bbt_buf; + } + + if (!bmtd.bbt) { + /* BMT not found */ + if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { + pr_info("nand: FATAL: Too many blocks, can not support!\n"); + return -1; + } + + bmtd.bbt = (struct bbbt *)bmtd.bbt_buf; + memset(bmt_tbl(bmtd.bbt), BMT_TBL_DEF_VAL, + bmtd.table_size * sizeof(struct bbmt)); + + if (scan_bad_blocks(bmtd.bbt)) + return -1; + + /* BMT always in the last valid block in pool */ + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + block = bmt_tbl(bmtd.bbt)[bmtd.bmt_blk_idx].block; + pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); + + if (bmtd.bmt_blk_idx == 0) + pr_info("nand: Warning: no available block in BMT pool!\n"); + else if (bmtd.bmt_blk_idx == (u16)-1) + return -1; + } + + return 0; +} + + +const struct mtk_bmt_ops mtk_bmt_v2_ops = { + .sig = "bmt", + .sig_len = 3, + .init = mtk_bmt_init_v2, + .remap_block = remap_block_v2, + .unmap_block = unmap_block_v2, + .get_mapping_block = get_mapping_block_index_v2, + .debug = mtk_bmt_debug_v2, +}; diff --git a/drivers/mtd/parsers/routerbootpart.c b/drivers/mtd/parsers/routerbootpart.c new file mode 100644 index 000000000000..aa786cd895e5 --- /dev/null +++ b/drivers/mtd/parsers/routerbootpart.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Parser for MikroTik RouterBoot partitions. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This parser builds from the "fixed-partitions" one (see ofpart.c), but it can + * handle dynamic partitions as found on routerboot devices. + * + * DTS nodes are defined as follows: + * For fixed partitions: + * node-name@unit-address { + * reg = ; + * label = ; + * read-only; + * lock; + * }; + * + * reg property is mandatory; other properties are optional. + * reg format is
. length can be 0 if the next partition is + * another fixed partition or a "well-known" partition as defined below: in that + * case the partition will extend up to the next one. + * + * For dynamic partitions: + * node-name { + * size = ; + * label = ; + * read-only; + * lock; + * }; + * + * size property is normally mandatory. It can only be omitted (or set to 0) if: + * - the partition is a "well-known" one (as defined below), in which case + * the partition size will be automatically adjusted; or + * - the next partition is a fixed one or a "well-known" one, in which case + * the current partition will extend up to the next one. + * Other properties are optional. + * size format is . + * By default dynamic partitions are appended after the preceding one, except + * for "well-known" ones which are automatically located on flash. + * + * Well-known partitions (matched via label or node-name): + * - "hard_config" + * - "soft_config" + * - "dtb_config" + * + * Note: this parser will happily register 0-sized partitions if misused. + * + * This parser requires the DTS to list partitions in ascending order as + * expected on the MTD device. + * + * Since only the "hard_config" and "soft_config" partitions are used in OpenWRT, + * a minimal working DTS could define only these two partitions dynamically (in + * the right order, usually hard_config then soft_config). + * + * Note: some mips RB devices encode the hard_config offset and length in two + * consecutive u32 located at offset 0x14 (for ramips) or 0x24 (for ath79) on + * the SPI NOR flash. Unfortunately this seems inconsistent across machines and + * does not apply to e.g. ipq-based ones, so we ignore that information. + * + * Note: To find well-known partitions, this parser will go through the entire + * top mtd partition parsed, _before_ the DTS nodes are processed. This works + * well in the current state of affairs, and is a simpler implementation than + * searching for known partitions in the "holes" left between fixed-partition, + * _after_ processing DTS nodes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) +#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) +#define RB_BLOCK_SIZE 0x1000 + +struct routerboot_dynpart { + const char * const name; + const u32 magic; + int (* const size_fixup)(struct mtd_info *, struct routerboot_dynpart *); + size_t offset; + size_t size; + bool found; +}; + +static int routerboot_dtbsfixup(struct mtd_info *, struct routerboot_dynpart *); + +static struct routerboot_dynpart rb_dynparts[] = { + { + .name = "hard_config", + .magic = RB_MAGIC_HARD, // stored in CPU-endianness on flash + .size_fixup = NULL, + .offset = 0x0, + .size = RB_BLOCK_SIZE, + .found = false, + }, { + .name = "soft_config", + .magic = RB_MAGIC_SOFT, // stored in CPU-endianness on flash + .size_fixup = NULL, + .offset = 0x0, + .size = RB_BLOCK_SIZE, + .found = false, + }, { + .name = "dtb_config", + .magic = fdt32_to_cpu(OF_DT_HEADER), // stored BE on flash + .size_fixup = routerboot_dtbsfixup, + .offset = 0x0, + .size = 0x0, + .found = false, + } +}; + +static int routerboot_dtbsfixup(struct mtd_info *master, struct routerboot_dynpart *rbdpart) +{ + int err; + size_t bytes_read, psize; + struct { + fdt32_t magic; + fdt32_t totalsize; + fdt32_t off_dt_struct; + fdt32_t off_dt_strings; + fdt32_t off_mem_rsvmap; + fdt32_t version; + fdt32_t last_comp_version; + fdt32_t boot_cpuid_phys; + fdt32_t size_dt_strings; + fdt32_t size_dt_struct; + } fdt_header; + + err = mtd_read(master, rbdpart->offset, sizeof(fdt_header), + &bytes_read, (u8 *)&fdt_header); + if (err) + return err; + + if (bytes_read != sizeof(fdt_header)) + return -EIO; + + psize = fdt32_to_cpu(fdt_header.totalsize); + if (!psize) + return -EINVAL; + + rbdpart->size = psize; + return 0; +} + +static void routerboot_find_dynparts(struct mtd_info *master) +{ + size_t bytes_read, offset; + bool allfound; + int err, i; + u32 buf; + + /* + * Dynamic RouterBoot partitions offsets are aligned to RB_BLOCK_SIZE: + * read the whole partition at RB_BLOCK_SIZE intervals to find sigs. + * Skip partition content when possible. + */ + offset = 0; + while (offset < master->size) { + err = mtd_read(master, offset, sizeof(buf), &bytes_read, (u8 *)&buf); + if (err) { + pr_err("%s: mtd_read error while parsing (offset: 0x%zX): %d\n", + master->name, offset, err); + continue; + } + + allfound = true; + + for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { + if (rb_dynparts[i].found) + continue; + + allfound = false; + + if (rb_dynparts[i].magic == buf) { + rb_dynparts[i].offset = offset; + + if (rb_dynparts[i].size_fixup) { + err = rb_dynparts[i].size_fixup(master, &rb_dynparts[i]); + if (err) { + pr_err("%s: size fixup error while parsing \"%s\": %d\n", + master->name, rb_dynparts[i].name, err); + continue; + } + } + + rb_dynparts[i].found = true; + + /* + * move offset to skip the whole partition on + * next iteration if size > RB_BLOCK_SIZE. + */ + if (rb_dynparts[i].size > RB_BLOCK_SIZE) + offset += ALIGN_DOWN((rb_dynparts[i].size - RB_BLOCK_SIZE), RB_BLOCK_SIZE); + + break; + } + } + + offset += RB_BLOCK_SIZE; + + if (allfound) + break; + } +} + +static int routerboot_partitions_parse(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *rbpart_node, *pp; + struct mtd_partition *parts; + const char *partname; + size_t master_ofs; + int np; + + /* Pull of_node from the master device node */ + rbpart_node = mtd_get_of_node(master); + if (!rbpart_node) + return 0; + + /* First count the subnodes */ + np = 0; + for_each_child_of_node(rbpart_node, pp) + np++; + + if (!np) + return 0; + + parts = kcalloc(np, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* Preemptively look for known parts in flash */ + routerboot_find_dynparts(master); + + np = 0; + master_ofs = 0; + for_each_child_of_node(rbpart_node, pp) { + const __be32 *reg, *sz; + size_t offset, size; + int i, len, a_cells, s_cells; + + partname = of_get_property(pp, "label", &len); + /* Allow deprecated use of "name" instead of "label" */ + if (!partname) + partname = of_get_property(pp, "name", &len); + /* Fallback to node name per spec if all else fails: partname is always set */ + if (!partname) + partname = pp->name; + parts[np].name = partname; + + reg = of_get_property(pp, "reg", &len); + if (reg) { + /* Fixed partition */ + a_cells = of_n_addr_cells(pp); + s_cells = of_n_size_cells(pp); + + if ((len / 4) != (a_cells + s_cells)) { + pr_debug("%s: routerboot partition %pOF (%pOF) error parsing reg property.\n", + master->name, pp, rbpart_node); + goto rbpart_fail; + } + + offset = of_read_number(reg, a_cells); + size = of_read_number(reg + a_cells, s_cells); + } else { + /* Dynamic partition */ + /* Default: part starts at current offset, 0 size */ + offset = master_ofs; + size = 0; + + /* Check if well-known partition */ + for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { + if (!strcmp(partname, rb_dynparts[i].name) && rb_dynparts[i].found) { + offset = rb_dynparts[i].offset; + size = rb_dynparts[i].size; + break; + } + } + + /* Standalone 'size' property? Override size */ + sz = of_get_property(pp, "size", &len); + if (sz) { + s_cells = of_n_size_cells(pp); + if ((len / 4) != s_cells) { + pr_debug("%s: routerboot partition %pOF (%pOF) error parsing size property.\n", + master->name, pp, rbpart_node); + goto rbpart_fail; + } + + size = of_read_number(sz, s_cells); + } + } + + if (np > 0) { + /* Minor sanity check for overlaps */ + if (offset < (parts[np-1].offset + parts[np-1].size)) { + pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" overlaps with previous partition \"%s\".\n", + master->name, pp, rbpart_node, + partname, parts[np-1].name); + goto rbpart_fail; + } + + /* Fixup end of previous partition if necessary */ + if (!parts[np-1].size) + parts[np-1].size = (offset - parts[np-1].offset); + } + + if ((offset + size) > master->size) { + pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" extends past end of segment.\n", + master->name, pp, rbpart_node, partname); + goto rbpart_fail; + } + + parts[np].offset = offset; + parts[np].size = size; + parts[np].of_node = pp; + + if (of_get_property(pp, "read-only", &len)) + parts[np].mask_flags |= MTD_WRITEABLE; + + if (of_get_property(pp, "lock", &len)) + parts[np].mask_flags |= MTD_POWERUP_LOCK; + + /* Keep master offset aligned to RB_BLOCK_SIZE */ + master_ofs = ALIGN(offset + size, RB_BLOCK_SIZE); + np++; + } + + *pparts = parts; + return np; + +rbpart_fail: + pr_err("%s: error parsing routerboot partition %pOF (%pOF)\n", + master->name, pp, rbpart_node); + of_node_put(pp); + kfree(parts); + return -EINVAL; +} + +static const struct of_device_id parse_routerbootpart_match_table[] = { + { .compatible = "mikrotik,routerboot-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_routerbootpart_match_table); + +static struct mtd_part_parser routerbootpart_parser = { + .parse_fn = routerboot_partitions_parse, + .name = "routerbootpart", + .of_match_table = parse_routerbootpart_match_table, +}; +module_mtd_part_parser(routerbootpart_parser); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MTD partitioning for RouterBoot"); +MODULE_AUTHOR("Thibaut VARENE"); diff --git a/drivers/net/dsa/an8855.c b/drivers/net/dsa/an8855.c new file mode 100644 index 000000000000..e6666d2011c9 --- /dev/null +++ b/drivers/net/dsa/an8855.c @@ -0,0 +1,2308 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Airoha AN8855 DSA Switch driver + * Copyright (C) 2023 Min Yao + * Copyright (C) 2024 Christian Marangi + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "an8855.h" + +static const struct an8855_mib_desc an8855_mib[] = { + MIB_DESC(1, AN8855_PORT_MIB_TX_DROP, "TxDrop"), + MIB_DESC(1, AN8855_PORT_MIB_TX_CRC_ERR, "TxCrcErr"), + MIB_DESC(1, AN8855_PORT_MIB_TX_COLLISION, "TxCollision"), + MIB_DESC(1, AN8855_PORT_MIB_TX_OVERSIZE_DROP, "TxOversizeDrop"), + MIB_DESC(2, AN8855_PORT_MIB_TX_BAD_PKT_BYTES, "TxBadPktBytes"), + MIB_DESC(1, AN8855_PORT_MIB_RX_DROP, "RxDrop"), + MIB_DESC(1, AN8855_PORT_MIB_RX_FILTERING, "RxFiltering"), + MIB_DESC(1, AN8855_PORT_MIB_RX_CRC_ERR, "RxCrcErr"), + MIB_DESC(1, AN8855_PORT_MIB_RX_CTRL_DROP, "RxCtrlDrop"), + MIB_DESC(1, AN8855_PORT_MIB_RX_INGRESS_DROP, "RxIngressDrop"), + MIB_DESC(1, AN8855_PORT_MIB_RX_ARL_DROP, "RxArlDrop"), + MIB_DESC(1, AN8855_PORT_MIB_FLOW_CONTROL_DROP, "FlowControlDrop"), + MIB_DESC(1, AN8855_PORT_MIB_WRED_DROP, "WredDrop"), + MIB_DESC(1, AN8855_PORT_MIB_MIRROR_DROP, "MirrorDrop"), + MIB_DESC(2, AN8855_PORT_MIB_RX_BAD_PKT_BYTES, "RxBadPktBytes"), + MIB_DESC(1, AN8855_PORT_MIB_RXS_FLOW_SAMPLING_PKT_DROP, "RxsFlowSamplingPktDrop"), + MIB_DESC(1, AN8855_PORT_MIB_RXS_FLOW_TOTAL_PKT_DROP, "RxsFlowTotalPktDrop"), + MIB_DESC(1, AN8855_PORT_MIB_PORT_CONTROL_DROP, "PortControlDrop"), +}; + +static int +an8855_mib_init(struct an8855_priv *priv) +{ + int ret; + + ret = regmap_write(priv->regmap, AN8855_MIB_CCR, + AN8855_CCR_MIB_ENABLE); + if (ret) + return ret; + + return regmap_write(priv->regmap, AN8855_MIB_CCR, + AN8855_CCR_MIB_ACTIVATE); +} + +static void an8855_fdb_write(struct an8855_priv *priv, u16 vid, + u8 port_mask, const u8 *mac, + bool add) __must_hold(&priv->reg_mutex) +{ + u32 mac_reg[2] = { }; + u32 reg; + + mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC0, mac[0]); + mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC1, mac[1]); + mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC2, mac[2]); + mac_reg[0] |= FIELD_PREP(AN8855_ATA1_MAC3, mac[3]); + mac_reg[1] |= FIELD_PREP(AN8855_ATA2_MAC4, mac[4]); + mac_reg[1] |= FIELD_PREP(AN8855_ATA2_MAC5, mac[5]); + + regmap_bulk_write(priv->regmap, AN8855_ATA1, mac_reg, + ARRAY_SIZE(mac_reg)); + + reg = AN8855_ATWD_IVL; + if (add) + reg |= AN8855_ATWD_VLD; + reg |= FIELD_PREP(AN8855_ATWD_VID, vid); + reg |= FIELD_PREP(AN8855_ATWD_FID, AN8855_FID_BRIDGED); + regmap_write(priv->regmap, AN8855_ATWD, reg); + regmap_write(priv->regmap, AN8855_ATWD2, + FIELD_PREP(AN8855_ATWD2_PORT, port_mask)); +} + +static void an8855_fdb_read(struct an8855_priv *priv, struct an8855_fdb *fdb) +{ + u32 reg[4]; + + regmap_bulk_read(priv->regmap, AN8855_ATRD0, reg, + ARRAY_SIZE(reg)); + + fdb->live = FIELD_GET(AN8855_ATRD0_LIVE, reg[0]); + fdb->type = FIELD_GET(AN8855_ATRD0_TYPE, reg[0]); + fdb->ivl = FIELD_GET(AN8855_ATRD0_IVL, reg[0]); + fdb->vid = FIELD_GET(AN8855_ATRD0_VID, reg[0]); + fdb->fid = FIELD_GET(AN8855_ATRD0_FID, reg[0]); + fdb->aging = FIELD_GET(AN8855_ATRD1_AGING, reg[1]); + fdb->port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, reg[3]); + fdb->mac[0] = FIELD_GET(AN8855_ATRD2_MAC0, reg[2]); + fdb->mac[1] = FIELD_GET(AN8855_ATRD2_MAC1, reg[2]); + fdb->mac[2] = FIELD_GET(AN8855_ATRD2_MAC2, reg[2]); + fdb->mac[3] = FIELD_GET(AN8855_ATRD2_MAC3, reg[2]); + fdb->mac[4] = FIELD_GET(AN8855_ATRD1_MAC4, reg[1]); + fdb->mac[5] = FIELD_GET(AN8855_ATRD1_MAC5, reg[1]); + fdb->noarp = !!FIELD_GET(AN8855_ATRD0_ARP, reg[0]); +} + +static int an8855_fdb_cmd(struct an8855_priv *priv, u32 cmd, + u32 *rsp) __must_hold(&priv->reg_mutex) +{ + u32 val; + int ret; + + /* Set the command operating upon the MAC address entries */ + val = AN8855_ATC_BUSY | cmd; + ret = regmap_write(priv->regmap, AN8855_ATC, val); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(priv->regmap, AN8855_ATC, val, + !(val & AN8855_ATC_BUSY), 20, 200000); + if (ret) + return ret; + + if (rsp) + *rsp = val; + + return 0; +} + +static void +an8855_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct dsa_port *dp = dsa_to_port(ds, port); + struct an8855_priv *priv = ds->priv; + bool learning = false; + u32 stp_state; + + switch (state) { + case BR_STATE_DISABLED: + stp_state = AN8855_STP_DISABLED; + break; + case BR_STATE_BLOCKING: + stp_state = AN8855_STP_BLOCKING; + break; + case BR_STATE_LISTENING: + stp_state = AN8855_STP_LISTENING; + break; + case BR_STATE_LEARNING: + stp_state = AN8855_STP_LEARNING; + learning = dp->learning; + break; + case BR_STATE_FORWARDING: + learning = dp->learning; + fallthrough; + default: + stp_state = AN8855_STP_FORWARDING; + break; + } + + regmap_update_bits(priv->regmap, AN8855_SSP_P(port), + AN8855_FID_PST_MASK(AN8855_FID_BRIDGED), + AN8855_FID_PST_VAL(AN8855_FID_BRIDGED, stp_state)); + + regmap_update_bits(priv->regmap, AN8855_PSC_P(port), AN8855_SA_DIS, + learning ? 0 : AN8855_SA_DIS); +} + +static void an8855_port_fast_age(struct dsa_switch *ds, int port) +{ + struct an8855_priv *priv = ds->priv; + int ret; + + /* Set to clean Dynamic entry */ + ret = regmap_write(priv->regmap, AN8855_ATA2, AN8855_ATA2_TYPE); + if (ret) + return; + + /* Set Port */ + ret = regmap_write(priv->regmap, AN8855_ATWD2, + FIELD_PREP(AN8855_ATWD2_PORT, BIT(port))); + if (ret) + return; + + /* Flush Dynamic entry at port */ + an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_TYPE_PORT) | + AN8855_FDB_FLUSH, NULL); +} + +static int an8855_update_port_member(struct dsa_switch *ds, int port, + const struct net_device *bridge_dev, + bool join) +{ + struct an8855_priv *priv = ds->priv; + bool isolated, other_isolated; + struct dsa_port *dp; + u32 port_mask = 0; + int ret; + + isolated = !!(priv->port_isolated_map & BIT(port)); + + dsa_switch_for_each_user_port(dp, ds) { + if (dp->index == port) + continue; + + if (!dsa_port_offloads_bridge_dev(dp, bridge_dev)) + continue; + + other_isolated = !!(priv->port_isolated_map & BIT(dp->index)); + port_mask |= BIT(dp->index); + /* Add/remove this port to the portvlan mask of the other + * ports in the bridge + */ + if (join && !(isolated && other_isolated)) + ret = regmap_set_bits(priv->regmap, + AN8855_PORTMATRIX_P(dp->index), + FIELD_PREP(AN8855_USER_PORTMATRIX, + BIT(port))); + else + ret = regmap_clear_bits(priv->regmap, + AN8855_PORTMATRIX_P(dp->index), + FIELD_PREP(AN8855_USER_PORTMATRIX, + BIT(port))); + if (ret) + return ret; + } + + /* Add/remove all other ports to this port's portvlan mask */ + return regmap_update_bits(priv->regmap, AN8855_PORTMATRIX_P(port), + AN8855_USER_PORTMATRIX, + join ? port_mask : ~port_mask); +} + +static int an8855_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | + BR_BCAST_FLOOD | BR_ISOLATED)) + return -EINVAL; + + return 0; +} + +static int an8855_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct an8855_priv *priv = ds->priv; + int ret; + + if (flags.mask & BR_LEARNING) { + ret = regmap_update_bits(priv->regmap, AN8855_PSC_P(port), AN8855_SA_DIS, + flags.val & BR_LEARNING ? 0 : AN8855_SA_DIS); + if (ret) + return ret; + } + + if (flags.mask & BR_FLOOD) { + ret = regmap_update_bits(priv->regmap, AN8855_UNUF, BIT(port), + flags.val & BR_FLOOD ? BIT(port) : 0); + if (ret) + return ret; + } + + if (flags.mask & BR_MCAST_FLOOD) { + ret = regmap_update_bits(priv->regmap, AN8855_UNMF, BIT(port), + flags.val & BR_MCAST_FLOOD ? BIT(port) : 0); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_UNIPMF, BIT(port), + flags.val & BR_MCAST_FLOOD ? BIT(port) : 0); + if (ret) + return ret; + } + + if (flags.mask & BR_BCAST_FLOOD) { + ret = regmap_update_bits(priv->regmap, AN8855_BCF, BIT(port), + flags.val & BR_BCAST_FLOOD ? BIT(port) : 0); + if (ret) + return ret; + } + + if (flags.mask & BR_ISOLATED) { + struct dsa_port *dp = dsa_to_port(ds, port); + struct net_device *bridge_dev = dsa_port_bridge_dev_get(dp); + + if (flags.val & BR_ISOLATED) + priv->port_isolated_map |= BIT(port); + else + priv->port_isolated_map &= ~BIT(port); + + ret = an8855_update_port_member(ds, port, bridge_dev, true); + if (ret) + return ret; + } + + return 0; +} + +static int an8855_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +{ + struct an8855_priv *priv = ds->priv; + u32 age_count, age_unit, val; + + /* Convert msec in AN8855_L2_AGING_MS_CONSTANT counter */ + val = msecs / AN8855_L2_AGING_MS_CONSTANT; + /* Derive the count unit */ + age_unit = val / FIELD_MAX(AN8855_AGE_UNIT); + /* Get the count in unit, age_unit is always incremented by 1 internally */ + age_count = val / (age_unit + 1); + + return regmap_update_bits(priv->regmap, AN8855_AAC, + AN8855_AGE_CNT | AN8855_AGE_UNIT, + FIELD_PREP(AN8855_AGE_CNT, age_count) | + FIELD_PREP(AN8855_AGE_UNIT, age_unit)); +} + +static int an8855_port_bridge_join(struct dsa_switch *ds, int port, + struct dsa_bridge bridge, + bool *tx_fwd_offload, + struct netlink_ext_ack *extack) +{ + struct an8855_priv *priv = ds->priv; + int ret; + + ret = an8855_update_port_member(ds, port, bridge.dev, true); + if (ret) + return ret; + + /* Set to fallback mode for independent VLAN learning if in a bridge */ + return regmap_update_bits(priv->regmap, AN8855_PCR_P(port), + AN8855_PORT_VLAN, + FIELD_PREP(AN8855_PORT_VLAN, + AN8855_PORT_FALLBACK_MODE)); +} + +static void an8855_port_bridge_leave(struct dsa_switch *ds, int port, + struct dsa_bridge bridge) +{ + struct an8855_priv *priv = ds->priv; + + an8855_update_port_member(ds, port, bridge.dev, false); + + /* When a port is removed from the bridge, the port would be set up + * back to the default as is at initial boot which is a VLAN-unaware + * port. + */ + regmap_update_bits(priv->regmap, AN8855_PCR_P(port), + AN8855_PORT_VLAN, + FIELD_PREP(AN8855_PORT_VLAN, + AN8855_PORT_MATRIX_MODE)); +} + +static int an8855_port_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + struct an8855_priv *priv = ds->priv; + u8 port_mask = BIT(port); + int ret; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = AN8855_PORT_VID_DEFAULT; + + mutex_lock(&priv->reg_mutex); + an8855_fdb_write(priv, vid, port_mask, addr, true); + ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +static int an8855_port_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + struct an8855_priv *priv = ds->priv; + u8 port_mask = BIT(port); + int ret; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = AN8855_PORT_VID_DEFAULT; + + mutex_lock(&priv->reg_mutex); + an8855_fdb_write(priv, vid, port_mask, addr, false); + ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +static int an8855_port_fdb_dump(struct dsa_switch *ds, int port, + dsa_fdb_dump_cb_t *cb, void *data) +{ + struct an8855_priv *priv = ds->priv; + int banks, count = 0; + u32 rsp; + int ret; + int i; + + mutex_lock(&priv->reg_mutex); + + /* Load search port */ + ret = regmap_write(priv->regmap, AN8855_ATWD2, + FIELD_PREP(AN8855_ATWD2_PORT, BIT(port))); + if (ret) + goto exit; + ret = an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_PORT) | + AN8855_FDB_START, &rsp); + if (ret < 0) + goto exit; + + do { + /* From response get the number of banks to read, exit if 0 */ + banks = FIELD_GET(AN8855_ATC_HIT, rsp); + if (!banks) + break; + + /* Each banks have 4 entry */ + for (i = 0; i < 4; i++) { + struct an8855_fdb _fdb = { }; + + count++; + + /* Check if bank is present */ + if (!(banks & BIT(i))) + continue; + + /* Select bank entry index */ + ret = regmap_write(priv->regmap, AN8855_ATRDS, + FIELD_PREP(AN8855_ATRD_SEL, i)); + if (ret) + break; + /* wait 1ms for the bank entry to be filled */ + usleep_range(1000, 1500); + an8855_fdb_read(priv, &_fdb); + + if (!_fdb.live) + continue; + ret = cb(_fdb.mac, _fdb.vid, _fdb.noarp, data); + if (ret < 0) + break; + } + + /* Stop if reached max FDB number */ + if (count >= AN8855_NUM_FDB_RECORDS) + break; + + /* Read next bank */ + ret = an8855_fdb_cmd(priv, AN8855_ATC_MAT(AND8855_FDB_MAT_MAC_PORT) | + AN8855_FDB_NEXT, &rsp); + if (ret < 0) + break; + } while (true); + +exit: + mutex_unlock(&priv->reg_mutex); + return ret; +} + +static int an8855_vlan_cmd(struct an8855_priv *priv, enum an8855_vlan_cmd cmd, + u16 vid) __must_hold(&priv->reg_mutex) +{ + u32 val; + int ret; + + val = AN8855_VTCR_BUSY | FIELD_PREP(AN8855_VTCR_FUNC, cmd) | + FIELD_PREP(AN8855_VTCR_VID, vid); + ret = regmap_write(priv->regmap, AN8855_VTCR, val); + if (ret) + return ret; + + return regmap_read_poll_timeout(priv->regmap, AN8855_VTCR, val, + !(val & AN8855_VTCR_BUSY), 20, 200000); +} + +static int an8855_vlan_add(struct an8855_priv *priv, u8 port, u16 vid, + bool untagged) __must_hold(&priv->reg_mutex) +{ + u32 port_mask; + u32 val; + int ret; + + /* Fetch entry */ + ret = an8855_vlan_cmd(priv, AN8855_VTCR_RD_VID, vid); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, AN8855_VARD0, &val); + if (ret) + return ret; + port_mask = FIELD_GET(AN8855_VA0_PORT, val) | BIT(port); + + /* Validate the entry with independent learning, create egress tag per + * VLAN and joining the port as one of the port members. + */ + val = (val & AN8855_VA0_ETAG) | AN8855_VA0_IVL_MAC | + AN8855_VA0_VTAG_EN | AN8855_VA0_VLAN_VALID | + FIELD_PREP(AN8855_VA0_PORT, port_mask) | + FIELD_PREP(AN8855_VA0_FID, AN8855_FID_BRIDGED); + ret = regmap_write(priv->regmap, AN8855_VAWD0, val); + if (ret) + return ret; + ret = regmap_write(priv->regmap, AN8855_VAWD1, 0); + if (ret) + return ret; + + /* CPU port is always taken as a tagged port for serving more than one + * VLANs across and also being applied with egress type stack mode for + * that VLAN tags would be appended after hardware special tag used as + * DSA tag. + */ + if (port == AN8855_CPU_PORT) + val = AN8855_VLAN_EGRESS_STACK; + /* Decide whether adding tag or not for those outgoing packets from the + * port inside the VLAN. + */ + else + val = untagged ? AN8855_VLAN_EGRESS_UNTAG : AN8855_VLAN_EGRESS_TAG; + ret = regmap_update_bits(priv->regmap, AN8855_VAWD0, + AN8855_VA0_ETAG_PORT_MASK(port), + AN8855_VA0_ETAG_PORT_VAL(port, val)); + if (ret) + return ret; + + /* Flush result to hardware */ + return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, vid); +} + +static int an8855_vlan_del(struct an8855_priv *priv, u8 port, + u16 vid) __must_hold(&priv->reg_mutex) +{ + u32 port_mask; + u32 val; + int ret; + + /* Fetch entry */ + ret = an8855_vlan_cmd(priv, AN8855_VTCR_RD_VID, vid); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, AN8855_VARD0, &val); + if (ret) + return ret; + port_mask = FIELD_GET(AN8855_VA0_PORT, val) & ~BIT(port); + + if (!(val & AN8855_VA0_VLAN_VALID)) { + dev_err(priv->dev, "Cannot be deleted due to invalid entry\n"); + return -EINVAL; + } + + if (port_mask) { + val = (val & AN8855_VA0_ETAG) | AN8855_VA0_IVL_MAC | + AN8855_VA0_VTAG_EN | AN8855_VA0_VLAN_VALID | + FIELD_PREP(AN8855_VA0_PORT, port_mask); + ret = regmap_write(priv->regmap, AN8855_VAWD0, val); + if (ret) + return ret; + } else { + ret = regmap_write(priv->regmap, AN8855_VAWD0, 0); + if (ret) + return ret; + } + ret = regmap_write(priv->regmap, AN8855_VAWD1, 0); + if (ret) + return ret; + + /* Flush result to hardware */ + return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, vid); +} + +static int an8855_port_set_vlan_mode(struct an8855_priv *priv, int port, + enum an8855_port_mode port_mode, + enum an8855_vlan_port_eg_tag eg_tag, + enum an8855_vlan_port_attr vlan_attr, + enum an8855_vlan_port_acc_frm acc_frm) +{ + int ret; + + ret = regmap_update_bits(priv->regmap, AN8855_PCR_P(port), + AN8855_PORT_VLAN, + FIELD_PREP(AN8855_PORT_VLAN, port_mode)); + if (ret) + return ret; + + return regmap_update_bits(priv->regmap, AN8855_PVC_P(port), + AN8855_PVC_EG_TAG | AN8855_VLAN_ATTR | AN8855_ACC_FRM, + FIELD_PREP(AN8855_PVC_EG_TAG, eg_tag) | + FIELD_PREP(AN8855_VLAN_ATTR, vlan_attr) | + FIELD_PREP(AN8855_ACC_FRM, acc_frm)); +} + +static int an8855_port_set_pid(struct an8855_priv *priv, int port, + u16 pid) +{ + int ret; + + ret = regmap_update_bits(priv->regmap, AN8855_PPBV1_P(port), + AN8855_PPBV_G0_PORT_VID, + FIELD_PREP(AN8855_PPBV_G0_PORT_VID, pid)); + if (ret) + return ret; + + return regmap_update_bits(priv->regmap, AN8855_PVID_P(port), + AN8855_G0_PORT_VID, + FIELD_PREP(AN8855_G0_PORT_VID, pid)); +} + +static int an8855_port_vlan_filtering(struct dsa_switch *ds, int port, + bool vlan_filtering, + struct netlink_ext_ack *extack) +{ + struct an8855_priv *priv = ds->priv; + u32 val; + int ret; + + /* The port is being kept as VLAN-unaware port when bridge is + * set up with vlan_filtering not being set, Otherwise, the + * port and the corresponding CPU port is required the setup + * for becoming a VLAN-aware port. + */ + if (vlan_filtering) { + u32 acc_frm; + /* CPU port is set to fallback mode to let untagged + * frames pass through. + */ + ret = an8855_port_set_vlan_mode(priv, AN8855_CPU_PORT, + AN8855_PORT_FALLBACK_MODE, + AN8855_VLAN_EG_CONSISTENT, + AN8855_VLAN_USER, + AN8855_VLAN_ACC_ALL); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); + if (ret) + return ret; + + /* Only accept tagged frames if PVID is not set */ + if (FIELD_GET(AN8855_G0_PORT_VID, val) != AN8855_PORT_VID_DEFAULT) + acc_frm = AN8855_VLAN_ACC_TAGGED; + else + acc_frm = AN8855_VLAN_ACC_ALL; + + /* Trapped into security mode allows packet forwarding through VLAN + * table lookup. + * Set the port as a user port which is to be able to recognize VID + * from incoming packets before fetching entry within the VLAN table. + */ + ret = an8855_port_set_vlan_mode(priv, port, + AN8855_PORT_SECURITY_MODE, + AN8855_VLAN_EG_DISABLED, + AN8855_VLAN_USER, + acc_frm); + if (ret) + return ret; + } else { + bool disable_cpu_vlan = true; + struct dsa_port *dp; + u32 port_mode; + + /* This is called after .port_bridge_leave when leaving a VLAN-aware + * bridge. Don't set standalone ports to fallback mode. + */ + if (dsa_port_bridge_dev_get(dsa_to_port(ds, port))) + port_mode = AN8855_PORT_FALLBACK_MODE; + else + port_mode = AN8855_PORT_MATRIX_MODE; + + /* When a port is removed from the bridge, the port would be set up + * back to the default as is at initial boot which is a VLAN-unaware + * port. + */ + ret = an8855_port_set_vlan_mode(priv, port, port_mode, + AN8855_VLAN_EG_CONSISTENT, + AN8855_VLAN_TRANSPARENT, + AN8855_VLAN_ACC_ALL); + if (ret) + return ret; + + /* Restore default PVID */ + ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); + if (ret) + return ret; + + dsa_switch_for_each_user_port(dp, ds) { + if (dsa_port_is_vlan_filtering(dp)) { + disable_cpu_vlan = false; + break; + } + } + + if (disable_cpu_vlan) { + ret = an8855_port_set_vlan_mode(priv, AN8855_CPU_PORT, + AN8855_PORT_MATRIX_MODE, + AN8855_VLAN_EG_CONSISTENT, + AN8855_VLAN_USER, + AN8855_VLAN_ACC_ALL); + if (ret) + return ret; + } + } + + return 0; +} + +static int an8855_port_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +{ + bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct an8855_priv *priv = ds->priv; + u32 val; + int ret; + + mutex_lock(&priv->reg_mutex); + ret = an8855_vlan_add(priv, port, vlan->vid, untagged); + mutex_unlock(&priv->reg_mutex); + if (ret) + return ret; + + if (pvid) { + /* Accept all frames if PVID is set */ + regmap_update_bits(priv->regmap, AN8855_PVC_P(port), AN8855_ACC_FRM, + FIELD_PREP(AN8855_ACC_FRM, AN8855_VLAN_ACC_ALL)); + + /* Only configure PVID if VLAN filtering is enabled */ + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { + ret = an8855_port_set_pid(priv, port, vlan->vid); + if (ret) + return ret; + } + } else if (vlan->vid) { + ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); + if (ret) + return ret; + + if (FIELD_GET(AN8855_G0_PORT_VID, val) != vlan->vid) + return 0; + + /* This VLAN is overwritten without PVID, so unset it */ + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { + ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(port), + AN8855_ACC_FRM, + FIELD_PREP(AN8855_ACC_FRM, + AN8855_VLAN_ACC_TAGGED)); + if (ret) + return ret; + } + + ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); + if (ret) + return ret; + } + + return 0; +} + +static int an8855_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct an8855_priv *priv = ds->priv; + u32 val; + int ret; + + mutex_lock(&priv->reg_mutex); + ret = an8855_vlan_del(priv, port, vlan->vid); + mutex_unlock(&priv->reg_mutex); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, AN8855_PVID_P(port), &val); + if (ret) + return ret; + + /* PVID is being restored to the default whenever the PVID port + * is being removed from the VLAN. + */ + if (FIELD_GET(AN8855_G0_PORT_VID, val) == vlan->vid) { + /* Only accept tagged frames if the port is VLAN-aware */ + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { + ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(port), + AN8855_ACC_FRM, + FIELD_PREP(AN8855_ACC_FRM, + AN8855_VLAN_ACC_TAGGED)); + if (ret) + return ret; + } + + ret = an8855_port_set_pid(priv, port, AN8855_PORT_VID_DEFAULT); + if (ret) + return ret; + } + + return 0; +} + +static int +an8855_port_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) +{ + struct an8855_priv *priv = ds->priv; + const u8 *addr = mdb->addr; + u16 vid = mdb->vid; + u8 port_mask = 0; + u32 val; + int ret; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = AN8855_PORT_VID_DEFAULT; + + mutex_lock(&priv->reg_mutex); + + an8855_fdb_write(priv, vid, 0, addr, false); + if (!an8855_fdb_cmd(priv, AN8855_FDB_READ, NULL)) { + ret = regmap_read(priv->regmap, AN8855_ATRD3, &val); + if (ret) + goto exit; + + port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, val); + } + + port_mask |= BIT(port); + an8855_fdb_write(priv, vid, port_mask, addr, true); + ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); + +exit: + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +static int +an8855_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb, + struct dsa_db db) +{ + struct an8855_priv *priv = ds->priv; + const u8 *addr = mdb->addr; + u16 vid = mdb->vid; + u8 port_mask = 0; + u32 val; + int ret; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = AN8855_PORT_VID_DEFAULT; + + mutex_lock(&priv->reg_mutex); + + an8855_fdb_write(priv, vid, 0, addr, 0); + if (!an8855_fdb_cmd(priv, AN8855_FDB_READ, NULL)) { + ret = regmap_read(priv->regmap, AN8855_ATRD3, &val); + if (ret) + goto exit; + + port_mask = FIELD_GET(AN8855_ATRD3_PORTMASK, val); + } + + port_mask &= ~BIT(port); + an8855_fdb_write(priv, vid, port_mask, addr, port_mask ? true : false); + ret = an8855_fdb_cmd(priv, AN8855_FDB_WRITE, NULL); + +exit: + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +static int +an8855_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +{ + struct an8855_priv *priv = ds->priv; + int length; + u32 val; + + /* When a new MTU is set, DSA always set the CPU port's MTU to the + * largest MTU of the slave ports. Because the switch only has a global + * RX length register, only allowing CPU port here is enough. + */ + if (!dsa_is_cpu_port(ds, port)) + return 0; + + /* RX length also includes Ethernet header, MTK tag, and FCS length */ + length = new_mtu + ETH_HLEN + MTK_TAG_LEN + ETH_FCS_LEN; + if (length <= 1522) + val = AN8855_MAX_RX_PKT_1518_1522; + else if (length <= 1536) + val = AN8855_MAX_RX_PKT_1536; + else if (length <= 1552) + val = AN8855_MAX_RX_PKT_1552; + else if (length <= 3072) + val = AN8855_MAX_RX_JUMBO_3K; + else if (length <= 4096) + val = AN8855_MAX_RX_JUMBO_4K; + else if (length <= 5120) + val = AN8855_MAX_RX_JUMBO_5K; + else if (length <= 6144) + val = AN8855_MAX_RX_JUMBO_6K; + else if (length <= 7168) + val = AN8855_MAX_RX_JUMBO_7K; + else if (length <= 8192) + val = AN8855_MAX_RX_JUMBO_8K; + else if (length <= 9216) + val = AN8855_MAX_RX_JUMBO_9K; + else if (length <= 12288) + val = AN8855_MAX_RX_JUMBO_12K; + else if (length <= 15360) + val = AN8855_MAX_RX_JUMBO_15K; + else + val = AN8855_MAX_RX_JUMBO_16K; + + /* Enable JUMBO packet */ + if (length > 1552) + val |= AN8855_MAX_RX_PKT_JUMBO; + + return regmap_update_bits(priv->regmap, AN8855_GMACCR, + AN8855_MAX_RX_JUMBO | AN8855_MAX_RX_PKT_LEN, + val); +} + +static int +an8855_port_max_mtu(struct dsa_switch *ds, int port) +{ + return AN8855_MAX_MTU; +} + +static void +an8855_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t *data) +{ + int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(an8855_mib); i++) + ethtool_puts(&data, an8855_mib[i].name); +} + +static void +an8855_read_port_stats(struct an8855_priv *priv, int port, u32 offset, u8 size, + uint64_t *data) +{ + u32 val, reg = AN8855_PORT_MIB_COUNTER(port) + offset; + + regmap_read(priv->regmap, reg, &val); + *data = val; + + if (size == 2) { + regmap_read(priv->regmap, reg + 4, &val); + *data |= (u64)val << 32; + } +} + +static void +an8855_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) +{ + struct an8855_priv *priv = ds->priv; + const struct an8855_mib_desc *mib; + int i; + + for (i = 0; i < ARRAY_SIZE(an8855_mib); i++) { + mib = &an8855_mib[i]; + + an8855_read_port_stats(priv, port, mib->offset, mib->size, + data + i); + } +} + +static int +an8855_get_sset_count(struct dsa_switch *ds, int port, int sset) +{ + if (sset != ETH_SS_STATS) + return 0; + + return ARRAY_SIZE(an8855_mib); +} + +static void +an8855_get_eth_mac_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct an8855_priv *priv = ds->priv; + + /* MIB counter doesn't provide a FramesTransmittedOK but instead + * provide stats for Unicast, Broadcast and Multicast frames separately. + * To simulate a global frame counter, read Unicast and addition Multicast + * and Broadcast later + */ + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_UNICAST, 1, + &mac_stats->FramesTransmittedOK); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_SINGLE_COLLISION, 1, + &mac_stats->SingleCollisionFrames); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_MULTIPLE_COLLISION, 1, + &mac_stats->MultipleCollisionFrames); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_UNICAST, 1, + &mac_stats->FramesReceivedOK); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_BYTES, 2, + &mac_stats->OctetsTransmittedOK); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_ALIGN_ERR, 1, + &mac_stats->AlignmentErrors); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_DEFERRED, 1, + &mac_stats->FramesWithDeferredXmissions); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_LATE_COLLISION, 1, + &mac_stats->LateCollisions); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_EXCESSIVE_COLLISION, 1, + &mac_stats->FramesAbortedDueToXSColls); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_BYTES, 2, + &mac_stats->OctetsReceivedOK); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_MULTICAST, 1, + &mac_stats->MulticastFramesXmittedOK); + mac_stats->FramesTransmittedOK += mac_stats->MulticastFramesXmittedOK; + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_BROADCAST, 1, + &mac_stats->BroadcastFramesXmittedOK); + mac_stats->FramesTransmittedOK += mac_stats->BroadcastFramesXmittedOK; + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_MULTICAST, 1, + &mac_stats->MulticastFramesReceivedOK); + mac_stats->FramesReceivedOK += mac_stats->MulticastFramesReceivedOK; + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_BROADCAST, 1, + &mac_stats->BroadcastFramesReceivedOK); + mac_stats->FramesReceivedOK += mac_stats->BroadcastFramesReceivedOK; +} + +static const struct ethtool_rmon_hist_range an8855_rmon_ranges[] = { + { 0, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, AN8855_MAX_MTU }, + {} +}; + +static void an8855_get_rmon_stats(struct dsa_switch *ds, int port, + struct ethtool_rmon_stats *rmon_stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct an8855_priv *priv = ds->priv; + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_UNDER_SIZE_ERR, 1, + &rmon_stats->undersize_pkts); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_OVER_SZ_ERR, 1, + &rmon_stats->oversize_pkts); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_FRAG_ERR, 1, + &rmon_stats->fragments); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_JABBER_ERR, 1, + &rmon_stats->jabbers); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_64, 1, + &rmon_stats->hist[0]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_65_TO_127, 1, + &rmon_stats->hist[1]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_128_TO_255, 1, + &rmon_stats->hist[2]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_256_TO_511, 1, + &rmon_stats->hist[3]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_512_TO_1023, 1, + &rmon_stats->hist[4]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_1024_TO_1518, 1, + &rmon_stats->hist[5]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PKT_SZ_1519_TO_MAX, 1, + &rmon_stats->hist[6]); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_64, 1, + &rmon_stats->hist_tx[0]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_65_TO_127, 1, + &rmon_stats->hist_tx[1]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_128_TO_255, 1, + &rmon_stats->hist_tx[2]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_256_TO_511, 1, + &rmon_stats->hist_tx[3]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_512_TO_1023, 1, + &rmon_stats->hist_tx[4]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_1024_TO_1518, 1, + &rmon_stats->hist_tx[5]); + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PKT_SZ_1519_TO_MAX, 1, + &rmon_stats->hist_tx[6]); + + *ranges = an8855_rmon_ranges; +} + +static void an8855_get_eth_ctrl_stats(struct dsa_switch *ds, int port, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct an8855_priv *priv = ds->priv; + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_TX_PAUSE, 1, + &ctrl_stats->MACControlFramesTransmitted); + + an8855_read_port_stats(priv, port, AN8855_PORT_MIB_RX_PAUSE, 1, + &ctrl_stats->MACControlFramesReceived); +} + +static int an8855_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress, + struct netlink_ext_ack *extack) +{ + struct an8855_priv *priv = ds->priv; + int monitor_port; + u32 val; + int ret; + + /* Check for existent entry */ + if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) + return -EEXIST; + + ret = regmap_read(priv->regmap, AN8855_MIR, &val); + if (ret) + return ret; + + /* AN8855 supports 4 monitor port, but only use first group */ + monitor_port = FIELD_GET(AN8855_MIRROR_PORT, val); + if (val & AN8855_MIRROR_EN && monitor_port != mirror->to_local_port) + return -EEXIST; + + val = AN8855_MIRROR_EN; + val |= FIELD_PREP(AN8855_MIRROR_PORT, mirror->to_local_port); + ret = regmap_update_bits(priv->regmap, AN8855_MIR, + AN8855_MIRROR_EN | AN8855_MIRROR_PORT, + val); + if (ret) + return ret; + + ret = regmap_set_bits(priv->regmap, AN8855_PCR_P(port), + ingress ? AN8855_PORT_RX_MIR : AN8855_PORT_TX_MIR); + if (ret) + return ret; + + if (ingress) + priv->mirror_rx |= BIT(port); + else + priv->mirror_tx |= BIT(port); + + return 0; +} + +static void an8855_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + struct an8855_priv *priv = ds->priv; + + if (mirror->ingress) + priv->mirror_rx &= ~BIT(port); + else + priv->mirror_tx &= ~BIT(port); + + regmap_clear_bits(priv->regmap, AN8855_PCR_P(port), + mirror->ingress ? AN8855_PORT_RX_MIR : + AN8855_PORT_TX_MIR); + + if (!priv->mirror_rx && !priv->mirror_tx) + regmap_clear_bits(priv->regmap, AN8855_MIR, AN8855_MIRROR_EN); +} + +static int an8855_port_set_status(struct an8855_priv *priv, int port, + bool enable) +{ + if (enable) + return regmap_set_bits(priv->regmap, AN8855_PMCR_P(port), + AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); + else + return regmap_clear_bits(priv->regmap, AN8855_PMCR_P(port), + AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); +} + +static int an8855_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + return an8855_port_set_status(ds->priv, port, true); +} + +static void an8855_port_disable(struct dsa_switch *ds, int port) +{ + an8855_port_set_status(ds->priv, port, false); +} + +static u32 en8855_get_phy_flags(struct dsa_switch *ds, int port) +{ + struct an8855_priv *priv = ds->priv; + + /* PHY doesn't need calibration */ + if (!priv->phy_require_calib) + return 0; + + /* Use AN8855_PHY_FLAGS_EN_CALIBRATION to signal + * calibration needed. + */ + return AN8855_PHY_FLAGS_EN_CALIBRATION; +} + +static enum dsa_tag_protocol +an8855_get_tag_protocol(struct dsa_switch *ds, int port, + enum dsa_tag_protocol mp) +{ + return DSA_TAG_PROTO_MTK; +} + +/* Similar to MT7530 also trap link local frame and special frame to CPU */ +static int an8855_trap_special_frames(struct an8855_priv *priv) +{ + int ret; + + /* Trap BPDUs to the CPU port(s) and egress them + * VLAN-untagged. + */ + ret = regmap_update_bits(priv->regmap, AN8855_BPC, + AN8855_BPDU_BPDU_FR | AN8855_BPDU_EG_TAG | + AN8855_BPDU_PORT_FW, + AN8855_BPDU_BPDU_FR | + FIELD_PREP(AN8855_BPDU_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_BPDU_PORT_FW, AN8855_BPDU_CPU_ONLY)); + if (ret) + return ret; + + /* Trap 802.1X PAE frames to the CPU port(s) and egress them + * VLAN-untagged. + */ + ret = regmap_update_bits(priv->regmap, AN8855_PAC, + AN8855_PAE_BPDU_FR | AN8855_PAE_EG_TAG | + AN8855_PAE_PORT_FW, + AN8855_PAE_BPDU_FR | + FIELD_PREP(AN8855_PAE_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_PAE_PORT_FW, AN8855_BPDU_CPU_ONLY)); + if (ret) + return ret; + + /* Trap frames with :01 MAC DAs to the CPU port(s) and egress + * them VLAN-untagged. + */ + ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, + AN8855_R01_BPDU_FR | AN8855_R01_EG_TAG | + AN8855_R01_PORT_FW, + AN8855_R01_BPDU_FR | + FIELD_PREP(AN8855_R01_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_R01_PORT_FW, AN8855_BPDU_CPU_ONLY)); + if (ret) + return ret; + + /* Trap frames with :02 MAC DAs to the CPU port(s) and egress + * them VLAN-untagged. + */ + ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, + AN8855_R02_BPDU_FR | AN8855_R02_EG_TAG | + AN8855_R02_PORT_FW, + AN8855_R02_BPDU_FR | + FIELD_PREP(AN8855_R02_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_R02_PORT_FW, AN8855_BPDU_CPU_ONLY)); + if (ret) + return ret; + + /* Trap frames with :03 MAC DAs to the CPU port(s) and egress + * them VLAN-untagged. + */ + ret = regmap_update_bits(priv->regmap, AN8855_RGAC1, + AN8855_R03_BPDU_FR | AN8855_R03_EG_TAG | + AN8855_R03_PORT_FW, + AN8855_R03_BPDU_FR | + FIELD_PREP(AN8855_R03_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_R03_PORT_FW, AN8855_BPDU_CPU_ONLY)); + if (ret) + return ret; + + /* Trap frames with :0E MAC DAs to the CPU port(s) and egress + * them VLAN-untagged. + */ + return regmap_update_bits(priv->regmap, AN8855_RGAC1, + AN8855_R0E_BPDU_FR | AN8855_R0E_EG_TAG | + AN8855_R0E_PORT_FW, + AN8855_R0E_BPDU_FR | + FIELD_PREP(AN8855_R0E_EG_TAG, AN8855_VLAN_EG_UNTAGGED) | + FIELD_PREP(AN8855_R0E_PORT_FW, AN8855_BPDU_CPU_ONLY)); +} + +static int +an8855_setup_pvid_vlan(struct an8855_priv *priv) +{ + u32 val; + int ret; + + /* Validate the entry with independent learning, keep the original + * ingress tag attribute. + */ + val = AN8855_VA0_IVL_MAC | AN8855_VA0_EG_CON | + FIELD_PREP(AN8855_VA0_FID, AN8855_FID_BRIDGED) | + AN8855_VA0_PORT | AN8855_VA0_VLAN_VALID; + ret = regmap_write(priv->regmap, AN8855_VAWD0, val); + if (ret) + return ret; + + return an8855_vlan_cmd(priv, AN8855_VTCR_WR_VID, + AN8855_PORT_VID_DEFAULT); +} + +static int an8855_setup(struct dsa_switch *ds) +{ + struct an8855_priv *priv = ds->priv; + struct dsa_port *dp; + int ret; + + /* Enable and reset MIB counters */ + ret = an8855_mib_init(priv); + if (ret) + return ret; + + dsa_switch_for_each_user_port(dp, ds) { + /* Disable MAC by default on all user ports */ + ret = an8855_port_set_status(priv, dp->index, false); + if (ret) + return ret; + + /* Individual user ports get connected to CPU port only */ + ret = regmap_write(priv->regmap, AN8855_PORTMATRIX_P(dp->index), + FIELD_PREP(AN8855_PORTMATRIX, BIT(AN8855_CPU_PORT))); + if (ret) + return ret; + + /* Disable Broadcast Forward on user ports */ + ret = regmap_clear_bits(priv->regmap, AN8855_BCF, BIT(dp->index)); + if (ret) + return ret; + + /* Disable Unknown Unicast Forward on user ports */ + ret = regmap_clear_bits(priv->regmap, AN8855_UNUF, BIT(dp->index)); + if (ret) + return ret; + + /* Disable Unknown Multicast Forward on user ports */ + ret = regmap_clear_bits(priv->regmap, AN8855_UNMF, BIT(dp->index)); + if (ret) + return ret; + + ret = regmap_clear_bits(priv->regmap, AN8855_UNIPMF, BIT(dp->index)); + if (ret) + return ret; + + /* Set default PVID to on all user ports */ + ret = an8855_port_set_pid(priv, dp->index, AN8855_PORT_VID_DEFAULT); + if (ret) + return ret; + } + + /* Enable Airoha header mode on the cpu port */ + ret = regmap_write(priv->regmap, AN8855_PVC_P(AN8855_CPU_PORT), + AN8855_PORT_SPEC_REPLACE_MODE | AN8855_PORT_SPEC_TAG); + if (ret) + return ret; + + /* Unknown multicast frame forwarding to the cpu port */ + ret = regmap_write(priv->regmap, AN8855_UNMF, BIT(AN8855_CPU_PORT)); + if (ret) + return ret; + + /* Set CPU port number */ + ret = regmap_update_bits(priv->regmap, AN8855_MFC, + AN8855_CPU_EN | AN8855_CPU_PORT_IDX, + AN8855_CPU_EN | + FIELD_PREP(AN8855_CPU_PORT_IDX, AN8855_CPU_PORT)); + if (ret) + return ret; + + /* CPU port gets connected to all user ports of + * the switch. + */ + ret = regmap_write(priv->regmap, AN8855_PORTMATRIX_P(AN8855_CPU_PORT), + FIELD_PREP(AN8855_PORTMATRIX, dsa_user_ports(ds))); + if (ret) + return ret; + + /* CPU port is set to fallback mode to let untagged + * frames pass through. + */ + ret = regmap_update_bits(priv->regmap, AN8855_PCR_P(AN8855_CPU_PORT), + AN8855_PORT_VLAN, + FIELD_PREP(AN8855_PORT_VLAN, AN8855_PORT_FALLBACK_MODE)); + if (ret) + return ret; + + /* Enable Broadcast Forward on CPU port */ + ret = regmap_set_bits(priv->regmap, AN8855_BCF, BIT(AN8855_CPU_PORT)); + if (ret) + return ret; + + /* Enable Unknown Unicast Forward on CPU port */ + ret = regmap_set_bits(priv->regmap, AN8855_UNUF, BIT(AN8855_CPU_PORT)); + if (ret) + return ret; + + /* Enable Unknown Multicast Forward on CPU port */ + ret = regmap_set_bits(priv->regmap, AN8855_UNMF, BIT(AN8855_CPU_PORT)); + if (ret) + return ret; + + ret = regmap_set_bits(priv->regmap, AN8855_UNIPMF, BIT(AN8855_CPU_PORT)); + if (ret) + return ret; + + /* Setup Trap special frame to CPU rules */ + ret = an8855_trap_special_frames(priv); + if (ret) + return ret; + + dsa_switch_for_each_port(dp, ds) { + /* Disable Learning on all ports. + * Learning on CPU is disabled for fdb isolation and handled by + * assisted_learning_on_cpu_port. + */ + ret = regmap_set_bits(priv->regmap, AN8855_PSC_P(dp->index), + AN8855_SA_DIS); + if (ret) + return ret; + + /* Enable consistent egress tag (for VLAN unware VLAN-passtrough) */ + ret = regmap_update_bits(priv->regmap, AN8855_PVC_P(dp->index), + AN8855_PVC_EG_TAG, + FIELD_PREP(AN8855_PVC_EG_TAG, AN8855_VLAN_EG_CONSISTENT)); + if (ret) + return ret; + } + + /* Setup VLAN for Default PVID */ + ret = an8855_setup_pvid_vlan(priv); + if (ret) + return ret; + + ret = regmap_clear_bits(priv->regmap, AN8855_CKGCR, + AN8855_CKG_LNKDN_GLB_STOP | AN8855_CKG_LNKDN_PORT_STOP); + if (ret) + return ret; + + /* Release global PHY power down */ + ret = regmap_write(priv->regmap, AN8855_RG_GPHY_AFE_PWD, 0x0); + if (ret) + return ret; + + ds->configure_vlan_while_not_filtering = true; + + /* Flush the FDB table */ + ret = an8855_fdb_cmd(priv, AN8855_FDB_FLUSH, NULL); + if (ret < 0) + return ret; + + /* Set min a max ageing value supported */ + ds->ageing_time_min = AN8855_L2_AGING_MS_CONSTANT; + ds->ageing_time_max = FIELD_MAX(AN8855_AGE_CNT) * + FIELD_MAX(AN8855_AGE_UNIT) * + AN8855_L2_AGING_MS_CONSTANT; + + /* Enable assisted learning for fdb isolation */ + ds->assisted_learning_on_cpu_port = true; + + return 0; +} + +static struct phylink_pcs *an8855_phylink_mac_select_pcs(struct phylink_config *config, + phy_interface_t interface) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct an8855_priv *priv = dp->ds->priv; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + return &priv->pcs; + default: + return NULL; + } +} + +static void an8855_phylink_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct dsa_switch *ds = dp->ds; + struct an8855_priv *priv; + int port = dp->index; + + priv = ds->priv; + + /* Nothing to configure for internal ports */ + if (port != 5) + return; + + regmap_update_bits(priv->regmap, AN8855_PMCR_P(port), + AN8855_PMCR_IFG_XMIT | AN8855_PMCR_MAC_MODE | + AN8855_PMCR_BACKOFF_EN | AN8855_PMCR_BACKPR_EN, + FIELD_PREP(AN8855_PMCR_IFG_XMIT, 0x1) | + AN8855_PMCR_MAC_MODE | AN8855_PMCR_BACKOFF_EN | + AN8855_PMCR_BACKPR_EN); +} + +static void an8855_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) +{ + switch (port) { + case 0: + case 1: + case 2: + case 3: + case 4: + __set_bit(PHY_INTERFACE_MODE_GMII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + break; + case 5: + phy_interface_set_rgmii(config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, + config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + config->supported_interfaces); + break; + } + + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; +} + +static void an8855_phylink_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct an8855_priv *priv = dp->ds->priv; + + /* With autoneg just disable TX/RX else also force link down */ + if (phylink_autoneg_inband(mode)) { + regmap_clear_bits(priv->regmap, AN8855_PMCR_P(dp->index), + AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN); + } else { + regmap_update_bits(priv->regmap, AN8855_PMCR_P(dp->index), + AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN | + AN8855_PMCR_FORCE_MODE | AN8855_PMCR_FORCE_LNK, + AN8855_PMCR_FORCE_MODE); + } +} + +static void an8855_phylink_mac_link_up(struct phylink_config *config, + struct phy_device *phydev, unsigned int mode, + phy_interface_t interface, int speed, + int duplex, bool tx_pause, bool rx_pause) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct an8855_priv *priv = dp->ds->priv; + int port = dp->index; + u32 reg; + + reg = regmap_read(priv->regmap, AN8855_PMCR_P(port), ®); + if (phylink_autoneg_inband(mode)) { + reg &= ~AN8855_PMCR_FORCE_MODE; + } else { + reg |= AN8855_PMCR_FORCE_MODE | AN8855_PMCR_FORCE_LNK; + + reg &= ~AN8855_PMCR_FORCE_SPEED; + switch (speed) { + case SPEED_10: + reg |= AN8855_PMCR_FORCE_SPEED_10; + break; + case SPEED_100: + reg |= AN8855_PMCR_FORCE_SPEED_100; + break; + case SPEED_1000: + reg |= AN8855_PMCR_FORCE_SPEED_1000; + break; + case SPEED_2500: + reg |= AN8855_PMCR_FORCE_SPEED_2500; + break; + case SPEED_5000: + dev_err(priv->dev, "Missing support for 5G speed. Aborting...\n"); + return; + } + + reg &= ~AN8855_PMCR_FORCE_FDX; + if (duplex == DUPLEX_FULL) + reg |= AN8855_PMCR_FORCE_FDX; + + reg &= ~AN8855_PMCR_RX_FC_EN; + if (rx_pause || dsa_port_is_cpu(dp)) + reg |= AN8855_PMCR_RX_FC_EN; + + reg &= ~AN8855_PMCR_TX_FC_EN; + if (rx_pause || dsa_port_is_cpu(dp)) + reg |= AN8855_PMCR_TX_FC_EN; + + /* Disable any EEE options */ + reg &= ~(AN8855_PMCR_FORCE_EEE5G | AN8855_PMCR_FORCE_EEE2P5G | + AN8855_PMCR_FORCE_EEE1G | AN8855_PMCR_FORCE_EEE100); + } + + reg |= AN8855_PMCR_TX_EN | AN8855_PMCR_RX_EN; + + regmap_write(priv->regmap, AN8855_PMCR_P(port), reg); +} + +static unsigned int an8855_pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + /* SGMII can be configured to use inband with AN result */ + if (interface == PHY_INTERFACE_MODE_SGMII) + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + /* inband is not supported in 2500-baseX and must be disabled */ + return LINK_INBAND_DISABLE; +} + +static void an8855_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct an8855_priv *priv = container_of(pcs, struct an8855_priv, pcs); + u32 val; + int ret; + + ret = regmap_read(priv->regmap, AN8855_PMSR_P(AN8855_CPU_PORT), &val); + if (ret < 0) { + state->link = false; + return; + } + + state->link = !!(val & AN8855_PMSR_LNK); + state->an_complete = state->link; + state->duplex = (val & AN8855_PMSR_DPX) ? DUPLEX_FULL : + DUPLEX_HALF; + + switch (val & AN8855_PMSR_SPEED) { + case AN8855_PMSR_SPEED_10: + state->speed = SPEED_10; + break; + case AN8855_PMSR_SPEED_100: + state->speed = SPEED_100; + break; + case AN8855_PMSR_SPEED_1000: + state->speed = SPEED_1000; + break; + case AN8855_PMSR_SPEED_2500: + state->speed = SPEED_2500; + break; + case AN8855_PMSR_SPEED_5000: + dev_err(priv->dev, "Missing support for 5G speed. Setting Unknown.\n"); + fallthrough; + default: + state->speed = SPEED_UNKNOWN; + break; + } + + if (val & AN8855_PMSR_RX_FC) + state->pause |= MLO_PAUSE_RX; + if (val & AN8855_PMSR_TX_FC) + state->pause |= MLO_PAUSE_TX; +} + +static int an8855_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct an8855_priv *priv = container_of(pcs, struct an8855_priv, pcs); + u32 val; + int ret; + + /* !!! WELCOME TO HELL !!! */ + + /* TX FIR - improve TX EYE */ + ret = regmap_update_bits(priv->regmap, AN8855_INTF_CTRL_10, + AN8855_RG_DA_QP_TX_FIR_C2_SEL | + AN8855_RG_DA_QP_TX_FIR_C2_FORCE | + AN8855_RG_DA_QP_TX_FIR_C1_SEL | + AN8855_RG_DA_QP_TX_FIR_C1_FORCE, + AN8855_RG_DA_QP_TX_FIR_C2_SEL | + FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C2_FORCE, 0x4) | + AN8855_RG_DA_QP_TX_FIR_C1_SEL | + FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C1_FORCE, 0x0)); + if (ret) + return ret; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x0; + else + val = 0xd; + ret = regmap_update_bits(priv->regmap, AN8855_INTF_CTRL_11, + AN8855_RG_DA_QP_TX_FIR_C0B_SEL | + AN8855_RG_DA_QP_TX_FIR_C0B_FORCE, + AN8855_RG_DA_QP_TX_FIR_C0B_SEL | + FIELD_PREP(AN8855_RG_DA_QP_TX_FIR_C0B_FORCE, val)); + if (ret) + return ret; + + /* RX CDR - improve RX Jitter Tolerance */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x5; + else + val = 0x6; + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_BOT_LIM, + AN8855_RG_QP_CDR_LPF_KP_GAIN | + AN8855_RG_QP_CDR_LPF_KI_GAIN, + FIELD_PREP(AN8855_RG_QP_CDR_LPF_KP_GAIN, val) | + FIELD_PREP(AN8855_RG_QP_CDR_LPF_KI_GAIN, val)); + if (ret) + return ret; + + /* PLL */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x1; + else + val = 0x0; + ret = regmap_update_bits(priv->regmap, AN8855_QP_DIG_MODE_CTRL_1, + AN8855_RG_TPHY_SPEED, + FIELD_PREP(AN8855_RG_TPHY_SPEED, val)); + if (ret) + return ret; + + /* PLL - LPF */ + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_RICO_SEL_INTF | + AN8855_RG_DA_QP_PLL_FBKSEL_INTF | + AN8855_RG_DA_QP_PLL_BR_INTF | + AN8855_RG_DA_QP_PLL_BPD_INTF | + AN8855_RG_DA_QP_PLL_BPA_INTF | + AN8855_RG_DA_QP_PLL_BC_INTF, + AN8855_RG_DA_QP_PLL_RICO_SEL_INTF | + FIELD_PREP(AN8855_RG_DA_QP_PLL_FBKSEL_INTF, 0x0) | + FIELD_PREP(AN8855_RG_DA_QP_PLL_BR_INTF, 0x3) | + FIELD_PREP(AN8855_RG_DA_QP_PLL_BPD_INTF, 0x0) | + FIELD_PREP(AN8855_RG_DA_QP_PLL_BPA_INTF, 0x5) | + FIELD_PREP(AN8855_RG_DA_QP_PLL_BC_INTF, 0x1)); + if (ret) + return ret; + + /* PLL - ICO */ + ret = regmap_set_bits(priv->regmap, AN8855_PLL_CTRL_4, + AN8855_RG_DA_QP_PLL_ICOLP_EN_INTF); + if (ret) + return ret; + ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_ICOIQ_EN_INTF); + if (ret) + return ret; + + /* PLL - CHP */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x6; + else + val = 0x4; + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_IR_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_IR_INTF, val)); + if (ret) + return ret; + + /* PLL - PFD */ + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_PFD_OFFSET_EN_INTRF | + AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF | + AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF, 0x1) | + FIELD_PREP(AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF, 0x1)); + if (ret) + return ret; + + /* PLL - POSTDIV */ + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_POSTDIV_EN_INTF | + AN8855_RG_DA_QP_PLL_PHY_CK_EN_INTF | + AN8855_RG_DA_QP_PLL_PCK_SEL_INTF, + AN8855_RG_DA_QP_PLL_PCK_SEL_INTF); + if (ret) + return ret; + + /* PLL - SDM */ + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_SDM_HREN_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_SDM_HREN_INTF, 0x0)); + if (ret) + return ret; + ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CTRL_2, + AN8855_RG_DA_QP_PLL_SDM_IFM_INTF); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_SS_LCPLL_PWCTL_SETTING_2, + AN8855_RG_NCPO_ANA_MSB, + FIELD_PREP(AN8855_RG_NCPO_ANA_MSB, 0x1)); + if (ret) + return ret; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x7a000000; + else + val = 0x48000000; + ret = regmap_write(priv->regmap, AN8855_SS_LCPLL_TDC_FLT_2, + FIELD_PREP(AN8855_RG_LCPLL_NCPO_VALUE, val)); + if (ret) + return ret; + ret = regmap_write(priv->regmap, AN8855_SS_LCPLL_TDC_PCW_1, + FIELD_PREP(AN8855_RG_LCPLL_PON_HRDDS_PCW_NCPO_GPON, val)); + if (ret) + return ret; + + ret = regmap_clear_bits(priv->regmap, AN8855_SS_LCPLL_TDC_FLT_5, + AN8855_RG_LCPLL_NCPO_CHG); + if (ret) + return ret; + ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CK_CTRL_0, + AN8855_RG_DA_QP_PLL_SDM_DI_EN_INTF); + if (ret) + return ret; + + /* PLL - SS */ + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_3, + AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF, 0x0)); + if (ret) + return ret; + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_4, + AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF, 0x0)); + if (ret) + return ret; + ret = regmap_update_bits(priv->regmap, AN8855_PLL_CTRL_3, + AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF, + FIELD_PREP(AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF, 0x0)); + if (ret) + return ret; + + /* PLL - TDC */ + ret = regmap_clear_bits(priv->regmap, AN8855_PLL_CK_CTRL_0, + AN8855_RG_DA_QP_PLL_TDC_TXCK_SEL_INTF); + if (ret) + return ret; + + ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_PLL_SDM_ORD, + AN8855_RG_QP_PLL_SSC_TRI_EN); + if (ret) + return ret; + ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_PLL_SDM_ORD, + AN8855_RG_QP_PLL_SSC_PHASE_INI); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_RX_DAC_EN, + AN8855_RG_QP_SIGDET_HF, + FIELD_PREP(AN8855_RG_QP_SIGDET_HF, 0x2)); + if (ret) + return ret; + + /* TCL Disable (only for Co-SIM) */ + ret = regmap_clear_bits(priv->regmap, AN8855_PON_RXFEDIG_CTRL_0, + AN8855_RG_QP_EQ_RX500M_CK_SEL); + if (ret) + return ret; + + /* TX Init */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x4; + else + val = 0x0; + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_TX_MODE, + AN8855_RG_QP_TX_RESERVE | + AN8855_RG_QP_TX_MODE_16B_EN, + FIELD_PREP(AN8855_RG_QP_TX_RESERVE, val)); + if (ret) + return ret; + + /* RX Control/Init */ + ret = regmap_set_bits(priv->regmap, AN8855_RG_QP_RXAFE_RESERVE, + AN8855_RG_QP_CDR_PD_10B_EN); + if (ret) + return ret; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x1; + else + val = 0x2; + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_MJV_LIM, + AN8855_RG_QP_CDR_LPF_RATIO, + FIELD_PREP(AN8855_RG_QP_CDR_LPF_RATIO, val)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_LPF_SETVALUE, + AN8855_RG_QP_CDR_PR_BUF_IN_SR | + AN8855_RG_QP_CDR_PR_BETA_SEL, + FIELD_PREP(AN8855_RG_QP_CDR_PR_BUF_IN_SR, 0x6) | + FIELD_PREP(AN8855_RG_QP_CDR_PR_BETA_SEL, 0x1)); + if (ret) + return ret; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0xf; + else + val = 0xc; + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_CKREF_DIV1, + AN8855_RG_QP_CDR_PR_DAC_BAND, + FIELD_PREP(AN8855_RG_QP_CDR_PR_DAC_BAND, val)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, + AN8855_RG_QP_CDR_PR_KBAND_PCIE_MODE | + AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK, + FIELD_PREP(AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK, 0x19)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, + AN8855_RG_QP_CDR_PHYCK_SEL | + AN8855_RG_QP_CDR_PHYCK_RSTB | + AN8855_RG_QP_CDR_PHYCK_DIV, + FIELD_PREP(AN8855_RG_QP_CDR_PHYCK_SEL, 0x2) | + FIELD_PREP(AN8855_RG_QP_CDR_PHYCK_DIV, 0x21)); + if (ret) + return ret; + + ret = regmap_clear_bits(priv->regmap, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, + AN8855_RG_QP_CDR_PR_XFICK_EN); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RG_QP_CDR_PR_CKREF_DIV1, + AN8855_RG_QP_CDR_PR_KBAND_DIV, + FIELD_PREP(AN8855_RG_QP_CDR_PR_KBAND_DIV, 0x4)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_26, + AN8855_RG_QP_EQ_RETRAIN_ONLY_EN | + AN8855_RG_LINK_NE_EN | + AN8855_RG_LINK_ERRO_EN, + AN8855_RG_QP_EQ_RETRAIN_ONLY_EN | + AN8855_RG_LINK_ERRO_EN); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_DLY_0, + AN8855_RG_QP_RX_SAOSC_EN_H_DLY | + AN8855_RG_QP_RX_PI_CAL_EN_H_DLY, + FIELD_PREP(AN8855_RG_QP_RX_SAOSC_EN_H_DLY, 0x3f) | + FIELD_PREP(AN8855_RG_QP_RX_PI_CAL_EN_H_DLY, 0x6f)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_42, + AN8855_RG_QP_EQ_EN_DLY, + FIELD_PREP(AN8855_RG_QP_EQ_EN_DLY, 0x150)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_2, + AN8855_RG_QP_RX_EQ_EN_H_DLY, + FIELD_PREP(AN8855_RG_QP_RX_EQ_EN_H_DLY, 0x150)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_PON_RXFEDIG_CTRL_9, + AN8855_RG_QP_EQ_LEQOSC_DLYCNT, + FIELD_PREP(AN8855_RG_QP_EQ_LEQOSC_DLYCNT, 0x1)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_8, + AN8855_RG_DA_QP_SAOSC_DONE_TIME | + AN8855_RG_DA_QP_LEQOS_EN_TIME, + FIELD_PREP(AN8855_RG_DA_QP_SAOSC_DONE_TIME, 0x200) | + FIELD_PREP(AN8855_RG_DA_QP_LEQOS_EN_TIME, 0xfff)); + if (ret) + return ret; + + /* Frequency meter */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = 0x10; + else + val = 0x28; + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_5, + AN8855_RG_FREDET_CHK_CYCLE, + FIELD_PREP(AN8855_RG_FREDET_CHK_CYCLE, val)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_6, + AN8855_RG_FREDET_GOLDEN_CYCLE, + FIELD_PREP(AN8855_RG_FREDET_GOLDEN_CYCLE, 0x64)); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_RX_CTRL_7, + AN8855_RG_FREDET_TOLERATE_CYCLE, + FIELD_PREP(AN8855_RG_FREDET_TOLERATE_CYCLE, 0x2710)); + if (ret) + return ret; + + ret = regmap_set_bits(priv->regmap, AN8855_PLL_CTRL_0, + AN8855_RG_PHYA_AUTO_INIT); + if (ret) + return ret; + + /* PCS Init */ + if (interface == PHY_INTERFACE_MODE_SGMII && + neg_mode == PHYLINK_PCS_NEG_INBAND_DISABLED) { + ret = regmap_clear_bits(priv->regmap, AN8855_QP_DIG_MODE_CTRL_0, + AN8855_RG_SGMII_MODE | AN8855_RG_SGMII_AN_EN); + if (ret) + return ret; + } + + ret = regmap_clear_bits(priv->regmap, AN8855_RG_HSGMII_PCS_CTROL_1, + AN8855_RG_TBI_10B_MODE); + if (ret) + return ret; + + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + /* Set AN Ability - Interrupt */ + ret = regmap_set_bits(priv->regmap, AN8855_SGMII_REG_AN_FORCE_CL37, + AN8855_RG_FORCE_AN_DONE); + if (ret) + return ret; + + ret = regmap_update_bits(priv->regmap, AN8855_SGMII_REG_AN_13, + AN8855_SGMII_REMOTE_FAULT_DIS | + AN8855_SGMII_IF_MODE, + AN8855_SGMII_REMOTE_FAULT_DIS | + FIELD_PREP(AN8855_SGMII_IF_MODE, 0xb)); + if (ret) + return ret; + } + + /* Rate Adaption - GMII path config. */ + if (interface == PHY_INTERFACE_MODE_2500BASEX) { + ret = regmap_clear_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, + AN8855_RG_P0_DIS_MII_MODE); + if (ret) + return ret; + } else { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + ret = regmap_set_bits(priv->regmap, AN8855_MII_RA_AN_ENABLE, + AN8855_RG_P0_RA_AN_EN); + if (ret) + return ret; + } else { + ret = regmap_update_bits(priv->regmap, AN8855_RG_AN_SGMII_MODE_FORCE, + AN8855_RG_FORCE_CUR_SGMII_MODE | + AN8855_RG_FORCE_CUR_SGMII_SEL, + AN8855_RG_FORCE_CUR_SGMII_SEL); + if (ret) + return ret; + + ret = regmap_clear_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, + AN8855_RG_P0_MII_RA_RX_EN | + AN8855_RG_P0_MII_RA_TX_EN | + AN8855_RG_P0_MII_RA_RX_MODE | + AN8855_RG_P0_MII_RA_TX_MODE); + if (ret) + return ret; + } + + ret = regmap_set_bits(priv->regmap, AN8855_RATE_ADP_P0_CTRL_0, + AN8855_RG_P0_MII_MODE); + if (ret) + return ret; + } + + ret = regmap_set_bits(priv->regmap, AN8855_RG_RATE_ADAPT_CTRL_0, + AN8855_RG_RATE_ADAPT_RX_BYPASS | + AN8855_RG_RATE_ADAPT_TX_BYPASS | + AN8855_RG_RATE_ADAPT_RX_EN | + AN8855_RG_RATE_ADAPT_TX_EN); + if (ret) + return ret; + + /* Disable AN if not in autoneg */ + ret = regmap_update_bits(priv->regmap, AN8855_SGMII_REG_AN0, BMCR_ANENABLE, + neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? BMCR_ANENABLE : + 0); + if (ret) + return ret; + + if (interface == PHY_INTERFACE_MODE_SGMII) { + /* Follow SDK init flow with restarting AN after AN enable */ + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + ret = regmap_set_bits(priv->regmap, AN8855_SGMII_REG_AN0, + BMCR_ANRESTART); + if (ret) + return ret; + } else { + ret = regmap_set_bits(priv->regmap, AN8855_PHY_RX_FORCE_CTRL_0, + AN8855_RG_FORCE_TXC_SEL); + if (ret) + return ret; + } + } + + /* Force Speed with fixed-link or 2500base-x as doesn't support aneg */ + if (interface == PHY_INTERFACE_MODE_2500BASEX || + neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val = AN8855_RG_LINK_MODE_P0_SPEED_2500; + else + val = AN8855_RG_LINK_MODE_P0_SPEED_1000; + ret = regmap_update_bits(priv->regmap, AN8855_SGMII_STS_CTRL_0, + AN8855_RG_LINK_MODE_P0 | + AN8855_RG_FORCE_SPD_MODE_P0, + val | AN8855_RG_FORCE_SPD_MODE_P0); + if (ret) + return ret; + } + + /* bypass flow control to MAC */ + ret = regmap_write(priv->regmap, AN8855_MSG_RX_LIK_STS_0, + AN8855_RG_DPX_STS_P3 | AN8855_RG_DPX_STS_P2 | + AN8855_RG_DPX_STS_P1 | AN8855_RG_TXFC_STS_P0 | + AN8855_RG_RXFC_STS_P0 | AN8855_RG_DPX_STS_P0); + if (ret) + return ret; + ret = regmap_write(priv->regmap, AN8855_MSG_RX_LIK_STS_2, + AN8855_RG_RXFC_AN_BYPASS_P3 | + AN8855_RG_RXFC_AN_BYPASS_P2 | + AN8855_RG_RXFC_AN_BYPASS_P1 | + AN8855_RG_TXFC_AN_BYPASS_P3 | + AN8855_RG_TXFC_AN_BYPASS_P2 | + AN8855_RG_TXFC_AN_BYPASS_P1 | + AN8855_RG_DPX_AN_BYPASS_P3 | + AN8855_RG_DPX_AN_BYPASS_P2 | + AN8855_RG_DPX_AN_BYPASS_P1 | + AN8855_RG_DPX_AN_BYPASS_P0); + if (ret) + return ret; + + return 0; +} + +static void an8855_pcs_an_restart(struct phylink_pcs *pcs) +{ + return; +} + +static const struct phylink_pcs_ops an8855_pcs_ops = { + .pcs_inband_caps = an8855_pcs_inband_caps, + .pcs_get_state = an8855_pcs_get_state, + .pcs_config = an8855_pcs_config, + .pcs_an_restart = an8855_pcs_an_restart, +}; + +static const struct phylink_mac_ops an8855_phylink_mac_ops = { + .mac_select_pcs = an8855_phylink_mac_select_pcs, + .mac_config = an8855_phylink_mac_config, + .mac_link_down = an8855_phylink_mac_link_down, + .mac_link_up = an8855_phylink_mac_link_up, +}; + +static const struct dsa_switch_ops an8855_switch_ops = { + .get_tag_protocol = an8855_get_tag_protocol, + .setup = an8855_setup, + .get_phy_flags = en8855_get_phy_flags, + .phylink_get_caps = an8855_phylink_get_caps, + .get_strings = an8855_get_strings, + .get_ethtool_stats = an8855_get_ethtool_stats, + .get_sset_count = an8855_get_sset_count, + .get_eth_mac_stats = an8855_get_eth_mac_stats, + .get_eth_ctrl_stats = an8855_get_eth_ctrl_stats, + .get_rmon_stats = an8855_get_rmon_stats, + .port_enable = an8855_port_enable, + .port_disable = an8855_port_disable, + .set_ageing_time = an8855_set_ageing_time, + .port_bridge_join = an8855_port_bridge_join, + .port_bridge_leave = an8855_port_bridge_leave, + .port_fast_age = an8855_port_fast_age, + .port_stp_state_set = an8855_port_stp_state_set, + .port_pre_bridge_flags = an8855_port_pre_bridge_flags, + .port_bridge_flags = an8855_port_bridge_flags, + .port_vlan_filtering = an8855_port_vlan_filtering, + .port_vlan_add = an8855_port_vlan_add, + .port_vlan_del = an8855_port_vlan_del, + .port_fdb_add = an8855_port_fdb_add, + .port_fdb_del = an8855_port_fdb_del, + .port_fdb_dump = an8855_port_fdb_dump, + .port_mdb_add = an8855_port_mdb_add, + .port_mdb_del = an8855_port_mdb_del, + .port_change_mtu = an8855_port_change_mtu, + .port_max_mtu = an8855_port_max_mtu, + .port_mirror_add = an8855_port_mirror_add, + .port_mirror_del = an8855_port_mirror_del, +}; + +static int an8855_read_switch_id(struct an8855_priv *priv) +{ + u32 id; + int ret; + + ret = regmap_read(priv->regmap, AN8855_CREV, &id); + if (ret) + return ret; + + if (id != AN8855_ID) { + dev_err(priv->dev, + "Switch id detected %x but expected %x\n", + id, AN8855_ID); + return -ENODEV; + } + + return 0; +} + +static int an8855_switch_probe(struct platform_device *pdev) +{ + struct an8855_priv *priv; + u32 val; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->phy_require_calib = of_property_read_bool(priv->dev->of_node, + "airoha,ext-surge"); + + priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(priv->reset_gpio)) + return PTR_ERR(priv->reset_gpio); + + /* Get regmap from MFD */ + priv->regmap = dev_get_regmap(priv->dev->parent, NULL); + + if (priv->reset_gpio) { + usleep_range(100000, 150000); + gpiod_set_value_cansleep(priv->reset_gpio, 0); + usleep_range(100000, 150000); + gpiod_set_value_cansleep(priv->reset_gpio, 1); + + /* Poll HWTRAP reg to wait for Switch to fully Init */ + ret = regmap_read_poll_timeout(priv->regmap, AN8855_HWTRAP, val, + val, 20, 200000); + if (ret) + return ret; + } + + ret = an8855_read_switch_id(priv); + if (ret) + return ret; + + priv->ds = devm_kzalloc(priv->dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + + priv->ds->dev = priv->dev; + priv->ds->num_ports = AN8855_NUM_PORTS; + priv->ds->priv = priv; + priv->ds->ops = &an8855_switch_ops; + devm_mutex_init(priv->dev, &priv->reg_mutex); + priv->ds->phylink_mac_ops = &an8855_phylink_mac_ops; + + priv->pcs.ops = &an8855_pcs_ops; + priv->pcs.neg_mode = true; + priv->pcs.poll = true; + + dev_set_drvdata(priv->dev, priv); + + return dsa_register_switch(priv->ds); +} + +static void an8855_switch_remove(struct platform_device *pdev) +{ + struct an8855_priv *priv = dev_get_drvdata(&pdev->dev); + + if (priv) + dsa_unregister_switch(priv->ds); +} + +static const struct of_device_id an8855_switch_of_match[] = { + { .compatible = "airoha,an8855-switch" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, an8855_switch_of_match); + +static struct platform_driver an8855_switch_driver = { + .probe = an8855_switch_probe, + .remove_new = an8855_switch_remove, + .driver = { + .name = "an8855-switch", + .of_match_table = an8855_switch_of_match, + }, +}; +module_platform_driver(an8855_switch_driver); + +MODULE_AUTHOR("Min Yao "); +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Driver for Airoha AN8855 Switch"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/dsa/an8855.h b/drivers/net/dsa/an8855.h new file mode 100644 index 000000000000..2462b9d33752 --- /dev/null +++ b/drivers/net/dsa/an8855.h @@ -0,0 +1,783 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 Min Yao + * Copyright (C) 2024 Christian Marangi + */ + +#ifndef __AN8855_H +#define __AN8855_H + +#include + +#define AN8855_NUM_PORTS 6 +#define AN8855_CPU_PORT 5 +#define AN8855_NUM_FDB_RECORDS 2048 +#define AN8855_GPHY_SMI_ADDR_DEFAULT 1 +#define AN8855_PORT_VID_DEFAULT 0 + +#define MTK_TAG_LEN 4 +#define AN8855_MAX_MTU (15360 - ETH_HLEN - ETH_FCS_LEN - MTK_TAG_LEN) + +#define AN8855_L2_AGING_MS_CONSTANT 1024 + +#define AN8855_PHY_FLAGS_EN_CALIBRATION BIT(0) + +/* AN8855_SCU 0x10000000 */ +#define AN8855_RG_GPIO_LED_MODE 0x10000054 +#define AN8855_RG_GPIO_LED_SEL(i) (0x10000000 + (0x0058 + ((i) * 4))) +#define AN8855_RG_INTB_MODE 0x10000080 +#define AN8855_RG_RGMII_TXCK_C 0x100001d0 + +#define AN8855_PKG_SEL 0x10000094 +#define AN8855_PAG_SEL_AN8855H 0x2 + +/* Register for hw trap status */ +#define AN8855_HWTRAP 0x1000009c + +#define AN8855_RG_GPIO_L_INV 0x10000010 +#define AN8855_RG_GPIO_CTRL 0x1000a300 +#define AN8855_RG_GPIO_DATA 0x1000a304 +#define AN8855_RG_GPIO_OE 0x1000a314 + +#define AN8855_CREV 0x10005000 +#define AN8855_ID 0x8855 + +/* Register for system reset */ +#define AN8855_RST_CTRL 0x100050c0 +#define AN8855_SYS_CTRL_SYS_RST BIT(31) + +#define AN8855_INT_MASK 0x100050f0 +#define AN8855_INT_SYS BIT(15) + +#define AN8855_RG_CLK_CPU_ICG 0x10005034 +#define AN8855_MCU_ENABLE BIT(3) + +#define AN8855_RG_TIMER_CTL 0x1000a100 +#define AN8855_WDOG_ENABLE BIT(25) + +#define AN8855_RG_GDMP_RAM 0x10010000 + +/* Registers to mac forward control for unknown frames */ +#define AN8855_MFC 0x10200010 +#define AN8855_CPU_EN BIT(15) +#define AN8855_CPU_PORT_IDX GENMASK(12, 8) + +#define AN8855_PAC 0x10200024 +#define AN8855_TAG_PAE_MANG_FR BIT(30) +#define AN8855_TAG_PAE_BPDU_FR BIT(28) +#define AN8855_TAG_PAE_EG_TAG GENMASK(27, 25) +#define AN8855_TAG_PAE_LKY_VLAN BIT(24) +#define AN8855_TAG_PAE_PRI_HIGH BIT(23) +#define AN8855_TAG_PAE_MIR GENMASK(20, 19) +#define AN8855_TAG_PAE_PORT_FW GENMASK(18, 16) +#define AN8855_PAE_MANG_FR BIT(14) +#define AN8855_PAE_BPDU_FR BIT(12) +#define AN8855_PAE_EG_TAG GENMASK(11, 9) +#define AN8855_PAE_LKY_VLAN BIT(8) +#define AN8855_PAE_PRI_HIGH BIT(7) +#define AN8855_PAE_MIR GENMASK(4, 3) +#define AN8855_PAE_PORT_FW GENMASK(2, 0) + +#define AN8855_RGAC1 0x10200028 +#define AN8855_R02_MANG_FR BIT(30) +#define AN8855_R02_BPDU_FR BIT(28) +#define AN8855_R02_EG_TAG GENMASK(27, 25) +#define AN8855_R02_LKY_VLAN BIT(24) +#define AN8855_R02_PRI_HIGH BIT(23) +#define AN8855_R02_MIR GENMASK(20, 19) +#define AN8855_R02_PORT_FW GENMASK(18, 16) +#define AN8855_R01_MANG_FR BIT(14) +#define AN8855_R01_BPDU_FR BIT(12) +#define AN8855_R01_EG_TAG GENMASK(11, 9) +#define AN8855_R01_LKY_VLAN BIT(8) +#define AN8855_R01_PRI_HIGH BIT(7) +#define AN8855_R01_MIR GENMASK(4, 3) +#define AN8855_R01_PORT_FW GENMASK(2, 0) + +#define AN8855_RGAC2 0x1020002c +#define AN8855_R0E_MANG_FR BIT(30) +#define AN8855_R0E_BPDU_FR BIT(28) +#define AN8855_R0E_EG_TAG GENMASK(27, 25) +#define AN8855_R0E_LKY_VLAN BIT(24) +#define AN8855_R0E_PRI_HIGH BIT(23) +#define AN8855_R0E_MIR GENMASK(20, 19) +#define AN8855_R0E_PORT_FW GENMASK(18, 16) +#define AN8855_R03_MANG_FR BIT(14) +#define AN8855_R03_BPDU_FR BIT(12) +#define AN8855_R03_EG_TAG GENMASK(11, 9) +#define AN8855_R03_LKY_VLAN BIT(8) +#define AN8855_R03_PRI_HIGH BIT(7) +#define AN8855_R03_MIR GENMASK(4, 3) +#define AN8855_R03_PORT_FW GENMASK(2, 0) + +#define AN8855_AAC 0x102000a0 +#define AN8855_MAC_AUTO_FLUSH BIT(28) +/* Control Address Table Age time. + * (AN8855_AGE_CNT + 1) * ( AN8855_AGE_UNIT + 1 ) * AN8855_L2_AGING_MS_CONSTANT + */ +#define AN8855_AGE_CNT GENMASK(20, 12) +/* Value in seconds. Value is always incremented of 1 */ +#define AN8855_AGE_UNIT GENMASK(10, 0) + +/* Registers for ARL Unknown Unicast Forward control */ +#define AN8855_UNUF 0x102000b4 + +/* Registers for ARL Unknown Multicast Forward control */ +#define AN8855_UNMF 0x102000b8 + +/* Registers for ARL Broadcast forward control */ +#define AN8855_BCF 0x102000bc + +/* Registers for port address age disable */ +#define AN8855_AGDIS 0x102000c0 + +/* Registers for mirror port control */ +#define AN8855_MIR 0x102000cc +#define AN8855_MIRROR_EN BIT(7) +#define AN8855_MIRROR_PORT GENMASK(4, 0) + +/* Registers for BPDU and PAE frame control*/ +#define AN8855_BPC 0x102000d0 +#define AN8855_BPDU_MANG_FR BIT(14) +#define AN8855_BPDU_BPDU_FR BIT(12) +#define AN8855_BPDU_EG_TAG GENMASK(11, 9) +#define AN8855_BPDU_LKY_VLAN BIT(8) +#define AN8855_BPDU_PRI_HIGH BIT(7) +#define AN8855_BPDU_MIR GENMASK(4, 3) +#define AN8855_BPDU_PORT_FW GENMASK(2, 0) + +/* Registers for IP Unknown Multicast Forward control */ +#define AN8855_UNIPMF 0x102000dc + +enum an8855_bpdu_port_fw { + AN8855_BPDU_FOLLOW_MFC = 0, + AN8855_BPDU_CPU_EXCLUDE = 4, + AN8855_BPDU_CPU_INCLUDE = 5, + AN8855_BPDU_CPU_ONLY = 6, + AN8855_BPDU_DROP = 7, +}; + +/* Register for address table control */ +#define AN8855_ATC 0x10200300 +#define AN8855_ATC_BUSY BIT(31) +#define AN8855_ATC_HASH GENMASK(24, 16) +#define AN8855_ATC_HIT GENMASK(15, 12) +#define AN8855_ATC_MAT_MASK GENMASK(11, 7) +#define AN8855_ATC_MAT(x) FIELD_PREP(AN8855_ATC_MAT_MASK, x) +#define AN8855_ATC_SAT GENMASK(5, 4) +#define AN8855_ATC_CMD GENMASK(2, 0) + +enum an8855_fdb_mat_cmds { + AND8855_FDB_MAT_ALL = 0, + AND8855_FDB_MAT_MAC, /* All MAC address */ + AND8855_FDB_MAT_DYNAMIC_MAC, /* All Dynamic MAC address */ + AND8855_FDB_MAT_STATIC_MAC, /* All Static Mac Address */ + AND8855_FDB_MAT_DIP, /* All DIP/GA address */ + AND8855_FDB_MAT_DIP_IPV4, /* All DIP/GA IPv4 address */ + AND8855_FDB_MAT_DIP_IPV6, /* All DIP/GA IPv6 address */ + AND8855_FDB_MAT_DIP_SIP, /* All DIP_SIP address */ + AND8855_FDB_MAT_DIP_SIP_IPV4, /* All DIP_SIP IPv4 address */ + AND8855_FDB_MAT_DIP_SIP_IPV6, /* All DIP_SIP IPv6 address */ + AND8855_FDB_MAT_MAC_CVID, /* All MAC address with CVID */ + AND8855_FDB_MAT_MAC_FID, /* All MAC address with Filter ID */ + AND8855_FDB_MAT_MAC_PORT, /* All MAC address with port */ + AND8855_FDB_MAT_DIP_SIP_DIP_IPV4, /* All DIP_SIP address with DIP_IPV4 */ + AND8855_FDB_MAT_DIP_SIP_SIP_IPV4, /* All DIP_SIP address with SIP_IPV4 */ + AND8855_FDB_MAT_DIP_SIP_DIP_IPV6, /* All DIP_SIP address with DIP_IPV6 */ + AND8855_FDB_MAT_DIP_SIP_SIP_IPV6, /* All DIP_SIP address with SIP_IPV6 */ + /* All MAC address with MAC type (dynamic or static) with CVID */ + AND8855_FDB_MAT_MAC_TYPE_CVID, + /* All MAC address with MAC type (dynamic or static) with Filter ID */ + AND8855_FDB_MAT_MAC_TYPE_FID, + /* All MAC address with MAC type (dynamic or static) with port */ + AND8855_FDB_MAT_MAC_TYPE_PORT, +}; + +enum an8855_fdb_cmds { + AN8855_FDB_READ = 0, + AN8855_FDB_WRITE = 1, + AN8855_FDB_FLUSH = 2, + AN8855_FDB_START = 4, + AN8855_FDB_NEXT = 5, +}; + +/* Registers for address table access */ +#define AN8855_ATA1 0x10200304 +#define AN8855_ATA1_MAC0 GENMASK(31, 24) +#define AN8855_ATA1_MAC1 GENMASK(23, 16) +#define AN8855_ATA1_MAC2 GENMASK(15, 8) +#define AN8855_ATA1_MAC3 GENMASK(7, 0) +#define AN8855_ATA2 0x10200308 +#define AN8855_ATA2_MAC4 GENMASK(31, 24) +#define AN8855_ATA2_MAC5 GENMASK(23, 16) +#define AN8855_ATA2_UNAUTH BIT(10) +#define AN8855_ATA2_TYPE BIT(9) /* 1: dynamic, 0: static */ +#define AN8855_ATA2_AGE GENMASK(8, 0) + +/* Register for address table write data */ +#define AN8855_ATWD 0x10200324 +#define AN8855_ATWD_FID GENMASK(31, 28) +#define AN8855_ATWD_VID GENMASK(27, 16) +#define AN8855_ATWD_IVL BIT(15) +#define AN8855_ATWD_EG_TAG GENMASK(14, 12) +#define AN8855_ATWD_SA_MIR GENMASK(9, 8) +#define AN8855_ATWD_SA_FWD GENMASK(7, 5) +#define AN8855_ATWD_UPRI GENMASK(4, 2) +#define AN8855_ATWD_LEAKY BIT(1) +#define AN8855_ATWD_VLD BIT(0) /* vid LOAD */ +#define AN8855_ATWD2 0x10200328 +#define AN8855_ATWD2_PORT GENMASK(7, 0) + +/* Registers for table search read address */ +#define AN8855_ATRDS 0x10200330 +#define AN8855_ATRD_SEL GENMASK(1, 0) +#define AN8855_ATRD0 0x10200334 +#define AN8855_ATRD0_FID GENMASK(28, 25) +#define AN8855_ATRD0_VID GENMASK(21, 10) +#define AN8855_ATRD0_IVL BIT(9) +#define AN8855_ATRD0_TYPE GENMASK(4, 3) +#define AN8855_ATRD0_ARP GENMASK(2, 1) +#define AN8855_ATRD0_LIVE BIT(0) +#define AN8855_ATRD1 0x10200338 +#define AN8855_ATRD1_MAC4 GENMASK(31, 24) +#define AN8855_ATRD1_MAC5 GENMASK(23, 16) +#define AN8855_ATRD1_AGING GENMASK(11, 3) +#define AN8855_ATRD2 0x1020033c +#define AN8855_ATRD2_MAC0 GENMASK(31, 24) +#define AN8855_ATRD2_MAC1 GENMASK(23, 16) +#define AN8855_ATRD2_MAC2 GENMASK(15, 8) +#define AN8855_ATRD2_MAC3 GENMASK(7, 0) +#define AN8855_ATRD3 0x10200340 +#define AN8855_ATRD3_PORTMASK GENMASK(7, 0) + +enum an8855_fdb_type { + AN8855_MAC_TB_TY_MAC = 0, + AN8855_MAC_TB_TY_DIP = 1, + AN8855_MAC_TB_TY_DIP_SIP = 2, +}; + +/* Register for vlan table control */ +#define AN8855_VTCR 0x10200600 +#define AN8855_VTCR_BUSY BIT(31) +#define AN8855_VTCR_FUNC GENMASK(15, 12) +#define AN8855_VTCR_VID GENMASK(11, 0) + +enum an8855_vlan_cmd { + /* Read/Write the specified VID entry from VAWD register based + * on VID. + */ + AN8855_VTCR_RD_VID = 0, + AN8855_VTCR_WR_VID = 1, +}; + +/* Register for setup vlan write data */ +#define AN8855_VAWD0 0x10200604 +/* VLAN Member Control */ +#define AN8855_VA0_PORT GENMASK(31, 26) +/* Egress Tag Control */ +#define AN8855_VA0_ETAG GENMASK(23, 12) +#define AN8855_VA0_ETAG_PORT GENMASK(13, 12) +#define AN8855_VA0_ETAG_PORT_SHIFT(port) ((port) * 2) +#define AN8855_VA0_ETAG_PORT_MASK(port) (AN8855_VA0_ETAG_PORT << \ + AN8855_VA0_ETAG_PORT_SHIFT(port)) +#define AN8855_VA0_ETAG_PORT_VAL(port, val) (FIELD_PREP(AN8855_VA0_ETAG_PORT, (val)) << \ + AN8855_VA0_ETAG_PORT_SHIFT(port)) +#define AN8855_VA0_EG_CON BIT(11) +#define AN8855_VA0_VTAG_EN BIT(10) /* Per VLAN Egress Tag Control */ +#define AN8855_VA0_IVL_MAC BIT(5) /* Independent VLAN Learning */ +#define AN8855_VA0_FID GENMASK(4, 1) +#define AN8855_VA0_VLAN_VALID BIT(0) /* VLAN Entry Valid */ +#define AN8855_VAWD1 0x10200608 +#define AN8855_VA1_PORT_STAG BIT(1) + +enum an8855_fid { + AN8855_FID_STANDALONE = 0, + AN8855_FID_BRIDGED = 1, +}; + +/* Same register field of VAWD0 */ +#define AN8855_VARD0 0x10200618 + +enum an8855_vlan_egress_attr { + AN8855_VLAN_EGRESS_UNTAG = 0, + AN8855_VLAN_EGRESS_TAG = 2, + AN8855_VLAN_EGRESS_STACK = 3, +}; + +/* Register for port STP state control */ +#define AN8855_SSP_P(x) (0x10208000 + ((x) * 0x200)) +/* Up to 16 FID supported, each with the same mask */ +#define AN8855_FID_PST GENMASK(1, 0) +#define AN8855_FID_PST_SHIFT(fid) (2 * (fid)) +#define AN8855_FID_PST_MASK(fid) (AN8855_FID_PST << \ + AN8855_FID_PST_SHIFT(fid)) +#define AN8855_FID_PST_VAL(fid, val) (FIELD_PREP(AN8855_FID_PST, (val)) << \ + AN8855_FID_PST_SHIFT(fid)) + +enum an8855_stp_state { + AN8855_STP_DISABLED = 0, + AN8855_STP_BLOCKING = 1, + AN8855_STP_LISTENING = AN8855_STP_BLOCKING, + AN8855_STP_LEARNING = 2, + AN8855_STP_FORWARDING = 3 +}; + +/* Register for port control */ +#define AN8855_PCR_P(x) (0x10208004 + ((x) * 0x200)) +#define AN8855_EG_TAG GENMASK(29, 28) +#define AN8855_PORT_PRI GENMASK(26, 24) +#define AN8855_PORT_TX_MIR BIT(20) +#define AN8855_PORT_RX_MIR BIT(16) +#define AN8855_PORT_VLAN GENMASK(1, 0) + +enum an8855_port_mode { + /* Port Matrix Mode: Frames are forwarded by the PCR_MATRIX members. */ + AN8855_PORT_MATRIX_MODE = 0, + + /* Fallback Mode: Forward received frames with ingress ports that do + * not belong to the VLAN member. Frames whose VID is not listed on + * the VLAN table are forwarded by the PCR_MATRIX members. + */ + AN8855_PORT_FALLBACK_MODE = 1, + + /* Check Mode: Forward received frames whose ingress do not + * belong to the VLAN member. Discard frames if VID ismiddes on the + * VLAN table. + */ + AN8855_PORT_CHECK_MODE = 2, + + /* Security Mode: Discard any frame due to ingress membership + * violation or VID missed on the VLAN table. + */ + AN8855_PORT_SECURITY_MODE = 3, +}; + +/* Register for port security control */ +#define AN8855_PSC_P(x) (0x1020800c + ((x) * 0x200)) +#define AN8855_SA_DIS BIT(4) + +/* Register for port vlan control */ +#define AN8855_PVC_P(x) (0x10208010 + ((x) * 0x200)) +#define AN8855_PORT_SPEC_REPLACE_MODE BIT(11) +#define AN8855_PVC_EG_TAG GENMASK(10, 8) +#define AN8855_VLAN_ATTR GENMASK(7, 6) +#define AN8855_PORT_SPEC_TAG BIT(5) +#define AN8855_ACC_FRM GENMASK(1, 0) + +enum an8855_vlan_port_eg_tag { + AN8855_VLAN_EG_DISABLED = 0, + AN8855_VLAN_EG_CONSISTENT = 1, + AN8855_VLAN_EG_UNTAGGED = 4, + AN8855_VLAN_EG_SWAP = 5, + AN8855_VLAN_EG_TAGGED = 6, + AN8855_VLAN_EG_STACK = 7, +}; + +enum an8855_vlan_port_attr { + AN8855_VLAN_USER = 0, + AN8855_VLAN_STACK = 1, + AN8855_VLAN_TRANSPARENT = 3, +}; + +enum an8855_vlan_port_acc_frm { + AN8855_VLAN_ACC_ALL = 0, + AN8855_VLAN_ACC_TAGGED = 1, + AN8855_VLAN_ACC_UNTAGGED = 2, +}; + +#define AN8855_PPBV1_P(x) (0x10208014 + ((x) * 0x200)) +#define AN8855_PPBV_G0_PORT_VID GENMASK(11, 0) + +#define AN8855_PORTMATRIX_P(x) (0x10208044 + ((x) * 0x200)) +#define AN8855_PORTMATRIX GENMASK(5, 0) +/* Port matrix without the CPU port that should never be removed */ +#define AN8855_USER_PORTMATRIX GENMASK(4, 0) + +/* Register for port PVID */ +#define AN8855_PVID_P(x) (0x10208048 + ((x) * 0x200)) +#define AN8855_G0_PORT_VID GENMASK(11, 0) + +/* Register for port MAC control register */ +#define AN8855_PMCR_P(x) (0x10210000 + ((x) * 0x200)) +#define AN8855_PMCR_FORCE_MODE BIT(31) +#define AN8855_PMCR_FORCE_SPEED GENMASK(30, 28) +#define AN8855_PMCR_FORCE_SPEED_5000 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x4) +#define AN8855_PMCR_FORCE_SPEED_2500 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x3) +#define AN8855_PMCR_FORCE_SPEED_1000 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x2) +#define AN8855_PMCR_FORCE_SPEED_100 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x1) +#define AN8855_PMCR_FORCE_SPEED_10 FIELD_PREP_CONST(AN8855_PMCR_FORCE_SPEED, 0x1) +#define AN8855_PMCR_FORCE_FDX BIT(25) +#define AN8855_PMCR_FORCE_LNK BIT(24) +#define AN8855_PMCR_IFG_XMIT GENMASK(21, 20) +#define AN8855_PMCR_EXT_PHY BIT(19) +#define AN8855_PMCR_MAC_MODE BIT(18) +#define AN8855_PMCR_TX_EN BIT(16) +#define AN8855_PMCR_RX_EN BIT(15) +#define AN8855_PMCR_BACKOFF_EN BIT(12) +#define AN8855_PMCR_BACKPR_EN BIT(11) +#define AN8855_PMCR_FORCE_EEE5G BIT(9) +#define AN8855_PMCR_FORCE_EEE2P5G BIT(8) +#define AN8855_PMCR_FORCE_EEE1G BIT(7) +#define AN8855_PMCR_FORCE_EEE100 BIT(6) +#define AN8855_PMCR_TX_FC_EN BIT(5) +#define AN8855_PMCR_RX_FC_EN BIT(4) + +#define AN8855_PMSR_P(x) (0x10210010 + (x) * 0x200) +#define AN8855_PMSR_SPEED GENMASK(30, 28) +#define AN8855_PMSR_SPEED_5000 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x4) +#define AN8855_PMSR_SPEED_2500 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x3) +#define AN8855_PMSR_SPEED_1000 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x2) +#define AN8855_PMSR_SPEED_100 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x1) +#define AN8855_PMSR_SPEED_10 FIELD_PREP_CONST(AN8855_PMSR_SPEED, 0x0) +#define AN8855_PMSR_DPX BIT(25) +#define AN8855_PMSR_LNK BIT(24) +#define AN8855_PMSR_EEE1G BIT(7) +#define AN8855_PMSR_EEE100M BIT(6) +#define AN8855_PMSR_RX_FC BIT(5) +#define AN8855_PMSR_TX_FC BIT(4) + +#define AN8855_PMEEECR_P(x) (0x10210004 + (x) * 0x200) +#define AN8855_LPI_MODE_EN BIT(31) +#define AN8855_WAKEUP_TIME_2500 GENMASK(23, 16) +#define AN8855_WAKEUP_TIME_1000 GENMASK(15, 8) +#define AN8855_WAKEUP_TIME_100 GENMASK(7, 0) +#define AN8855_PMEEECR2_P(x) (0x10210008 + (x) * 0x200) +#define AN8855_WAKEUP_TIME_5000 GENMASK(7, 0) + +#define AN8855_GMACCR 0x10213e00 +#define AN8855_MAX_RX_JUMBO GENMASK(7, 4) +/* 2K for 0x0, 0x1, 0x2 */ +#define AN8855_MAX_RX_JUMBO_2K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x0) +#define AN8855_MAX_RX_JUMBO_3K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x3) +#define AN8855_MAX_RX_JUMBO_4K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x4) +#define AN8855_MAX_RX_JUMBO_5K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x5) +#define AN8855_MAX_RX_JUMBO_6K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x6) +#define AN8855_MAX_RX_JUMBO_7K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x7) +#define AN8855_MAX_RX_JUMBO_8K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x8) +#define AN8855_MAX_RX_JUMBO_9K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0x9) +#define AN8855_MAX_RX_JUMBO_12K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xa) +#define AN8855_MAX_RX_JUMBO_15K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xb) +#define AN8855_MAX_RX_JUMBO_16K FIELD_PREP_CONST(AN8855_MAX_RX_JUMBO, 0xc) +#define AN8855_MAX_RX_PKT_LEN GENMASK(1, 0) +#define AN8855_MAX_RX_PKT_1518_1522 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x0) +#define AN8855_MAX_RX_PKT_1536 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x1) +#define AN8855_MAX_RX_PKT_1552 FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x2) +#define AN8855_MAX_RX_PKT_JUMBO FIELD_PREP_CONST(AN8855_MAX_RX_PKT_LEN, 0x3) + +#define AN8855_CKGCR 0x10213e1c +#define AN8855_LPI_TXIDLE_THD_MASK GENMASK(31, 14) +#define AN8855_CKG_LNKDN_PORT_STOP BIT(1) +#define AN8855_CKG_LNKDN_GLB_STOP BIT(0) + +/* Register for MIB */ +#define AN8855_PORT_MIB_COUNTER(x) (0x10214000 + (x) * 0x200) +/* Each define is an offset of AN8855_PORT_MIB_COUNTER */ +#define AN8855_PORT_MIB_TX_DROP 0x00 +#define AN8855_PORT_MIB_TX_CRC_ERR 0x04 +#define AN8855_PORT_MIB_TX_UNICAST 0x08 +#define AN8855_PORT_MIB_TX_MULTICAST 0x0c +#define AN8855_PORT_MIB_TX_BROADCAST 0x10 +#define AN8855_PORT_MIB_TX_COLLISION 0x14 +#define AN8855_PORT_MIB_TX_SINGLE_COLLISION 0x18 +#define AN8855_PORT_MIB_TX_MULTIPLE_COLLISION 0x1c +#define AN8855_PORT_MIB_TX_DEFERRED 0x20 +#define AN8855_PORT_MIB_TX_LATE_COLLISION 0x24 +#define AN8855_PORT_MIB_TX_EXCESSIVE_COLLISION 0x28 +#define AN8855_PORT_MIB_TX_PAUSE 0x2c +#define AN8855_PORT_MIB_TX_PKT_SZ_64 0x30 +#define AN8855_PORT_MIB_TX_PKT_SZ_65_TO_127 0x34 +#define AN8855_PORT_MIB_TX_PKT_SZ_128_TO_255 0x38 +#define AN8855_PORT_MIB_TX_PKT_SZ_256_TO_511 0x3 +#define AN8855_PORT_MIB_TX_PKT_SZ_512_TO_1023 0x40 +#define AN8855_PORT_MIB_TX_PKT_SZ_1024_TO_1518 0x44 +#define AN8855_PORT_MIB_TX_PKT_SZ_1519_TO_MAX 0x48 +#define AN8855_PORT_MIB_TX_BYTES 0x4c /* 64 bytes */ +#define AN8855_PORT_MIB_TX_OVERSIZE_DROP 0x54 +#define AN8855_PORT_MIB_TX_BAD_PKT_BYTES 0x58 /* 64 bytes */ +#define AN8855_PORT_MIB_RX_DROP 0x80 +#define AN8855_PORT_MIB_RX_FILTERING 0x84 +#define AN8855_PORT_MIB_RX_UNICAST 0x88 +#define AN8855_PORT_MIB_RX_MULTICAST 0x8c +#define AN8855_PORT_MIB_RX_BROADCAST 0x90 +#define AN8855_PORT_MIB_RX_ALIGN_ERR 0x94 +#define AN8855_PORT_MIB_RX_CRC_ERR 0x98 +#define AN8855_PORT_MIB_RX_UNDER_SIZE_ERR 0x9c +#define AN8855_PORT_MIB_RX_FRAG_ERR 0xa0 +#define AN8855_PORT_MIB_RX_OVER_SZ_ERR 0xa4 +#define AN8855_PORT_MIB_RX_JABBER_ERR 0xa8 +#define AN8855_PORT_MIB_RX_PAUSE 0xac +#define AN8855_PORT_MIB_RX_PKT_SZ_64 0xb0 +#define AN8855_PORT_MIB_RX_PKT_SZ_65_TO_127 0xb4 +#define AN8855_PORT_MIB_RX_PKT_SZ_128_TO_255 0xb8 +#define AN8855_PORT_MIB_RX_PKT_SZ_256_TO_511 0xbc +#define AN8855_PORT_MIB_RX_PKT_SZ_512_TO_1023 0xc0 +#define AN8855_PORT_MIB_RX_PKT_SZ_1024_TO_1518 0xc4 +#define AN8855_PORT_MIB_RX_PKT_SZ_1519_TO_MAX 0xc8 +#define AN8855_PORT_MIB_RX_BYTES 0xcc /* 64 bytes */ +#define AN8855_PORT_MIB_RX_CTRL_DROP 0xd4 +#define AN8855_PORT_MIB_RX_INGRESS_DROP 0xd8 +#define AN8855_PORT_MIB_RX_ARL_DROP 0xdc +#define AN8855_PORT_MIB_FLOW_CONTROL_DROP 0xe0 +#define AN8855_PORT_MIB_WRED_DROP 0xe4 +#define AN8855_PORT_MIB_MIRROR_DROP 0xe8 +#define AN8855_PORT_MIB_RX_BAD_PKT_BYTES 0xec /* 64 bytes */ +#define AN8855_PORT_MIB_RXS_FLOW_SAMPLING_PKT_DROP 0xf4 +#define AN8855_PORT_MIB_RXS_FLOW_TOTAL_PKT_DROP 0xf8 +#define AN8855_PORT_MIB_PORT_CONTROL_DROP 0xfc +#define AN8855_MIB_CCR 0x10213e30 +#define AN8855_CCR_MIB_ENABLE BIT(31) +#define AN8855_CCR_RX_OCT_CNT_GOOD BIT(7) +#define AN8855_CCR_RX_OCT_CNT_BAD BIT(6) +#define AN8855_CCR_TX_OCT_CNT_GOOD BIT(5) +#define AN8855_CCR_TX_OCT_CNT_BAD BIT(4) +#define AN8855_CCR_RX_OCT_CNT_GOOD_2 BIT(3) +#define AN8855_CCR_RX_OCT_CNT_BAD_2 BIT(2) +#define AN8855_CCR_TX_OCT_CNT_GOOD_2 BIT(1) +#define AN8855_CCR_TX_OCT_CNT_BAD_2 BIT(0) +#define AN8855_CCR_MIB_ACTIVATE (AN8855_CCR_MIB_ENABLE | \ + AN8855_CCR_RX_OCT_CNT_GOOD | \ + AN8855_CCR_RX_OCT_CNT_BAD | \ + AN8855_CCR_TX_OCT_CNT_GOOD | \ + AN8855_CCR_TX_OCT_CNT_BAD | \ + AN8855_CCR_RX_OCT_CNT_BAD_2 | \ + AN8855_CCR_TX_OCT_CNT_BAD_2) +#define AN8855_MIB_CLR 0x10213e34 +#define AN8855_MIB_PORT6_CLR BIT(6) +#define AN8855_MIB_PORT5_CLR BIT(5) +#define AN8855_MIB_PORT4_CLR BIT(4) +#define AN8855_MIB_PORT3_CLR BIT(3) +#define AN8855_MIB_PORT2_CLR BIT(2) +#define AN8855_MIB_PORT1_CLR BIT(1) +#define AN8855_MIB_PORT0_CLR BIT(0) + +/* HSGMII/SGMII Configuration register */ +/* AN8855_HSGMII_AN_CSR_BASE 0x10220000 */ +#define AN8855_SGMII_REG_AN0 0x10220000 +/* AN8855_SGMII_AN_ENABLE BMCR_ANENABLE */ +/* AN8855_SGMII_AN_RESTART BMCR_ANRESTART */ +#define AN8855_SGMII_REG_AN_13 0x10220034 +#define AN8855_SGMII_REMOTE_FAULT_DIS BIT(8) +#define AN8855_SGMII_IF_MODE GENMASK(5, 0) +#define AN8855_SGMII_REG_AN_FORCE_CL37 0x10220060 +#define AN8855_RG_FORCE_AN_DONE BIT(0) + +/* AN8855_HSGMII_CSR_PCS_BASE 0x10220000 */ +#define AN8855_RG_HSGMII_PCS_CTROL_1 0x10220a00 +#define AN8855_RG_TBI_10B_MODE BIT(30) +#define AN8855_RG_AN_SGMII_MODE_FORCE 0x10220a24 +#define AN8855_RG_FORCE_CUR_SGMII_MODE GENMASK(5, 4) +#define AN8855_RG_FORCE_CUR_SGMII_SEL BIT(0) + +/* AN8855_MULTI_SGMII_CSR_BASE 0x10224000 */ +#define AN8855_SGMII_STS_CTRL_0 0x10224018 +#define AN8855_RG_LINK_MODE_P0 GENMASK(5, 4) +#define AN8855_RG_LINK_MODE_P0_SPEED_2500 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x3) +#define AN8855_RG_LINK_MODE_P0_SPEED_1000 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x2) +#define AN8855_RG_LINK_MODE_P0_SPEED_100 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x1) +#define AN8855_RG_LINK_MODE_P0_SPEED_10 FIELD_PREP_CONST(AN8855_RG_LINK_MODE_P0, 0x0) +#define AN8855_RG_FORCE_SPD_MODE_P0 BIT(2) +#define AN8855_MSG_RX_CTRL_0 0x10224100 +#define AN8855_MSG_RX_LIK_STS_0 0x10224514 +#define AN8855_RG_DPX_STS_P3 BIT(24) +#define AN8855_RG_DPX_STS_P2 BIT(16) +#define AN8855_RG_EEE1G_STS_P1 BIT(12) +#define AN8855_RG_DPX_STS_P1 BIT(8) +#define AN8855_RG_TXFC_STS_P0 BIT(2) +#define AN8855_RG_RXFC_STS_P0 BIT(1) +#define AN8855_RG_DPX_STS_P0 BIT(0) +#define AN8855_MSG_RX_LIK_STS_2 0x1022451c +#define AN8855_RG_RXFC_AN_BYPASS_P3 BIT(11) +#define AN8855_RG_RXFC_AN_BYPASS_P2 BIT(10) +#define AN8855_RG_RXFC_AN_BYPASS_P1 BIT(9) +#define AN8855_RG_TXFC_AN_BYPASS_P3 BIT(7) +#define AN8855_RG_TXFC_AN_BYPASS_P2 BIT(6) +#define AN8855_RG_TXFC_AN_BYPASS_P1 BIT(5) +#define AN8855_RG_DPX_AN_BYPASS_P3 BIT(3) +#define AN8855_RG_DPX_AN_BYPASS_P2 BIT(2) +#define AN8855_RG_DPX_AN_BYPASS_P1 BIT(1) +#define AN8855_RG_DPX_AN_BYPASS_P0 BIT(0) +#define AN8855_PHY_RX_FORCE_CTRL_0 0x10224520 +#define AN8855_RG_FORCE_TXC_SEL BIT(4) + +/* AN8855_XFI_CSR_PCS_BASE 0x10225000 */ +#define AN8855_RG_USXGMII_AN_CONTROL_0 0x10225bf8 + +/* AN8855_MULTI_PHY_RA_CSR_BASE 0x10226000 */ +#define AN8855_RG_RATE_ADAPT_CTRL_0 0x10226000 +#define AN8855_RG_RATE_ADAPT_RX_BYPASS BIT(27) +#define AN8855_RG_RATE_ADAPT_TX_BYPASS BIT(26) +#define AN8855_RG_RATE_ADAPT_RX_EN BIT(4) +#define AN8855_RG_RATE_ADAPT_TX_EN BIT(0) +#define AN8855_RATE_ADP_P0_CTRL_0 0x10226100 +#define AN8855_RG_P0_DIS_MII_MODE BIT(31) +#define AN8855_RG_P0_MII_MODE BIT(28) +#define AN8855_RG_P0_MII_RA_RX_EN BIT(3) +#define AN8855_RG_P0_MII_RA_TX_EN BIT(2) +#define AN8855_RG_P0_MII_RA_RX_MODE BIT(1) +#define AN8855_RG_P0_MII_RA_TX_MODE BIT(0) +#define AN8855_MII_RA_AN_ENABLE 0x10226300 +#define AN8855_RG_P0_RA_AN_EN BIT(0) + +/* AN8855_QP_DIG_CSR_BASE 0x1022a000 */ +#define AN8855_QP_CK_RST_CTRL_4 0x1022a310 +#define AN8855_QP_DIG_MODE_CTRL_0 0x1022a324 +#define AN8855_RG_SGMII_MODE GENMASK(5, 4) +#define AN8855_RG_SGMII_AN_EN BIT(0) +#define AN8855_QP_DIG_MODE_CTRL_1 0x1022a330 +#define AN8855_RG_TPHY_SPEED GENMASK(3, 2) + +/* AN8855_SERDES_WRAPPER_BASE 0x1022c000 */ +#define AN8855_USGMII_CTRL_0 0x1022c000 + +/* AN8855_QP_PMA_TOP_BASE 0x1022e000 */ +#define AN8855_PON_RXFEDIG_CTRL_0 0x1022e100 +#define AN8855_RG_QP_EQ_RX500M_CK_SEL BIT(12) +#define AN8855_PON_RXFEDIG_CTRL_9 0x1022e124 +#define AN8855_RG_QP_EQ_LEQOSC_DLYCNT GENMASK(2, 0) + +#define AN8855_SS_LCPLL_PWCTL_SETTING_2 0x1022e208 +#define AN8855_RG_NCPO_ANA_MSB GENMASK(17, 16) +#define AN8855_SS_LCPLL_TDC_FLT_2 0x1022e230 +#define AN8855_RG_LCPLL_NCPO_VALUE GENMASK(30, 0) +#define AN8855_SS_LCPLL_TDC_FLT_5 0x1022e23c +#define AN8855_RG_LCPLL_NCPO_CHG BIT(24) +#define AN8855_SS_LCPLL_TDC_PCW_1 0x1022e248 +#define AN8855_RG_LCPLL_PON_HRDDS_PCW_NCPO_GPON GENMASK(30, 0) +#define AN8855_INTF_CTRL_8 0x1022e320 +#define AN8855_INTF_CTRL_9 0x1022e324 +#define AN8855_INTF_CTRL_10 0x1022e328 +#define AN8855_RG_DA_QP_TX_FIR_C2_SEL BIT(29) +#define AN8855_RG_DA_QP_TX_FIR_C2_FORCE GENMASK(28, 24) +#define AN8855_RG_DA_QP_TX_FIR_C1_SEL BIT(21) +#define AN8855_RG_DA_QP_TX_FIR_C1_FORCE GENMASK(20, 16) +#define AN8855_INTF_CTRL_11 0x1022e32c +#define AN8855_RG_DA_QP_TX_FIR_C0B_SEL BIT(6) +#define AN8855_RG_DA_QP_TX_FIR_C0B_FORCE GENMASK(5, 0) +#define AN8855_PLL_CTRL_0 0x1022e400 +#define AN8855_RG_PHYA_AUTO_INIT BIT(0) +#define AN8855_PLL_CTRL_2 0x1022e408 +#define AN8855_RG_DA_QP_PLL_SDM_IFM_INTF BIT(30) +#define AN8855_RG_DA_QP_PLL_RICO_SEL_INTF BIT(29) +#define AN8855_RG_DA_QP_PLL_POSTDIV_EN_INTF BIT(28) +#define AN8855_RG_DA_QP_PLL_PHY_CK_EN_INTF BIT(27) +#define AN8855_RG_DA_QP_PLL_PFD_OFFSET_EN_INTRF BIT(26) +#define AN8855_RG_DA_QP_PLL_PFD_OFFSET_INTF GENMASK(25, 24) +#define AN8855_RG_DA_QP_PLL_PCK_SEL_INTF BIT(22) +#define AN8855_RG_DA_QP_PLL_KBAND_PREDIV_INTF GENMASK(21, 20) +#define AN8855_RG_DA_QP_PLL_IR_INTF GENMASK(19, 16) +#define AN8855_RG_DA_QP_PLL_ICOIQ_EN_INTF BIT(14) +#define AN8855_RG_DA_QP_PLL_FBKSEL_INTF GENMASK(13, 12) +#define AN8855_RG_DA_QP_PLL_BR_INTF GENMASK(10, 8) +#define AN8855_RG_DA_QP_PLL_BPD_INTF GENMASK(7, 6) +#define AN8855_RG_DA_QP_PLL_BPA_INTF GENMASK(4, 2) +#define AN8855_RG_DA_QP_PLL_BC_INTF GENMASK(1, 0) +#define AN8855_PLL_CTRL_3 0x1022e40c +#define AN8855_RG_DA_QP_PLL_SSC_PERIOD_INTF GENMASK(31, 16) +#define AN8855_RG_DA_QP_PLL_SSC_DELTA_INTF GENMASK(15, 0) +#define AN8855_PLL_CTRL_4 0x1022e410 +#define AN8855_RG_DA_QP_PLL_SDM_HREN_INTF GENMASK(4, 3) +#define AN8855_RG_DA_QP_PLL_ICOLP_EN_INTF BIT(2) +#define AN8855_RG_DA_QP_PLL_SSC_DIR_DLY_INTF GENMASK(1, 0) +#define AN8855_PLL_CK_CTRL_0 0x1022e414 +#define AN8855_RG_DA_QP_PLL_TDC_TXCK_SEL_INTF BIT(9) +#define AN8855_RG_DA_QP_PLL_SDM_DI_EN_INTF BIT(8) +#define AN8855_RX_DLY_0 0x1022e614 +#define AN8855_RG_QP_RX_SAOSC_EN_H_DLY GENMASK(13, 8) +#define AN8855_RG_QP_RX_PI_CAL_EN_H_DLY GENMASK(7, 0) +#define AN8855_RX_CTRL_2 0x1022e630 +#define AN8855_RG_QP_RX_EQ_EN_H_DLY GENMASK(28, 16) +#define AN8855_RX_CTRL_5 0x1022e63c +#define AN8855_RG_FREDET_CHK_CYCLE GENMASK(29, 10) +#define AN8855_RX_CTRL_6 0x1022e640 +#define AN8855_RG_FREDET_GOLDEN_CYCLE GENMASK(19, 0) +#define AN8855_RX_CTRL_7 0x1022e644 +#define AN8855_RG_FREDET_TOLERATE_CYCLE GENMASK(19, 0) +#define AN8855_RX_CTRL_8 0x1022e648 +#define AN8855_RG_DA_QP_SAOSC_DONE_TIME GENMASK(27, 16) +#define AN8855_RG_DA_QP_LEQOS_EN_TIME GENMASK(14, 0) +#define AN8855_RX_CTRL_26 0x1022e690 +#define AN8855_RG_QP_EQ_RETRAIN_ONLY_EN BIT(26) +#define AN8855_RG_LINK_NE_EN BIT(24) +#define AN8855_RG_LINK_ERRO_EN BIT(23) +#define AN8855_RX_CTRL_42 0x1022e6d0 +#define AN8855_RG_QP_EQ_EN_DLY GENMASK(12, 0) + +/* AN8855_QP_ANA_CSR_BASE 0x1022f000 */ +#define AN8855_RG_QP_RX_DAC_EN 0x1022f000 +#define AN8855_RG_QP_SIGDET_HF GENMASK(17, 16) +#define AN8855_RG_QP_RXAFE_RESERVE 0x1022f004 +#define AN8855_RG_QP_CDR_PD_10B_EN BIT(11) +#define AN8855_RG_QP_CDR_LPF_BOT_LIM 0x1022f008 +#define AN8855_RG_QP_CDR_LPF_KP_GAIN GENMASK(26, 24) +#define AN8855_RG_QP_CDR_LPF_KI_GAIN GENMASK(22, 20) +#define AN8855_RG_QP_CDR_LPF_MJV_LIM 0x1022f00c +#define AN8855_RG_QP_CDR_LPF_RATIO GENMASK(5, 4) +#define AN8855_RG_QP_CDR_LPF_SETVALUE 0x1022f014 +#define AN8855_RG_QP_CDR_PR_BUF_IN_SR GENMASK(31, 29) +#define AN8855_RG_QP_CDR_PR_BETA_SEL GENMASK(28, 25) +#define AN8855_RG_QP_CDR_PR_CKREF_DIV1 0x1022f018 +#define AN8855_RG_QP_CDR_PR_KBAND_DIV GENMASK(26, 24) +#define AN8855_RG_QP_CDR_PR_DAC_BAND GENMASK(12, 8) +#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE 0x1022f01c +#define AN8855_RG_QP_CDR_PR_XFICK_EN BIT(30) +#define AN8855_RG_QP_CDR_PR_KBAND_PCIE_MODE BIT(6) +#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE_MASK GENMASK(5, 0) +#define AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF 0x1022f020 +#define AN8855_RG_QP_CDR_PHYCK_SEL GENMASK(17, 16) +#define AN8855_RG_QP_CDR_PHYCK_RSTB BIT(13) +#define AN8855_RG_QP_CDR_PHYCK_DIV GENMASK(12, 6) +#define AN8855_RG_QP_TX_MODE 0x1022f028 +#define AN8855_RG_QP_TX_RESERVE GENMASK(31, 16) +#define AN8855_RG_QP_TX_MODE_16B_EN BIT(0) +#define AN8855_RG_QP_PLL_IPLL_DIG_PWR_SEL 0x1022f03c +#define AN8855_RG_QP_PLL_SDM_ORD 0x1022f040 +#define AN8855_RG_QP_PLL_SSC_PHASE_INI BIT(4) +#define AN8855_RG_QP_PLL_SSC_TRI_EN BIT(3) + +/* AN8855_ETHER_SYS_BASE 0x1028c800 */ +#define AN8855_RG_GPHY_AFE_PWD 0x1028c840 +#define AN8855_RG_GPHY_SMI_ADDR 0x1028c848 + +#define MIB_DESC(_s, _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + } + +struct an8855_mib_desc { + unsigned int size; + unsigned int offset; + const char *name; +}; + +struct an8855_fdb { + u16 vid; + u8 port_mask; + u16 aging; + u8 mac[6]; + bool noarp; + u8 live; + u8 type; + u8 fid; + u8 ivl; +}; + +struct an8855_priv { + struct device *dev; + struct dsa_switch *ds; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + /* Protect ATU or VLAN table access */ + struct mutex reg_mutex; + + struct phylink_pcs pcs; + + u8 mirror_rx; + u8 mirror_tx; + u8 port_isolated_map; + + bool phy_require_calib; +}; + +#endif /* __AN8855_H */ diff --git a/drivers/net/mdio/mdio-an8855.c b/drivers/net/mdio/mdio-an8855.c new file mode 100644 index 000000000000..5feba72c021b --- /dev/null +++ b/drivers/net/mdio/mdio-an8855.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MDIO passthrough driver for Airoha AN8855 Switch + */ + +#include +#include +#include +#include + +static int an855_phy_restore_page(struct an8855_mfd_priv *priv, + int phy) __must_hold(&priv->bus->mdio_lock) +{ + /* Check PHY page only for addr shared with switch */ + if (phy != priv->switch_addr) + return 0; + + /* Don't restore page if it's not set to switch page */ + if (priv->current_page != FIELD_GET(AN8855_PHY_PAGE, + AN8855_PHY_PAGE_EXTENDED_4)) + return 0; + + /* Restore page to 0, PHY might change page right after but that + * will be ignored as it won't be a switch page. + */ + return an8855_mii_set_page(priv, phy, AN8855_PHY_PAGE_STANDARD); +} + +static int an8855_phy_read(struct mii_bus *bus, int phy, int regnum) +{ + struct an8855_mfd_priv *priv = bus->priv; + struct mii_bus *real_bus = priv->bus; + int ret; + + mutex_lock_nested(&real_bus->mdio_lock, MDIO_MUTEX_NESTED); + + ret = an855_phy_restore_page(priv, phy); + if (ret) + goto exit; + + ret = __mdiobus_read(real_bus, phy, regnum); +exit: + mutex_unlock(&real_bus->mdio_lock); + + return ret; +} + +static int an8855_phy_write(struct mii_bus *bus, int phy, int regnum, u16 val) +{ + struct an8855_mfd_priv *priv = bus->priv; + struct mii_bus *real_bus = priv->bus; + int ret; + + mutex_lock_nested(&real_bus->mdio_lock, MDIO_MUTEX_NESTED); + + ret = an855_phy_restore_page(priv, phy); + if (ret) + goto exit; + + ret = __mdiobus_write(real_bus, phy, regnum, val); +exit: + mutex_unlock(&real_bus->mdio_lock); + + return ret; +} + +static int an8855_mdio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct an8855_mfd_priv *priv; + struct mii_bus *bus; + int ret; + + /* Get priv of MFD */ + priv = dev_get_drvdata(dev->parent); + + bus = devm_mdiobus_alloc(dev); + if (!bus) + return -ENOMEM; + + bus->priv = priv; + bus->name = KBUILD_MODNAME "-mii"; + snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", + priv->switch_addr); + bus->parent = dev; + bus->read = an8855_phy_read; + bus->write = an8855_phy_write; + + ret = devm_of_mdiobus_register(dev, bus, dev->of_node); + if (ret) + return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); + + return ret; +} + +static const struct of_device_id an8855_mdio_of_match[] = { + { .compatible = "airoha,an8855-mdio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, an8855_mdio_of_match); + +static struct platform_driver an8855_mdio_driver = { + .probe = an8855_mdio_probe, + .driver = { + .name = "an8855-mdio", + .of_match_table = an8855_mdio_of_match, + }, +}; +module_platform_driver(an8855_mdio_driver); + +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Driver for AN8855 MDIO passthrough"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/adm6996.c b/drivers/net/phy/adm6996.c new file mode 100644 index 000000000000..d917427419ad --- /dev/null +++ b/drivers/net/phy/adm6996.c @@ -0,0 +1,1241 @@ +/* + * ADM6996 switch driver + * + * swconfig interface based on ar8216.c + * + * Copyright (c) 2008 Felix Fietkau + * VLAN support Copyright (c) 2010, 2011 Peter Lebbing + * Copyright (c) 2013 Hauke Mehrtens + * Copyright (c) 2014 Matti Laakso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/*#define DEBUG 1*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "adm6996.h" + +MODULE_DESCRIPTION("Infineon ADM6996 Switch"); +MODULE_AUTHOR("Felix Fietkau, Peter Lebbing "); +MODULE_LICENSE("GPL"); + +static const char * const adm6996_model_name[] = +{ + NULL, + "ADM6996FC", + "ADM6996M", + "ADM6996L" +}; + +struct adm6996_mib_desc { + unsigned int offset; + const char *name; +}; + +struct adm6996_priv { + struct switch_dev dev; + void *priv; + + u8 eecs; + u8 eesk; + u8 eedi; + + enum adm6996_model model; + + bool enable_vlan; + bool vlan_enabled; /* Current hardware state */ + +#ifdef DEBUG + u16 addr; /* Debugging: register address to operate on */ +#endif + + u16 pvid[ADM_NUM_PORTS]; /* Primary VLAN ID */ + u8 tagged_ports; + + u16 vlan_id[ADM_NUM_VLANS]; + u8 vlan_table[ADM_NUM_VLANS]; /* bitmap, 1 = port is member */ + u8 vlan_tagged[ADM_NUM_VLANS]; /* bitmap, 1 = tagged member */ + + struct mutex mib_lock; + char buf[2048]; + + struct mutex reg_mutex; + + /* use abstraction for regops, we want to add gpio support in the future */ + u16 (*read)(struct adm6996_priv *priv, enum admreg reg); + void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val); +}; + +#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) +#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) + +#define MIB_DESC(_o, _n) \ + { \ + .offset = (_o), \ + .name = (_n), \ + } + +static const struct adm6996_mib_desc adm6996_mibs[] = { + MIB_DESC(ADM_CL0, "RxPacket"), + MIB_DESC(ADM_CL6, "RxByte"), + MIB_DESC(ADM_CL12, "TxPacket"), + MIB_DESC(ADM_CL18, "TxByte"), + MIB_DESC(ADM_CL24, "Collision"), + MIB_DESC(ADM_CL30, "Error"), +}; + +#define ADM6996_MIB_RXB_ID 1 +#define ADM6996_MIB_TXB_ID 3 + +static inline u16 +r16(struct adm6996_priv *priv, enum admreg reg) +{ + return priv->read(priv, reg); +} + +static inline void +w16(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + priv->write(priv, reg, val); +} + +/* Minimum timing constants */ +#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */ +#define EEDI_SETUP_TIME 1 /* 1us - max(adm 10ns, 93c 400ns) */ +#define EECS_SETUP_TIME 1 /* 1us - max(adm no, 93c 200ns) */ + +static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + /* Bit bang from MSB to LSB */ + for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) { + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Output on rising edge */ + gpio_set_value(priv->eedi, (mask & buf[i])); + udelay(EEDI_SETUP_TIME); + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + u8 byte; + + /* Bit bang from MSB to LSB */ + for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) { + u8 gp; + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Input on rising edge */ + gp = gpio_get_value(priv->eedi); + if (gp) + byte |= mask; + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + + *buf++ = byte; + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +/* Advance clock(s) */ +static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks) +{ + int i; + for (i = 0; i < clocks; i++) { + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + } +} + +static u16 +adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg) +{ + /* cmd: 01 10 T DD R RRRRRR */ + u8 bits[6] = { + 0xFF, 0xFF, 0xFF, 0xFF, + (0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6), + ((reg&63)<<2) + }; + + u8 rbits[4]; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + adm6996_gpio_write(priv, 0, bits, 46); + gpio_direction_input(priv->eedi); + adm6996_gpio_adclk(priv, 2); + adm6996_gpio_read(priv, 0, rbits, 32); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + + /* EEPROM has 16-bit registers, but pumps out two registers in one request */ + return (reg & 0x01 ? (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3])); +} + +/* Write chip configuration register */ +/* Follow 93c66 timing and chip's min EEPROM timing requirement */ +static void +adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + /* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */ + u8 bits[4] = { + (0x05 << 5) | (reg >> 3), + (reg << 5) | (u8)(val >> 11), + (u8)(val >> 3), + (u8)(val << 5) + }; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + /* Write cmd. Total 27 bits */ + adm6996_gpio_write(priv, 1, bits, 27); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + gpio_direction_input(priv->eedi); +} + +static u16 +adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, PHYADDR(reg)); +} + +static void +adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, PHYADDR(reg), val); +} + +static int +adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1) + return -EINVAL; + + priv->enable_vlan = val->value.i; + + return 0; +}; + +static int +adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->enable_vlan; + + return 0; +}; + +#ifdef DEBUG + +static int +adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1023) + return -EINVAL; + + priv->addr = val->value.i; + + return 0; +}; + +static int +adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->addr; + + return 0; +}; + +static int +adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 65535) + return -EINVAL; + + w16(priv, priv->addr, val->value.i); + + return 0; +}; + +static int +adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = r16(priv, priv->addr); + + return 0; +}; + +#endif /* def DEBUG */ + +static int +adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_pvid port %d vlan %d\n", port, vlan); + + if (vlan > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->pvid[port] = vlan; + + return 0; +} + +static int +adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_pvid port %d\n", port); + *vlan = priv->pvid[port]; + + return 0; +} + +static int +adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i); + + if (val->value.i > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->vlan_id[val->port_vlan] = val->value.i; + + return 0; +}; + +static int +adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_vid port %d\n", val->port_vlan); + + val->value.i = priv->vlan_id[val->port_vlan]; + + return 0; +}; + +static int +adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + u8 tagged = priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("get_ports port_vlan %d\n", val->port_vlan); + + val->len = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + + return 0; +}; + +static int +adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 *ports = &priv->vlan_table[val->port_vlan]; + u8 *tagged = &priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("set_ports port_vlan %d ports", val->port_vlan); + + *ports = 0; + *tagged = 0; + + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + +#ifdef DEBUG + pr_cont(" %d%s", p->id, + ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : + "")); +#endif + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + *tagged |= (1 << p->id); + priv->tagged_ports |= (1 << p->id); + } + + *ports |= (1 << p->id); + } + +#ifdef DEBUG + pr_cont("\n"); +#endif + + return 0; +}; + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_enable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_OTBE_MASK); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg &= ~(ADM_IFNTE_MASK); + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg |= ADM_VID_CHECK_MASK; + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg |= ADM_NTTE; + reg &= ~(ADM_RVID1); + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + w16(priv, ADM_SYSC3, reg); +} + +static void +adm6996_enable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + reg |= ADM_MAC_CLONE; + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + reg = ADM_VLAN_FILT_MEMBER_MASK; + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg |= ADM_OTBE_MASK; + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg |= ADM_IFNTE_MASK; + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg &= ~(ADM_VID_CHECK_MASK); + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg &= ~(ADM_NTTE); + reg |= ADM_RVID1; + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + w16(priv, ADM_VLAN_MAP(i), 0); + } + + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + reg &= ~(ADM_MAC_CLONE); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_port_pvids(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + reg = r16(priv, adm_portcfg[i]); + reg &= ~(ADM_PORTCFG_PVID_MASK); + reg |= ADM_PORTCFG_PVID(priv->pvid[i]); + if (priv->model == ADM6996L) { + if (priv->tagged_ports & (1 << i)) + reg |= (1 << 4); + else + reg &= ~(1 << 4); + } + w16(priv, adm_portcfg[i], reg); + } + + w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); + w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P2_PVID_VAL(priv->pvid[2]); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = ADM_P3_PVID_VAL(priv->pvid[3]); + reg |= ADM_P4_PVID_VAL(priv->pvid[4]); + w16(priv, ADM_P3_P4_PVID, reg); + reg = r16(priv, ADM_P5_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P5_PVID_VAL(priv->pvid[5]); + w16(priv, ADM_P5_PVID, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_vlan_filters(struct adm6996_priv *priv) +{ + u8 ports, tagged; + u16 vid, reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + vid = priv->vlan_id[i]; + ports = priv->vlan_table[i]; + tagged = priv->vlan_tagged[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_FILT_H(i), 0); + w16(priv, ADM_VLAN_FILT_L(i), 0); + continue; + } + + reg = ADM_VLAN_FILT_MEMBER(ports); + reg |= ADM_VLAN_FILT_TAGGED(tagged); + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } +} + +static void +adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv) +{ + u8 ports; + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + ports = priv->vlan_table[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_MAP(i), 0); + continue; + } else { + reg = ADM_VLAN_FILT(ports); + w16(priv, ADM_VLAN_MAP(i), reg); + } + } +} + +static int +adm6996_hw_apply(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("hw_apply\n"); + + mutex_lock(&priv->reg_mutex); + + if (!priv->enable_vlan) { + if (priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_disable_vlan_6996l(priv); + else + adm6996_disable_vlan(priv); + priv->vlan_enabled = 0; + } + goto out; + } + + if (!priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_enable_vlan_6996l(priv); + else + adm6996_enable_vlan(priv); + priv->vlan_enabled = 1; + } + + adm6996_apply_port_pvids(priv); + if (priv->model == ADM6996L) + adm6996_apply_vlan_filters_6996l(priv); + else + adm6996_apply_vlan_filters(priv); + +out: + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +/* + * Reset the switch + * + * The ADM6996 can't do a software-initiated reset, so we just initialise the + * registers we support in this driver. + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_perform_reset (struct adm6996_priv *priv) +{ + int i; + + /* initialize port and vlan settings */ + for (i = 0; i < ADM_NUM_PORTS - 1; i++) { + w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT | + ADM_PORTCFG_PVID(0)); + } + w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU); + + if (priv->model == ADM6996M || priv->model == ADM6996FC) { + /* reset all PHY ports */ + for (i = 0; i < ADM_PHY_PORTS; i++) { + w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); + } + } + + priv->enable_vlan = 0; + priv->vlan_enabled = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + priv->pvid[i] = 0; + } + + for (i = 0; i < ADM_NUM_VLANS; i++) { + priv->vlan_id[i] = i; + priv->vlan_table[i] = 0; + priv->vlan_tagged[i] = 0; + } + + if (priv->model == ADM6996M) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan(priv); + adm6996_apply_port_pvids(priv); + } else if (priv->model == ADM6996L) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan_6996l(priv); + adm6996_apply_port_pvids(priv); + } +} + +static int +adm6996_reset_switch(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("reset\n"); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int +adm6996_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct adm6996_priv *priv = to_adm(dev); + + u16 reg = 0; + + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + switch (port) { + case 0: + reg = r16(priv, ADM_PS0); + break; + case 1: + reg = r16(priv, ADM_PS0); + reg = reg >> 8; + break; + case 2: + reg = r16(priv, ADM_PS1); + break; + case 3: + reg = r16(priv, ADM_PS1); + reg = reg >> 8; + break; + case 4: + reg = r16(priv, ADM_PS1); + reg = reg >> 12; + break; + case 5: + reg = r16(priv, ADM_PS2); + /* Bits 0, 1, 3 and 4. */ + reg = (reg & 3) | ((reg & 24) >> 1); + break; + default: + return -EINVAL; + } + + link->link = reg & ADM_PS_LS; + if (!link->link) + return 0; + link->aneg = true; + link->duplex = reg & ADM_PS_DS; + link->tx_flow = reg & ADM_PS_FCS; + link->rx_flow = reg & ADM_PS_FCS; + if (reg & ADM_PS_SS) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +adm6996_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + int port; + char *buf = priv->buf; + int i, len = 0; + u32 reg = 0; + + port = val->port_vlan; + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "Port %d MIB counters\n", + port); + + for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) { + reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16; + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %u\n", + adm6996_mibs[i].name, + reg); + } + + mutex_unlock(&priv->mib_lock); + + val->value.s = buf; + val->len = len; + + return 0; +} + +static int +adm6996_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct adm6996_priv *priv = to_adm(dev); + int id; + u32 reg = 0; + + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + id = ADM6996_MIB_TXB_ID; + reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; + stats->tx_bytes = reg; + + id = ADM6996_MIB_RXB_ID; + reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; + stats->rx_bytes = reg; + + mutex_unlock(&priv->mib_lock); + + return 0; +} + +static struct switch_attr adm6996_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLANs", + .set = adm6996_set_enable_vlan, + .get = adm6996_get_enable_vlan, + }, +#ifdef DEBUG + { + .type = SWITCH_TYPE_INT, + .name = "addr", + .description = + "Direct register access: set register address (0 - 1023)", + .set = adm6996_set_addr, + .get = adm6996_get_addr, + }, + { + .type = SWITCH_TYPE_INT, + .name = "data", + .description = + "Direct register access: read/write to register (0 - 65535)", + .set = adm6996_set_data, + .get = adm6996_get_data, + }, +#endif /* def DEBUG */ +}; + +static struct switch_attr adm6996_port[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = adm6996_sw_get_port_mib, + }, +}; + +static struct switch_attr adm6996_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID", + .set = adm6996_set_vid, + .get = adm6996_get_vid, + }, +}; + +static struct switch_dev_ops adm6996_ops = { + .attr_global = { + .attr = adm6996_globals, + .n_attr = ARRAY_SIZE(adm6996_globals), + }, + .attr_port = { + .attr = adm6996_port, + .n_attr = ARRAY_SIZE(adm6996_port), + }, + .attr_vlan = { + .attr = adm6996_vlan, + .n_attr = ARRAY_SIZE(adm6996_vlan), + }, + .get_port_pvid = adm6996_get_pvid, + .set_port_pvid = adm6996_set_pvid, + .get_vlan_ports = adm6996_get_ports, + .set_vlan_ports = adm6996_set_ports, + .apply_config = adm6996_hw_apply, + .reset_switch = adm6996_reset_switch, + .get_port_link = adm6996_get_port_link, + .get_port_stats = adm6996_get_port_stats, +}; + +static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev) +{ + struct switch_dev *swdev; + u16 test, old; + + if (!priv->model) { + /* Detect type of chip */ + old = r16(priv, ADM_VID_CHECK); + test = old ^ (1 << 12); + w16(priv, ADM_VID_CHECK, test); + test ^= r16(priv, ADM_VID_CHECK); + if (test & (1 << 12)) { + /* + * Bit 12 of this register is read-only. + * This is the FC model. + */ + priv->model = ADM6996FC; + } else { + /* Bit 12 is read-write. This is the M model. */ + priv->model = ADM6996M; + w16(priv, ADM_VID_CHECK, old); + } + } + + swdev = &priv->dev; + swdev->name = (adm6996_model_name[priv->model]); + swdev->cpu_port = ADM_CPU_PORT; + swdev->ports = ADM_NUM_PORTS; + swdev->vlans = ADM_NUM_VLANS; + swdev->ops = &adm6996_ops; + swdev->alias = alias; + + /* The ADM6996L connected through GPIOs does not support any switch + status calls */ + if (priv->model == ADM6996L) { + adm6996_ops.attr_port.n_attr = 0; + adm6996_ops.get_port_link = NULL; + } + + pr_info ("%s: %s model PHY found.\n", alias, swdev->name); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + + if (priv->model == ADM6996M || priv->model == ADM6996L) { + return register_switch(swdev, netdev); + } + + return -ENODEV; +} + +static int adm6996_config_init(struct phy_device *pdev) +{ + struct adm6996_priv *priv; + int ret; + + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + + if (pdev->mdio.addr != 0) { + pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n" + , pdev->attached_dev->name, pdev->mdio.addr); + return 0; + } + + priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + priv->priv = pdev; + priv->read = adm6996_read_mii_reg; + priv->write = adm6996_write_mii_reg; + + ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev); + if (ret < 0) + return ret; + + pdev->priv = priv; + + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 + */ +static int adm6996_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 + */ +static int adm6996_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int adm6996_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + /* Our custom registers are at PHY addresses 0-10. Claim those. */ + if (dev->mdio.addr > 10) + return 0; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; + if (reg != ADM_SIG0_VAL) + return 0; + + reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; + if (reg != ADM_SIG1_VAL) + return 0; + + dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; + + return 0; +} + +static int adm6996_probe(struct phy_device *pdev) +{ + return 0; +} + +static void adm6996_remove(struct phy_device *pdev) +{ + struct adm6996_priv *priv = phy_to_adm(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); +} + +static int adm6996_soft_reset(struct phy_device *phydev) +{ + /* we don't need an extra reset */ + return 0; +} + +static struct phy_driver adm6996_phy_driver = { + .name = "Infineon ADM6996", + .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = adm6996_probe, + .remove = adm6996_remove, + .config_init = &adm6996_config_init, + .config_aneg = &adm6996_config_aneg, + .read_status = &adm6996_read_status, + .soft_reset = adm6996_soft_reset, +}; + +static int adm6996_gpio_probe(struct platform_device *pdev) +{ + struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data; + struct adm6996_priv *priv; + int ret; + + if (!pdata) + return -EINVAL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + + priv->eecs = pdata->eecs; + priv->eedi = pdata->eedi; + priv->eesk = pdata->eesk; + + priv->model = pdata->model; + priv->read = adm6996_read_gpio_reg; + priv->write = adm6996_write_gpio_reg; + + ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk"); + if (ret) + return ret; + + ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static void adm6996_gpio_remove(struct platform_device *pdev) +{ + struct adm6996_priv *priv = platform_get_drvdata(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); +} + +static struct platform_driver adm6996_gpio_driver = { + .probe = adm6996_gpio_probe, + .remove_new = adm6996_gpio_remove, + .driver = { + .name = "adm6996_gpio", + }, +}; + +static int __init adm6996_init(void) +{ + int err; + + phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); + err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE); + if (err) + return err; + + err = platform_driver_register(&adm6996_gpio_driver); + if (err) + phy_driver_unregister(&adm6996_phy_driver); + + return err; +} + +static void __exit adm6996_exit(void) +{ + platform_driver_unregister(&adm6996_gpio_driver); + phy_driver_unregister(&adm6996_phy_driver); +} + +module_init(adm6996_init); +module_exit(adm6996_exit); diff --git a/drivers/net/phy/adm6996.h b/drivers/net/phy/adm6996.h new file mode 100644 index 000000000000..6fd460a46594 --- /dev/null +++ b/drivers/net/phy/adm6996.h @@ -0,0 +1,186 @@ +/* + * ADM6996 switch driver + * + * Copyright (c) 2008 Felix Fietkau + * Copyright (c) 2010,2011 Peter Lebbing + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __ADM6996_H +#define __ADM6996_H + +/* + * ADM_PHY_PORTS: Number of ports with a PHY. + * We only control ports 0 to 3, because if 4 is connected, it is most likely + * not connected to the switch but to a separate MII and MAC for the WAN port. + */ +#define ADM_PHY_PORTS 4 +#define ADM_NUM_PORTS 6 +#define ADM_CPU_PORT 5 + +#define ADM_NUM_VLANS 16 +#define ADM_VLAN_MAX_ID 4094 + +enum admreg { + ADM_EEPROM_BASE = 0x0, + ADM_P0_CFG = ADM_EEPROM_BASE + 1, + ADM_P1_CFG = ADM_EEPROM_BASE + 3, + ADM_P2_CFG = ADM_EEPROM_BASE + 5, + ADM_P3_CFG = ADM_EEPROM_BASE + 7, + ADM_P4_CFG = ADM_EEPROM_BASE + 8, + ADM_P5_CFG = ADM_EEPROM_BASE + 9, + ADM_SYSC0 = ADM_EEPROM_BASE + 0xa, + ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe, + ADM_SYSC3 = ADM_EEPROM_BASE + 0x11, + /* Input Force No Tag Enable */ + ADM_IFNTE = ADM_EEPROM_BASE + 0x20, + ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26, + ADM_P0_PVID = ADM_EEPROM_BASE + 0x28, + ADM_P1_PVID = ADM_EEPROM_BASE + 0x29, + /* Output Tag Bypass Enable and P2 PVID */ + ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a, + ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b, + ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c, + ADM_EEPROM_EXT_BASE = 0x40, +#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) +#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) +#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n) + ADM_COUNTER_BASE = 0xa0, + ADM_SIG0 = ADM_COUNTER_BASE + 0, + ADM_SIG1 = ADM_COUNTER_BASE + 1, + ADM_PS0 = ADM_COUNTER_BASE + 2, + ADM_PS1 = ADM_COUNTER_BASE + 3, + ADM_PS2 = ADM_COUNTER_BASE + 4, + ADM_CL0 = ADM_COUNTER_BASE + 8, /* RxPacket */ + ADM_CL6 = ADM_COUNTER_BASE + 0x1a, /* RxByte */ + ADM_CL12 = ADM_COUNTER_BASE + 0x2c, /* TxPacket */ + ADM_CL18 = ADM_COUNTER_BASE + 0x3e, /* TxByte */ + ADM_CL24 = ADM_COUNTER_BASE + 0x50, /* Coll */ + ADM_CL30 = ADM_COUNTER_BASE + 0x62, /* Err */ +#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2) + ADM_PHY_BASE = 0x200, +#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) +}; + +/* Chip identification patterns */ +#define ADM_SIG0_MASK 0xffff +#define ADM_SIG0_VAL 0x1023 +#define ADM_SIG1_MASK 0xffff +#define ADM_SIG1_VAL 0x0007 + +enum { + ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ + ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ + ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ + ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ + ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ + ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ + ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ + ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ + ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ + ADM_PHYCFG_INIT = ( + ADM_PHYCFG_RST | + ADM_PHYCFG_SPEED_100 | + ADM_PHYCFG_ANEN | + ADM_PHYCFG_ANEN_RST + ) +}; + +enum { + ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ + ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ + ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ + ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ + ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ + ADM_PORTCFG_PD = (1 << 5), /* Port disable */ + ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority + * 1 = TOS based priority */ + ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ + ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ + ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ + ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ + ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ + + ADM_PORTCFG_INIT = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_AN | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_DPLX | + ADM_PORTCFG_CAM + ), + ADM_PORTCFG_CPU = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_OT | + ADM_PORTCFG_DPLX + ), +}; + +#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) +#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) +#define ADM_PORTCFG_PVID_MASK (0xf << 10) + +#define ADM_IFNTE_MASK (0x3f << 9) +#define ADM_VID_CHECK_MASK (0x3f << 6) + +#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) +#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_MASK 0xff + +#define ADM_OTBE(n) (((n) & 0x3f) << 8) +#define ADM_OTBE_MASK (0x3f << 8) + +/* ADM_SYSC0 */ +enum { + ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */ + ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */ +}; + +/* Tag Based VLAN in ADM_SYSC3 */ +#define ADM_MAC_CLONE BIT(4) +#define ADM_TBV BIT(5) + +static const u8 adm_portcfg[] = { + [0] = ADM_P0_CFG, + [1] = ADM_P1_CFG, + [2] = ADM_P2_CFG, + [3] = ADM_P3_CFG, + [4] = ADM_P4_CFG, + [5] = ADM_P5_CFG, +}; + +/* Fields in ADM_VLAN_FILT_L(x) */ +#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) +#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) +#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) +#define ADM_VLAN_FILT_MEMBER_MASK 0x3f +/* Fields in ADM_VLAN_FILT_H(x) */ +#define ADM_VLAN_FILT_VALID (1 << 15) +#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) + +/* Convert ports to a form for ADM6996L VLAN map */ +#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \ + ((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \ + ((ports & 0x10) << 3) | ((ports & 0x20) << 3)) + +/* Port status register */ +enum { + ADM_PS_LS = (1 << 0), /* Link status */ + ADM_PS_SS = (1 << 1), /* Speed status */ + ADM_PS_DS = (1 << 2), /* Duplex status */ + ADM_PS_FCS = (1 << 3) /* Flow control status */ +}; + +/* + * Split the register address in phy id and register + * it will get combined again by the mdio bus op + */ +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +#endif diff --git a/drivers/net/phy/air_an8855.c b/drivers/net/phy/air_an8855.c new file mode 100644 index 000000000000..7fab0854ef78 --- /dev/null +++ b/drivers/net/phy/air_an8855.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Christian Marangi + */ + +#include +#include +#include +#include + +#define AN8855_PHY_SELECT_PAGE 0x1f +#define AN8855_PHY_PAGE GENMASK(2, 0) +#define AN8855_PHY_PAGE_STANDARD FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x0) +#define AN8855_PHY_PAGE_EXTENDED_1 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x1) + +/* MII Registers Page 1 */ +#define AN8855_PHY_EXT_REG_14 0x14 +#define AN8855_PHY_EN_DOWN_SHIFT BIT(4) + +/* R50 Calibration regs in MDIO_MMD_VEND1 */ +#define AN8855_PHY_R500HM_RSEL_TX_AB 0x174 +#define AN8855_PHY_R50OHM_RSEL_TX_A_EN BIT(15) +#define AN8855_PHY_R50OHM_RSEL_TX_A GENMASK(14, 8) +#define AN8855_PHY_R50OHM_RSEL_TX_B_EN BIT(7) +#define AN8855_PHY_R50OHM_RSEL_TX_B GENMASK(6, 0) +#define AN8855_PHY_R500HM_RSEL_TX_CD 0x175 +#define AN8855_PHY_R50OHM_RSEL_TX_C_EN BIT(15) +#define AN8855_PHY_R50OHM_RSEL_TX_C GENMASK(14, 8) +#define AN8855_PHY_R50OHM_RSEL_TX_D_EN BIT(7) +#define AN8855_PHY_R50OHM_RSEL_TX_D GENMASK(6, 0) + +#define AN8855_SWITCH_EFUSE_R50O GENMASK(30, 24) + +/* PHY TX PAIR DELAY SELECT Register */ +#define AN8855_PHY_TX_PAIR_DLY_SEL_GBE 0x013 +#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_A_GBE GENMASK(14, 12) +#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_B_GBE GENMASK(10, 8) +#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_C_GBE GENMASK(6, 4) +#define AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_D_GBE GENMASK(2, 0) +/* PHY ADC Register */ +#define AN8855_PHY_RXADC_CTRL 0x0d8 +#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_A BIT(12) +#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_B BIT(8) +#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_C BIT(4) +#define AN8855_PHY_RG_AD_SAMNPLE_PHSEL_D BIT(0) +#define AN8855_PHY_RXADC_REV_0 0x0d9 +#define AN8855_PHY_RG_AD_RESERVE0_A GENMASK(15, 8) +#define AN8855_PHY_RG_AD_RESERVE0_B GENMASK(7, 0) +#define AN8855_PHY_RXADC_REV_1 0x0da +#define AN8855_PHY_RG_AD_RESERVE0_C GENMASK(15, 8) +#define AN8855_PHY_RG_AD_RESERVE0_D GENMASK(7, 0) + +#define AN8855_PHY_ID 0xc0ff0410 + +#define AN8855_PHY_FLAGS_EN_CALIBRATION BIT(0) + +struct air_an8855_priv { + u8 calibration_data[4]; +}; + +static const u8 dsa_r50ohm_table[] = { + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 126, 122, 117, + 112, 109, 104, 101, 97, 94, 90, 88, 84, 80, + 78, 74, 72, 68, 66, 64, 61, 58, 56, 53, + 51, 48, 47, 44, 42, 40, 38, 36, 34, 32, + 31, 28, 27, 24, 24, 22, 20, 18, 16, 16, + 14, 12, 11, 9 +}; + +static int en8855_get_r50ohm_val(struct device *dev, const char *calib_name, + u8 *dest) +{ + u32 shift_sel, val; + int ret; + int i; + + ret = nvmem_cell_read_u32(dev, calib_name, &val); + if (ret) + return ret; + + shift_sel = FIELD_GET(AN8855_SWITCH_EFUSE_R50O, val); + for (i = 0; i < ARRAY_SIZE(dsa_r50ohm_table); i++) + if (dsa_r50ohm_table[i] == shift_sel) + break; + + if (i < 8 || i >= ARRAY_SIZE(dsa_r50ohm_table)) + *dest = dsa_r50ohm_table[25]; + else + *dest = dsa_r50ohm_table[i - 8]; + + return 0; +} + +static int an8855_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct device_node *node = dev->of_node; + struct air_an8855_priv *priv; + + /* If we don't have a node, skip calib */ + if (!node) + return 0; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static int an8855_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val; + + val = phy_read_paged(phydev, AN8855_PHY_PAGE_EXTENDED_1, AN8855_PHY_EXT_REG_14); + if (val < 0) + return val; + + *data = val & AN8855_PHY_EN_DOWN_SHIFT ? DOWNSHIFT_DEV_DEFAULT_COUNT : + DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int an8855_set_downshift(struct phy_device *phydev, u8 cnt) +{ + u16 ds = cnt != DOWNSHIFT_DEV_DISABLE ? AN8855_PHY_EN_DOWN_SHIFT : 0; + + return phy_modify_paged(phydev, AN8855_PHY_PAGE_EXTENDED_1, + AN8855_PHY_EXT_REG_14, AN8855_PHY_EN_DOWN_SHIFT, + ds); +} + +static int an8855_config_init(struct phy_device *phydev) +{ + struct air_an8855_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + int ret; + + /* Enable HW auto downshift */ + ret = an8855_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT); + if (ret) + return ret; + + /* Apply calibration values, if needed. + * AN8855_PHY_FLAGS_EN_CALIBRATION signal this. + */ + if (priv && phydev->dev_flags & AN8855_PHY_FLAGS_EN_CALIBRATION) { + u8 *calibration_data = priv->calibration_data; + + ret = en8855_get_r50ohm_val(dev, "tx_a", &calibration_data[0]); + if (ret) + return ret; + + ret = en8855_get_r50ohm_val(dev, "tx_b", &calibration_data[1]); + if (ret) + return ret; + + ret = en8855_get_r50ohm_val(dev, "tx_c", &calibration_data[2]); + if (ret) + return ret; + + ret = en8855_get_r50ohm_val(dev, "tx_d", &calibration_data[3]); + if (ret) + return ret; + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_R500HM_RSEL_TX_AB, + AN8855_PHY_R50OHM_RSEL_TX_A | AN8855_PHY_R50OHM_RSEL_TX_B, + FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_A, calibration_data[0]) | + FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_B, calibration_data[1])); + if (ret) + return ret; + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_R500HM_RSEL_TX_CD, + AN8855_PHY_R50OHM_RSEL_TX_C | AN8855_PHY_R50OHM_RSEL_TX_D, + FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_C, calibration_data[2]) | + FIELD_PREP(AN8855_PHY_R50OHM_RSEL_TX_D, calibration_data[3])); + if (ret) + return ret; + } + + /* Apply values to reduce signal noise */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_TX_PAIR_DLY_SEL_GBE, + FIELD_PREP(AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_A_GBE, 0x4) | + FIELD_PREP(AN8855_PHY_CR_DA_TX_PAIR_DELKAY_SEL_C_GBE, 0x4)); + if (ret) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_CTRL, + AN8855_PHY_RG_AD_SAMNPLE_PHSEL_A | + AN8855_PHY_RG_AD_SAMNPLE_PHSEL_C); + if (ret) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_REV_0, + FIELD_PREP(AN8855_PHY_RG_AD_RESERVE0_A, 0x1)); + if (ret) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8855_PHY_RXADC_REV_1, + FIELD_PREP(AN8855_PHY_RG_AD_RESERVE0_C, 0x1)); + if (ret) + return ret; + + return 0; +} + +static int an8855_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return an8855_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int an8855_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return an8855_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +static int an8855_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, AN8855_PHY_SELECT_PAGE); +} + +static int an8855_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, AN8855_PHY_SELECT_PAGE, page); +} + +static struct phy_driver an8855_driver[] = { +{ + PHY_ID_MATCH_EXACT(AN8855_PHY_ID), + .name = "Airoha AN8855 internal PHY", + /* PHY_GBIT_FEATURES */ + .flags = PHY_IS_INTERNAL, + .probe = an8855_probe, + .config_init = an8855_config_init, + .soft_reset = genphy_soft_reset, + .get_tunable = an8855_get_tunable, + .set_tunable = an8855_set_tunable, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = an8855_read_page, + .write_page = an8855_write_page, +}, }; + +module_phy_driver(an8855_driver); + +static struct mdio_device_id __maybe_unused an8855_tbl[] = { + { PHY_ID_MATCH_EXACT(AN8855_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, an8855_tbl); + +MODULE_DESCRIPTION("Airoha AN8855 PHY driver"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/ar8216.c b/drivers/net/phy/ar8216.c new file mode 100644 index 000000000000..84b923ffc125 --- /dev/null +++ b/drivers/net/phy/ar8216.c @@ -0,0 +1,2909 @@ +/* + * ar8216.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" + +extern const struct ar8xxx_chip ar8327_chip; +extern const struct ar8xxx_chip ar8337_chip; + +#define MIB_DESC_BASIC(_s , _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + .type = AR8XXX_MIB_BASIC, \ + } + +#define MIB_DESC_EXT(_s , _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + .type = AR8XXX_MIB_EXTENDED, \ + } + +static const struct ar8xxx_mib_desc ar8216_mibs[] = { + MIB_DESC_EXT(1, AR8216_STATS_RXBROAD, "RxBroad"), + MIB_DESC_EXT(1, AR8216_STATS_RXPAUSE, "RxPause"), + MIB_DESC_EXT(1, AR8216_STATS_RXMULTI, "RxMulti"), + MIB_DESC_EXT(1, AR8216_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC_EXT(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC_EXT(1, AR8216_STATS_RXRUNT, "RxRunt"), + MIB_DESC_EXT(1, AR8216_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC_EXT(1, AR8216_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC_EXT(1, AR8216_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC_BASIC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC_EXT(2, AR8216_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC_EXT(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC_EXT(1, AR8216_STATS_FILTERED, "Filtered"), + MIB_DESC_EXT(1, AR8216_STATS_TXBROAD, "TxBroad"), + MIB_DESC_EXT(1, AR8216_STATS_TXPAUSE, "TxPause"), + MIB_DESC_EXT(1, AR8216_STATS_TXMULTI, "TxMulti"), + MIB_DESC_EXT(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC_EXT(1, AR8216_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC_EXT(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC_BASIC(2, AR8216_STATS_TXBYTE, "TxByte"), + MIB_DESC_EXT(1, AR8216_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC_EXT(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC_EXT(1, AR8216_STATS_TXDEFER, "TxDefer"), + MIB_DESC_EXT(1, AR8216_STATS_TXLATECOL, "TxLateCol"), +}; + +const struct ar8xxx_mib_desc ar8236_mibs[39] = { + MIB_DESC_EXT(1, AR8236_STATS_RXBROAD, "RxBroad"), + MIB_DESC_EXT(1, AR8236_STATS_RXPAUSE, "RxPause"), + MIB_DESC_EXT(1, AR8236_STATS_RXMULTI, "RxMulti"), + MIB_DESC_EXT(1, AR8236_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC_EXT(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC_EXT(1, AR8236_STATS_RXRUNT, "RxRunt"), + MIB_DESC_EXT(1, AR8236_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC_EXT(1, AR8236_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC_EXT(1, AR8236_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC_BASIC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC_EXT(2, AR8236_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC_EXT(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC_EXT(1, AR8236_STATS_FILTERED, "Filtered"), + MIB_DESC_EXT(1, AR8236_STATS_TXBROAD, "TxBroad"), + MIB_DESC_EXT(1, AR8236_STATS_TXPAUSE, "TxPause"), + MIB_DESC_EXT(1, AR8236_STATS_TXMULTI, "TxMulti"), + MIB_DESC_EXT(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC_EXT(1, AR8236_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC_EXT(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC_BASIC(2, AR8236_STATS_TXBYTE, "TxByte"), + MIB_DESC_EXT(1, AR8236_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC_EXT(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC_EXT(1, AR8236_STATS_TXDEFER, "TxDefer"), + MIB_DESC_EXT(1, AR8236_STATS_TXLATECOL, "TxLateCol"), +}; + +static DEFINE_MUTEX(ar8xxx_dev_list_lock); +static LIST_HEAD(ar8xxx_dev_list); + +static void +ar8xxx_mib_start(struct ar8xxx_priv *priv); +static void +ar8xxx_mib_stop(struct ar8xxx_priv *priv); + +/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */ +static int +ar8xxx_phy_poll_reset(struct mii_bus *bus) +{ + unsigned int sleep_msecs = 20; + int ret, elapsed, i; + + for (elapsed = sleep_msecs; elapsed <= 600; + elapsed += sleep_msecs) { + msleep(sleep_msecs); + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + ret = mdiobus_read(bus, i, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_RESET) + break; + if (i == AR8XXX_NUM_PHYS - 1) { + usleep_range(1000, 2000); + return 0; + } + } + } + return -ETIMEDOUT; +} + +static int +ar8xxx_phy_check_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->autoneg != AUTONEG_ENABLE) + return 0; + /* + * BMCR_ANENABLE might have been cleared + * by phy_init_hw in certain kernel versions + * therefore check for it + */ + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_ANENABLE) + return 0; + + dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n"); + ret |= BMCR_ANENABLE | BMCR_ANRESTART; + return phy_write(phydev, MII_BMCR, ret); +} + +void +ar8xxx_phy_init(struct ar8xxx_priv *priv) +{ + int i; + struct mii_bus *bus; + + bus = priv->sw_mii_bus ?: priv->mii_bus; + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + if (priv->chip->phy_fixup) + priv->chip->phy_fixup(priv, i); + + /* initialize the port itself */ + mdiobus_write(bus, i, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + if (ar8xxx_has_gige(priv)) + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + } + + ar8xxx_phy_poll_reset(bus); +} + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = bus->read(bus, phy_id, regnum); + hi = bus->read(bus, phy_id, regnum + 1); + + return (hi << 16) | lo; +} + +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = val & 0xffff; + hi = (u16) (val >> 16); + + if (priv->chip->mii_lo_first) + { + bus->write(bus, phy_id, regnum, lo); + bus->write(bus, phy_id, regnum + 1, hi); + } else { + bus->write(bus, phy_id, regnum + 1, hi); + bus->write(bus, phy_id, regnum, lo); + } +} + +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 val; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + val = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + + mutex_unlock(&bus->mdio_lock); + + return val; +} + +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + ar8xxx_mii_write32(priv, 0x10 | r2, r1, val); + + mutex_unlock(&bus->mdio_lock); +} + +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 ret; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + ret &= ~mask; + ret |= val; + ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret); + + mutex_unlock(&bus->mdio_lock); + + return ret; +} +void +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 *dbg_data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA); + mutex_unlock(&bus->mdio_lock); +} + +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); + mutex_unlock(&bus->mdio_lock); +} + +static inline void +ar8xxx_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg) +{ + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, reg); + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000); +} + +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data); + mutex_unlock(&bus->mdio_lock); +} + +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg) +{ + struct mii_bus *bus = priv->mii_bus; + u16 data; + + mutex_lock(&bus->mdio_lock); + ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); + data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); + mutex_unlock(&bus->mdio_lock); + + return data; +} + +static int +ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, + unsigned timeout) +{ + int i; + + for (i = 0; i < timeout; i++) { + u32 t; + + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + usleep_range(1000, 2000); + cond_resched(); + } + + return -ETIMEDOUT; +} + +static int +ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op) +{ + unsigned mib_func = priv->chip->mib_func; + int ret; + + lockdep_assert_held(&priv->mib_lock); + + /* Capture the hardware statistics for all ports */ + ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S)); + + /* Wait for the capturing to complete. */ + ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10); + if (ret) + goto out; + + ret = 0; + +out: + return ret; +} + +static int +ar8xxx_mib_capture(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE); +} + +static int +ar8xxx_mib_flush(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH); +} + +static void +ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush) +{ + unsigned int base; + u64 *mib_stats; + int i; + + WARN_ON(port >= priv->dev.ports); + + lockdep_assert_held(&priv->mib_lock); + + base = priv->chip->reg_port_stats_start + + priv->chip->reg_port_stats_length * port; + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + for (i = 0; i < priv->chip->num_mibs; i++) { + const struct ar8xxx_mib_desc *mib; + u64 t; + + mib = &priv->chip->mib_decs[i]; + if (mib->type > priv->mib_type) + continue; + t = ar8xxx_read(priv, base + mib->offset); + if (mib->size == 2) { + u64 hi; + + hi = ar8xxx_read(priv, base + mib->offset + 4); + t |= hi << 32; + } + + if (flush) + mib_stats[i] = 0; + else + mib_stats[i] += t; + cond_resched(); + } +} + +static void +ar8216_read_port_link(struct ar8xxx_priv *priv, int port, + struct switch_port_link *link) +{ + u32 status; + u32 speed; + + memset(link, '\0', sizeof(*link)); + + status = priv->chip->read_port_status(priv, port); + + link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO); + if (link->aneg) { + link->link = !!(status & AR8216_PORT_STATUS_LINK_UP); + } else { + link->link = true; + + if (priv->get_port_link) { + int err; + + err = priv->get_port_link(port); + if (err >= 0) + link->link = !!err; + } + } + + if (!link->link) + return; + + link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX); + link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); + link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); + + if (link->aneg && link->duplex && priv->chip->read_port_eee_status) + link->eee = priv->chip->read_port_eee_status(priv, port); + + speed = (status & AR8216_PORT_STATUS_SPEED) >> + AR8216_PORT_STATUS_SPEED_S; + + switch (speed) { + case AR8216_PORT_SPEED_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case AR8216_PORT_SPEED_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case AR8216_PORT_SPEED_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } +} + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + +static struct sk_buff * +ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv = dev->phy_ptr; + unsigned char *buf; + + if (unlikely(!priv)) + goto error; + + if (!priv->vlan) + goto send; + + if (unlikely(skb_headroom(skb) < 2)) { + if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) + goto error; + } + + buf = skb_push(skb, 2); + buf[0] = 0x10; + buf[1] = 0x80; + +send: + return skb; + +error: + dev_kfree_skb_any(skb); + return NULL; +} + +static void +ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv; + unsigned char *buf; + int port, vlan; + + priv = dev->phy_ptr; + if (!priv) + return; + + /* don't strip the header if vlan mode is disabled */ + if (!priv->vlan) + return; + + /* strip header, get vlan id */ + buf = skb->data; + skb_pull(skb, 2); + + /* check for vlan header presence */ + if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) + return; + + port = buf[0] & 0x7; + + /* no need to fix up packets coming from a tagged source */ + if (priv->vlan_tagged & (1 << port)) + return; + + /* lookup port vid from local table, the switch passes an invalid vlan id */ + vlan = priv->vlan_id[priv->pvid[port]]; + + buf[14 + 2] &= 0xf0; + buf[14 + 2] |= vlan >> 8; + buf[15 + 2] = vlan & 0xff; +} + +#endif + +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + int timeout = 20; + u32 t = 0; + + while (1) { + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + if (timeout-- <= 0) + break; + + udelay(10); + cond_resched(); + } + + pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n", + (unsigned int) reg, t, mask, val); + return -ETIMEDOUT; +} + +static void +ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) + return; + if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { + val &= AR8216_VTUDATA_MEMBER; + val |= AR8216_VTUDATA_VALID; + ar8xxx_write(priv, AR8216_REG_VTU_DATA, val); + } + op |= AR8216_VTU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_VTU, op); +} + +static void +ar8216_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); +} + +static void +ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + + op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S); + ar8216_vtu_op(priv, op, port_mask); +} + +static int +ar8216_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | + AR8216_ATU_ACTIVE); + + return ret; +} + +static int +ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) { + t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT; + t |= AR8216_ATU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t); + } + + return ret; +} + +static u32 +ar8216_read_port_status(struct ar8xxx_priv *priv, int port) +{ + return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port)); +} + +static void +__ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members, + bool ath_hdr_en) +{ + u32 header; + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + header = ath_hdr_en ? AR8216_PORT_CTRL_HEADER : 0; + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | header | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port), + AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | + AR8216_PORT_VLAN_DEFAULT_ID, + (members << AR8216_PORT_VLAN_DEST_PORTS_S) | + (ingress << AR8216_PORT_VLAN_MODE_S) | + (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); +} + +static void +ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + return __ar8216_setup_port(priv, port, members, + chip_is_ar8216(priv) && priv->vlan && + port == AR8216_PORT_CPU); +} + +static int +ar8216_hw_init(struct ar8xxx_priv *priv) +{ + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar8216_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, 1518 + 8 + 2); +} + +static void +__ar8216_init_port(struct ar8xxx_priv *priv, int port, + bool cpu_ge, bool flow_en) +{ + /* Enable port learning and tx */ + ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | + (4 << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0); + + if (port == AR8216_PORT_CPU) { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_UP | + (cpu_ge ? AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | + AR8216_PORT_STATUS_TXMAC | + AR8216_PORT_STATUS_RXMAC | + (flow_en ? AR8216_PORT_STATUS_RXFLOW : 0) | + (flow_en ? AR8216_PORT_STATUS_TXFLOW : 0) | + AR8216_PORT_STATUS_DUPLEX); + } else { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_AUTO); + } +} + +static void +ar8216_init_port(struct ar8xxx_priv *priv, int port) +{ + __ar8216_init_port(priv, port, ar8xxx_has_gige(priv), + chip_is_ar8316(priv)); +} + +static void +ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) { + udelay(10); + cond_resched(); + } + + if (!timeout) + pr_err("ar8216: timeout waiting for atu to become ready\n"); +} + +static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_func0, r1_func1, r1_func2; + u32 t, val0, val1, val2; + + split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); + r2 |= 0x10; + + r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; + r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8216_wait_atu_ready(priv, r2, r1_func0); + + ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); + ar8xxx_mii_write32(priv, r2, r1_func1, 0); + ar8xxx_mii_write32(priv, r2, r1_func2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + t = ar8xxx_mii_read32(priv, r2, r1_func0); + t |= AR8216_ATU_ACTIVE; + ar8xxx_mii_write32(priv, r2, r1_func0, t); + ar8216_wait_atu_ready(priv, r2, r1_func0); + + val0 = ar8xxx_mii_read32(priv, r2, r1_func0); + val1 = ar8xxx_mii_read32(priv, r2, r1_func1); + val2 = ar8xxx_mii_read32(priv, r2, r1_func2); + + *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; + if (!*status) + break; + + a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S; + a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; + a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; + a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; + a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; + a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; + a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; + break; + } +} + +static int +ar8216_phy_read(struct ar8xxx_priv *priv, int addr, int regnum) +{ + u32 t, val = 0xffff; + int err; + + if (addr >= AR8216_NUM_PORTS) + return 0xffff; + t = (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | + (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | + AR8216_MDIO_CTRL_MASTER_EN | + AR8216_MDIO_CTRL_BUSY | + AR8216_MDIO_CTRL_CMD_READ; + + ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); + err = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, + AR8216_MDIO_CTRL_BUSY, 0, 5); + if (!err) + val = ar8xxx_read(priv, AR8216_REG_MDIO_CTRL); + + return val & AR8216_MDIO_CTRL_DATA_M; +} + +static int +ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val) +{ + u32 t; + int ret; + + if (addr >= AR8216_NUM_PORTS) + return -EINVAL; + + t = (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | + (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | + AR8216_MDIO_CTRL_MASTER_EN | + AR8216_MDIO_CTRL_BUSY | + AR8216_MDIO_CTRL_CMD_WRITE | + val; + + ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); + ret = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, + AR8216_MDIO_CTRL_BUSY, 0, 5); + + return ret; +} + +static int +ar8229_hw_init(struct ar8xxx_priv *priv) +{ + phy_interface_t phy_if_mode; + + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + + of_get_phy_mode(priv->pdev->of_node, &phy_if_mode); + + if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE0, + AR8229_OPER_MODE0_MAC_GMII_EN); + } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE0, + AR8229_OPER_MODE0_PHY_MII_EN); + } else { + pr_err("ar8229: unsupported mii mode\n"); + return -EINVAL; + } + + if (priv->port4_phy) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE1, + AR8229_REG_OPER_MODE1_PHY4_MII_EN); + /* disable port5 to prevent mii conflict */ + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); + } + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar8229_init_globals(struct ar8xxx_priv *priv) +{ + + /* Enable CPU port, and disable mirror port */ + ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_EN | + (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + /* Setup TAG priority mapping */ + ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); + + /* Enable aging, MAC replacing */ + ar8xxx_write(priv, AR8216_REG_ATU_CTRL, + 0x2b /* 5 min age time */ | + AR8216_ATU_CTRL_AGE_EN | + AR8216_ATU_CTRL_LEARN_CHANGE); + + /* Enable ARP frame acknowledge */ + ar8xxx_reg_set(priv, AR8229_REG_QM_CTRL, + AR8229_QM_CTRL_ARP_EN); + + /* + * Enable Broadcast/unknown multicast and unicast frames + * transmitted to the CPU port. + */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8229_FLOOD_MASK_BC_DP(0) | + AR8229_FLOOD_MASK_MC_DP(0) | + AR8229_FLOOD_MASK_UC_DP(0)); + + /* setup MTU */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8236_GCTRL_MTU, AR8236_GCTRL_MTU); + + /* Enable MIB counters */ + ar8xxx_reg_set(priv, AR8216_REG_MIB_FUNC, + AR8236_MIB_EN); + + /* setup Service TAG */ + ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); +} + +static void +ar8229_init_port(struct ar8xxx_priv *priv, int port) +{ + __ar8216_init_port(priv, port, true, true); +} + + +static int +ar7240sw_hw_init(struct ar8xxx_priv *priv) +{ + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + + priv->port4_phy = 1; + /* disable port5 to prevent mii conflict */ + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar7240sw_init_globals(struct ar8xxx_priv *priv) +{ + + /* Enable CPU port, and disable mirror port */ + ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_EN | + (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + /* Setup TAG priority mapping */ + ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); + + /* Enable ARP frame acknowledge, aging, MAC replacing */ + ar8xxx_write(priv, AR8216_REG_ATU_CTRL, + AR8216_ATU_CTRL_RESERVED | + 0x2b /* 5 min age time */ | + AR8216_ATU_CTRL_AGE_EN | + AR8216_ATU_CTRL_ARP_EN | + AR8216_ATU_CTRL_LEARN_CHANGE); + + /* Enable Broadcast frames transmitted to the CPU */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8216_FM_CPU_BROADCAST_EN); + + /* setup MTU */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, + AR8216_GCTRL_MTU); + + /* setup Service TAG */ + ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); +} + +static void +ar7240sw_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + return __ar8216_setup_port(priv, port, members, false); +} + +static void +ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port), + AR8236_PORT_VLAN_DEFAULT_ID, + (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port), + AR8236_PORT_VLAN2_VLAN_MODE | + AR8236_PORT_VLAN2_MEMBER, + (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) | + (members << AR8236_PORT_VLAN2_MEMBER_S)); +} + +static void +ar8236_init_globals(struct ar8xxx_priv *priv) +{ + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* enable cpu port to receive arp frames */ + ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL, + AR8236_ATU_CTRL_RES); + + /* + * Enable Broadcast/unknown multicast and unicast frames + * transmitted to the CPU port. + */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8229_FLOOD_MASK_BC_DP(0) | + AR8229_FLOOD_MASK_MC_DP(0) | + AR8229_FLOOD_MASK_UC_DP(0)); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +static int +ar8316_hw_init(struct ar8xxx_priv *priv) +{ + u32 val, newval; + + val = ar8xxx_read(priv, AR8316_REG_POSTRIP); + + if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + if (priv->port4_phy) { + /* value taken from Ubiquiti RouterStation Pro */ + newval = 0x81461bea; + pr_info("ar8316: Using port 4 as PHY\n"); + } else { + newval = 0x01261be2; + pr_info("ar8316: Using port 4 as switch port\n"); + } + } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { + /* value taken from AVM Fritz!Box 7390 sources */ + newval = 0x010e5b71; + } else { + /* no known value for phy interface */ + pr_err("ar8316: unsupported mii mode: %d.\n", + priv->phy->interface); + return -EINVAL; + } + + if (val == newval) + goto out; + + ar8xxx_write(priv, AR8316_REG_POSTRIP, newval); + + if (priv->port4_phy && + priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + /* work around for phy4 rgmii mode */ + ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c); + /* rx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e); + /* tx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47); + msleep(1000); + } + + ar8xxx_phy_init(priv); + +out: + priv->initialized = true; + return 0; +} + +static void +ar8316_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + /* enable cpu port to receive multicast and broadcast frames */ + ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + priv->vlan = !!val->value.i; + return 0; +} + +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan; + return 0; +} + + +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + /* make sure no invalid PVIDs get set */ + + if (vlan < 0 || vlan >= dev->vlans || + port < 0 || port >= AR8X16_MAX_PORTS) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (port < 0 || port >= AR8X16_MAX_PORTS) + return -EINVAL; + + *vlan = priv->pvid[port]; + return 0; +} + +static int +ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + ar8216_read_port_link(priv, port, link); + return 0; +} + +static int +ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports; + int i; + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + ports = priv->vlan_table[val->port_vlan]; + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + priv->vlan_tagged |= (1 << p->id); + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < dev->vlans; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8216_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + for (port = 0; port < AR8216_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_RX); + + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_TX); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8216_NUM_PORTS || + priv->monitor_port >= AR8216_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_RX); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_TX); +} + +static inline u32 +ar8xxx_age_time_val(int age_time) +{ + return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) / + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS; +} + +static inline void +ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg) +{ + u32 age_time = ar8xxx_age_time_val(priv->arl_age_time); + ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S); +} + +int +ar8xxx_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + u8 portmask[AR8X16_MAX_PORTS]; + int i, j; + + mutex_lock(&priv->reg_mutex); + /* flush all vlan translation unit entries */ + priv->chip->vtu_flush(priv); + + memset(portmask, 0, sizeof(portmask)); + if (!priv->init) { + /* calculate the port destination masks and load vlans + * into the vlan translation unit */ + for (j = 0; j < dev->vlans; j++) { + u8 vp = priv->vlan_table[j]; + + if (!vp) + continue; + + for (i = 0; i < dev->ports; i++) { + u8 mask = (1 << i); + if (vp & mask) + portmask[i] |= vp & ~mask; + } + + chip->vtu_load_vlan(priv, priv->vlan_id[j], + priv->vlan_table[j]); + } + } else { + /* vlan disabled: + * isolate all ports, but connect them to the cpu port */ + for (i = 0; i < dev->ports; i++) { + if (i == AR8216_PORT_CPU) + continue; + + portmask[i] = 1 << AR8216_PORT_CPU; + portmask[AR8216_PORT_CPU] |= (1 << i); + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < dev->ports; i++) { + chip->setup_port(priv, i, portmask[i]); + } + + chip->set_mirror_regs(priv); + + /* set age time */ + if (chip->reg_arl_ctrl) + ar8xxx_set_age_time(priv, chip->reg_arl_ctrl); + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +int +ar8xxx_sw_reset_switch(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + int i; + + mutex_lock(&priv->reg_mutex); + memset(&priv->ar8xxx_priv_volatile, 0, sizeof(priv->ar8xxx_priv_volatile)); + + for (i = 0; i < dev->vlans; i++) + priv->vlan_id[i] = i; + + /* Configure all ports */ + for (i = 0; i < dev->ports; i++) + chip->init_port(priv, i); + + priv->mirror_rx = false; + priv->mirror_tx = false; + priv->source_port = 0; + priv->monitor_port = 0; + priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME; + + chip->init_globals(priv); + chip->atu_flush(priv); + + mutex_unlock(&priv->reg_mutex); + + return chip->sw_hw_apply(dev); +} + +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + unsigned int len; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + mutex_lock(&priv->mib_lock); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + memset(priv->mib_stats, '\0', len); + ret = ar8xxx_mib_flush(priv); + if (ret) + goto unlock; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + ar8xxx_mib_stop(priv); + priv->mib_poll_interval = val->value.i; + ar8xxx_mib_start(priv); + + return 0; +} + +int +ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + val->value.i = priv->mib_poll_interval; + return 0; +} + +int +ar8xxx_sw_set_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + priv->mib_type = val->value.i; + return 0; +} + +int +ar8xxx_sw_get_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + val->value.i = priv->mib_type; + return 0; +} + +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_rx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_rx; + return 0; +} + +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_tx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_tx; + return 0; +} + +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->monitor_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->monitor_port; + return 0; +} + +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->source_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->source_port; + return 0; +} + +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, true); + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +static void +ar8xxx_byte_to_str(char *buf, int len, u64 byte) +{ + unsigned long b; + const char *unit; + + if (byte >= 0x40000000) { /* 1 GiB */ + b = byte * 10 / 0x40000000; + unit = "GiB"; + } else if (byte >= 0x100000) { /* 1 MiB */ + b = byte * 10 / 0x100000; + unit = "MiB"; + } else if (byte >= 0x400) { /* 1 KiB */ + b = byte * 10 / 0x400; + unit = "KiB"; + } else { + b = byte; + unit = "Byte"; + } + if (strcmp(unit, "Byte")) + snprintf(buf, len, "%lu.%lu %s", b / 10, b % 10, unit); + else + snprintf(buf, len, "%lu %s", b, unit); +} + +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + u64 *mib_stats, mib_data; + unsigned int port; + int ret; + char *buf = priv->buf; + char buf1[64]; + const char *mib_name; + int i, len = 0; + bool mib_stats_empty = true; + + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, false); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "MIB counters\n"); + + mib_stats = &priv->mib_stats[port * chip->num_mibs]; + for (i = 0; i < chip->num_mibs; i++) { + if (chip->mib_decs[i].type > priv->mib_type) + continue; + mib_name = chip->mib_decs[i].name; + mib_data = mib_stats[i]; + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %llu\n", mib_name, mib_data); + if ((!strcmp(mib_name, "TxByte") || + !strcmp(mib_name, "RxGoodByte")) && + mib_data >= 1024) { + ar8xxx_byte_to_str(buf1, sizeof(buf1), mib_data); + --len; /* discard newline at the end of buf */ + len += snprintf(buf + len, sizeof(priv->buf) - len, + " (%s)\n", buf1); + } + if (mib_stats_empty && mib_data) + mib_stats_empty = false; + } + + if (mib_stats_empty) + len = snprintf(buf, sizeof(priv->buf), "No MIB data"); + + val->value.s = buf; + val->len = len; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int age_time = val->value.i; + u32 age_time_val; + + if (age_time < 0) + return -EINVAL; + + age_time_val = ar8xxx_age_time_val(age_time); + if (age_time_val == 0 || age_time_val > 0xffff) + return -EINVAL; + + priv->arl_age_time = age_time; + return 0; +} + +int +ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->arl_age_time; + return 0; +} + +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct mii_bus *bus = priv->mii_bus; + const struct ar8xxx_chip *chip = priv->chip; + char *buf = priv->arl_buf; + int i, j, k, len = 0; + struct arl_entry *a, *a1; + u32 status; + + if (!chip->get_arl_entry) + return -EOPNOTSUPP; + + mutex_lock(&priv->reg_mutex); + mutex_lock(&bus->mdio_lock); + + chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE); + + for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) { + a = &priv->arl_table[i]; + duplicate: + chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT); + + if (!status) + break; + + /* avoid duplicates + * ARL table can include multiple valid entries + * per MAC, just with differing status codes + */ + for (j = 0; j < i; ++j) { + a1 = &priv->arl_table[j]; + if (!memcmp(a->mac, a1->mac, sizeof(a->mac))) { + /* ignore ports already seen in former entry */ + a->portmap &= ~a1->portmap; + if (!a->portmap) + goto duplicate; + } + } + } + + mutex_unlock(&bus->mdio_lock); + + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "address resolution table\n"); + + if (i == AR8XXX_NUM_ARL_RECORDS) + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Too many entries found, displaying the first %d only!\n", + AR8XXX_NUM_ARL_RECORDS); + + for (j = 0; j < priv->dev.ports; ++j) { + for (k = 0; k < i; ++k) { + a = &priv->arl_table[k]; + if (!(a->portmap & BIT(j))) + continue; + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + j, + a->mac[5], a->mac[4], a->mac[3], + a->mac[2], a->mac[1], a->mac[0]); + } + } + + val->value.s = buf; + val->len = len; + + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int ret; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush(priv); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port, ret; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush_port(priv, port); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u64 *mib_stats; + + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return -EOPNOTSUPP; + + if (!(priv->chip->mib_rxb_id || priv->chip->mib_txb_id)) + return -EOPNOTSUPP; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + + stats->tx_bytes = mib_stats[priv->chip->mib_txb_id]; + stats->rx_bytes = mib_stats[priv->chip->mib_rxb_id]; + + mutex_unlock(&priv->mib_lock); + return 0; +} + +static int +ar8xxx_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr) +{ + struct ar8xxx_priv *priv = bus->priv; + return priv->chip->phy_read(priv, phy_addr, reg_addr); +} + +static int +ar8xxx_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr, + u16 reg_val) +{ + struct ar8xxx_priv *priv = bus->priv; + return priv->chip->phy_write(priv, phy_addr, reg_addr, reg_val); +} + +static const struct switch_attr ar8xxx_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_poll_interval", + .description = "MIB polling interval in msecs (0 to disable)", + .set = ar8xxx_sw_set_mib_poll_interval, + .get = ar8xxx_sw_get_mib_poll_interval + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_type", + .description = "MIB type (0=basic 1=extended)", + .set = ar8xxx_sw_set_mib_type, + .get = ar8xxx_sw_get_mib_type + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_vlan[1] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = ar8xxx_sw_set_vid, + .get = ar8xxx_sw_get_vid, + .max = 4094, + }, +}; + +static const struct switch_dev_ops ar8xxx_sw_ops = { + .attr_global = { + .attr = ar8xxx_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals), + }, + .attr_port = { + .attr = ar8xxx_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8xxx_sw_get_ports, + .set_vlan_ports = ar8xxx_sw_set_ports, + .apply_config = ar8xxx_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, + .get_port_stats = ar8xxx_sw_get_port_stats, +}; + +static const struct ar8xxx_chip ar7240sw_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR724X/AR933X built-in", + .ports = AR7240SW_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar7240sw_hw_init, + .init_globals = ar7240sw_init_globals, + .init_port = ar8229_init_port, + .phy_read = ar8216_phy_read, + .phy_write = ar8216_phy_write, + .setup_port = ar7240sw_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8216_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x19000, + .reg_port_stats_length = 0xa0, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8216", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8216_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8216_mibs), + .mib_decs = ar8216_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8216_MIB_RXB_ID, + .mib_txb_id = AR8216_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8229_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8229", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8229_hw_init, + .init_globals = ar8229_init_globals, + .init_port = ar8229_init_port, + .phy_read = ar8216_phy_read, + .phy_write = ar8216_phy_write, + .setup_port = ar8236_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8236_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8236", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8236_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8236_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8316_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8316", + .ports = AR8216_NUM_PORTS, + .vlans = AR8X16_MAX_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8316_hw_init, + .init_globals = ar8316_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static int +ar8xxx_read_id(struct ar8xxx_priv *priv) +{ + u32 val; + u16 id; + int i; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { + u16 t; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + if (t != id) + return -ENODEV; + } + + priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S; + priv->chip_rev = (id & AR8216_CTRL_REVISION); + return 0; +} + +static int +ar8xxx_id_chip(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8xxx_read_id(priv); + if(ret) + return ret; + + switch (priv->chip_ver) { + case AR8XXX_VER_AR8216: + priv->chip = &ar8216_chip; + break; + case AR8XXX_VER_AR8236: + priv->chip = &ar8236_chip; + break; + case AR8XXX_VER_AR8316: + priv->chip = &ar8316_chip; + break; + case AR8XXX_VER_AR8327: + priv->chip = &ar8327_chip; + break; + case AR8XXX_VER_AR8337: + priv->chip = &ar8337_chip; + break; + default: + pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", + priv->chip_ver, priv->chip_rev); + + return -ENODEV; + } + + return 0; +} + +static void +ar8xxx_mib_work_func(struct work_struct *work) +{ + struct ar8xxx_priv *priv; + int err, i; + + priv = container_of(work, struct ar8xxx_priv, mib_work.work); + + mutex_lock(&priv->mib_lock); + + err = ar8xxx_mib_capture(priv); + if (err) + goto next_attempt; + + for (i = 0; i < priv->dev.ports; i++) + ar8xxx_mib_fetch_port_stat(priv, i, false); + +next_attempt: + mutex_unlock(&priv->mib_lock); + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(priv->mib_poll_interval)); +} + +static int +ar8xxx_mib_init(struct ar8xxx_priv *priv) +{ + unsigned int len; + + if (!ar8xxx_has_mib_counters(priv)) + return 0; + + BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + priv->mib_stats = kzalloc(len, GFP_KERNEL); + + if (!priv->mib_stats) + return -ENOMEM; + + return 0; +} + +static void +ar8xxx_mib_start(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return; + + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(priv->mib_poll_interval)); +} + +static void +ar8xxx_mib_stop(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return; + + cancel_delayed_work_sync(&priv->mib_work); +} + +static struct ar8xxx_priv * +ar8xxx_create(void) +{ + struct ar8xxx_priv *priv; + + priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); + + return priv; +} + +static void +ar8xxx_free(struct ar8xxx_priv *priv) +{ + if (priv->chip && priv->chip->cleanup) + priv->chip->cleanup(priv); + + kfree(priv->chip_data); + kfree(priv->mib_stats); + kfree(priv); +} + +static int +ar8xxx_probe_switch(struct ar8xxx_priv *priv) +{ + const struct ar8xxx_chip *chip; + struct switch_dev *swdev; + int ret; + + chip = priv->chip; + + swdev = &priv->dev; + swdev->cpu_port = AR8216_PORT_CPU; + swdev->name = chip->name; + swdev->vlans = chip->vlans; + swdev->ports = chip->ports; + swdev->ops = chip->swops; + + ret = ar8xxx_mib_init(priv); + if (ret) + return ret; + + return 0; +} + +static int +ar8xxx_start(struct ar8xxx_priv *priv) +{ + int ret; + + priv->init = true; + + ret = priv->chip->hw_init(priv); + if (ret) + return ret; + + ret = ar8xxx_sw_reset_switch(&priv->dev); + if (ret) + return ret; + + priv->init = false; + + ar8xxx_mib_start(priv); + + return 0; +} + +static int +ar8xxx_phy_config_init(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + struct net_device *dev = phydev->attached_dev; +#endif + int ret; + + if (WARN_ON(!priv)) + return -ENODEV; + + if (priv->chip->config_at_probe) + return ar8xxx_phy_check_aneg(phydev); + + priv->phy = phydev; + + if (phydev->mdio.addr != 0) { + if (chip_is_ar8316(priv)) { + /* switch device has been initialized, reinit */ + priv->dev.ports = (AR8216_NUM_PORTS - 1); + priv->initialized = false; + priv->port4_phy = true; + ar8316_hw_init(priv); + return 0; + } + + return 0; + } + + ret = ar8xxx_start(priv); + if (ret) + return ret; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + /* VID fixup only needed on ar8216 */ + if (chip_is_ar8216(priv)) { + dev->phy_ptr = priv; + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = ar8216_mangle_rx; + dev->eth_mangle_tx = ar8216_mangle_tx; + } +#endif + + return 0; +} + +static bool +ar8xxx_check_link_states(struct ar8xxx_priv *priv) +{ + bool link_new, changed = false; + u32 status; + int i; + + mutex_lock(&priv->reg_mutex); + + for (i = 0; i < priv->dev.ports; i++) { + status = priv->chip->read_port_status(priv, i); + link_new = !!(status & AR8216_PORT_STATUS_LINK_UP); + if (link_new == priv->link_up[i]) + continue; + + priv->link_up[i] = link_new; + changed = true; + /* flush ARL entries for this port if it went down*/ + if (!link_new) + priv->chip->atu_flush_port(priv, i); + dev_info(&priv->phy->mdio.dev, "Port %d is %s\n", + i, link_new ? "up" : "down"); + } + + mutex_unlock(&priv->reg_mutex); + + return changed; +} + +static int +ar8xxx_phy_read_status(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + struct switch_port_link link; + + /* check for switch port link changes */ + ar8xxx_check_link_states(priv); + + if (phydev->mdio.addr != 0) + return genphy_read_status(phydev); + + ar8216_read_port_link(priv, phydev->mdio.addr, &link); + phydev->link = !!link.link; + if (!phydev->link) + return 0; + + switch (link.speed) { + case SWITCH_PORT_SPEED_10: + phydev->speed = SPEED_10; + break; + case SWITCH_PORT_SPEED_100: + phydev->speed = SPEED_100; + break; + case SWITCH_PORT_SPEED_1000: + phydev->speed = SPEED_1000; + break; + default: + phydev->speed = 0; + } + phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + if (phydev->adjust_link) + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int +ar8xxx_phy_config_aneg(struct phy_device *phydev) +{ + if (phydev->mdio.addr == 0) + return 0; + + return genphy_config_aneg(phydev); +} + +static int +ar8xxx_get_features(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + + linkmode_copy(phydev->supported, PHY_BASIC_FEATURES); + if (ar8xxx_has_gige(priv)) + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); + + return 0; +} + +static const u32 ar8xxx_phy_ids[] = { + 0x004dd033, + 0x004dd034, /* AR8327 */ + 0x004dd036, /* AR8337 */ + 0x004dd041, + 0x004dd042, + 0x004dd043, /* AR8236 */ +}; + +static bool +ar8xxx_phy_match(u32 phy_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) + if (phy_id == ar8xxx_phy_ids[i]) + return true; + + return false; +} + +static bool +ar8xxx_is_possible(struct mii_bus *bus) +{ + unsigned int i, found_phys = 0; + + for (i = 0; i < 5; i++) { + u32 phy_id; + + phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; + phy_id |= mdiobus_read(bus, i, MII_PHYSID2); + if (ar8xxx_phy_match(phy_id)) { + found_phys++; + } else if (phy_id) { + pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", + dev_name(&bus->dev), i, phy_id); + } + } + return !!found_phys; +} + +static int +ar8xxx_phy_probe(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv; + struct switch_dev *swdev; + int ret; + + /* skip PHYs at unused adresses */ + if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4) + return -ENODEV; + + if (!ar8xxx_is_possible(phydev->mdio.bus)) + return -ENODEV; + + mutex_lock(&ar8xxx_dev_list_lock); + list_for_each_entry(priv, &ar8xxx_dev_list, list) + if (priv->mii_bus == phydev->mdio.bus) + goto found; + + priv = ar8xxx_create(); + if (priv == NULL) { + ret = -ENOMEM; + goto unlock; + } + + priv->mii_bus = phydev->mdio.bus; + priv->pdev = &phydev->mdio.dev; + + ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", + &priv->mib_poll_interval); + if (ret) + priv->mib_poll_interval = 0; + + ret = ar8xxx_id_chip(priv); + if (ret) + goto free_priv; + + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + + swdev = &priv->dev; + swdev->alias = dev_name(&priv->mii_bus->dev); + ret = register_switch(swdev, NULL); + if (ret) + goto free_priv; + + pr_info("%s: %s rev. %u switch registered on %s\n", + swdev->devname, swdev->name, priv->chip_rev, + dev_name(&priv->mii_bus->dev)); + + list_add(&priv->list, &ar8xxx_dev_list); + +found: + priv->use_count++; + + if (phydev->mdio.addr == 0 && priv->chip->config_at_probe) { + priv->phy = phydev; + + ret = ar8xxx_start(priv); + if (ret) + goto err_unregister_switch; + } else if (priv->chip->phy_rgmii_set) { + priv->chip->phy_rgmii_set(priv, phydev); + } + + phydev->priv = priv; + + mutex_unlock(&ar8xxx_dev_list_lock); + + return 0; + +err_unregister_switch: + if (--priv->use_count) + goto unlock; + + unregister_switch(&priv->dev); + +free_priv: + ar8xxx_free(priv); +unlock: + mutex_unlock(&ar8xxx_dev_list_lock); + return ret; +} + +static void +ar8xxx_phy_detach(struct phy_device *phydev) +{ + struct net_device *dev = phydev->attached_dev; + + if (!dev) + return; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + dev->phy_ptr = NULL; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; +#endif +} + +static void +ar8xxx_phy_remove(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + + if (WARN_ON(!priv)) + return; + + phydev->priv = NULL; + + mutex_lock(&ar8xxx_dev_list_lock); + + if (--priv->use_count > 0) { + mutex_unlock(&ar8xxx_dev_list_lock); + return; + } + + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); + + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); + ar8xxx_free(priv); +} + +static struct phy_driver ar8xxx_phy_driver[] = { + { + .phy_id = 0x004d0000, + .name = "Atheros AR8216/AR8236/AR8316", + .phy_id_mask = 0xffff0000, + .probe = ar8xxx_phy_probe, + .remove = ar8xxx_phy_remove, + .detach = ar8xxx_phy_detach, + .config_init = ar8xxx_phy_config_init, + .config_aneg = ar8xxx_phy_config_aneg, + .read_status = ar8xxx_phy_read_status, + .get_features = ar8xxx_get_features, + } +}; + +static const struct of_device_id ar8xxx_mdiodev_of_match[] = { + { + .compatible = "qca,ar7240sw", + .data = &ar7240sw_chip, + }, { + .compatible = "qca,ar8229", + .data = &ar8229_chip, + }, { + .compatible = "qca,ar8236", + .data = &ar8236_chip, + }, { + .compatible = "qca,ar8327", + .data = &ar8327_chip, + }, + { /* sentinel */ }, +}; + +static int +ar8xxx_mdiodev_probe(struct mdio_device *mdiodev) +{ + const struct of_device_id *match; + struct ar8xxx_priv *priv; + struct switch_dev *swdev; + struct device_node *mdio_node; + int ret; + + match = of_match_device(ar8xxx_mdiodev_of_match, &mdiodev->dev); + if (!match) + return -EINVAL; + + priv = ar8xxx_create(); + if (priv == NULL) + return -ENOMEM; + + priv->mii_bus = mdiodev->bus; + priv->pdev = &mdiodev->dev; + priv->chip = (const struct ar8xxx_chip *) match->data; + + ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", + &priv->mib_poll_interval); + if (ret) + priv->mib_poll_interval = 0; + + ret = ar8xxx_read_id(priv); + if (ret) + goto free_priv; + + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + + if (priv->chip->phy_read && priv->chip->phy_write) { + priv->sw_mii_bus = devm_mdiobus_alloc(&mdiodev->dev); + priv->sw_mii_bus->name = "ar8xxx-mdio"; + priv->sw_mii_bus->read = ar8xxx_phy_read; + priv->sw_mii_bus->write = ar8xxx_phy_write; + priv->sw_mii_bus->priv = priv; + priv->sw_mii_bus->parent = &mdiodev->dev; + snprintf(priv->sw_mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(&mdiodev->dev)); + mdio_node = of_get_child_by_name(priv->pdev->of_node, "mdio-bus"); + ret = of_mdiobus_register(priv->sw_mii_bus, mdio_node); + if (ret) + goto free_priv; + } + + swdev = &priv->dev; + swdev->alias = dev_name(&mdiodev->dev); + + if (of_property_read_bool(priv->pdev->of_node, "qca,phy4-mii-enable")) { + priv->port4_phy = true; + swdev->ports--; + } + + ret = register_switch(swdev, NULL); + if (ret) + goto free_priv; + + pr_info("%s: %s rev. %u switch registered on %s\n", + swdev->devname, swdev->name, priv->chip_rev, + dev_name(&priv->mii_bus->dev)); + + mutex_lock(&ar8xxx_dev_list_lock); + list_add(&priv->list, &ar8xxx_dev_list); + mutex_unlock(&ar8xxx_dev_list_lock); + + priv->use_count++; + + ret = ar8xxx_start(priv); + if (ret) + goto err_unregister_switch; + + dev_set_drvdata(&mdiodev->dev, priv); + + return 0; + +err_unregister_switch: + if (--priv->use_count) + return ret; + + unregister_switch(&priv->dev); + +free_priv: + ar8xxx_free(priv); + return ret; +} + +static void +ar8xxx_mdiodev_remove(struct mdio_device *mdiodev) +{ + struct ar8xxx_priv *priv = dev_get_drvdata(&mdiodev->dev); + + if (WARN_ON(!priv)) + return; + + mutex_lock(&ar8xxx_dev_list_lock); + + if (--priv->use_count > 0) { + mutex_unlock(&ar8xxx_dev_list_lock); + return; + } + + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); + + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); + if(priv->sw_mii_bus) + mdiobus_unregister(priv->sw_mii_bus); + ar8xxx_free(priv); +} + +static struct mdio_driver ar8xxx_mdio_driver = { + .probe = ar8xxx_mdiodev_probe, + .remove = ar8xxx_mdiodev_remove, + .mdiodrv.driver = { + .name = "ar8xxx-switch", + .of_match_table = ar8xxx_mdiodev_of_match, + }, +}; + +static int __init ar8216_init(void) +{ + int ret; + + ret = phy_drivers_register(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver), + THIS_MODULE); + if (ret) + return ret; + + ret = mdio_driver_register(&ar8xxx_mdio_driver); + if (ret) + phy_drivers_unregister(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver)); + + return ret; +} +module_init(ar8216_init); + +static void __exit ar8216_exit(void) +{ + mdio_driver_unregister(&ar8xxx_mdio_driver); + phy_drivers_unregister(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver)); +} +module_exit(ar8216_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/ar8216.h b/drivers/net/phy/ar8216.h new file mode 100644 index 000000000000..f046b35f43fb --- /dev/null +++ b/drivers/net/phy/ar8216.h @@ -0,0 +1,725 @@ +/* + * ar8216.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AR8216_H +#define __AR8216_H + +#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) + +#define AR8XXX_CAP_GIGE BIT(0) +#define AR8XXX_CAP_MIB_COUNTERS BIT(1) + +#define AR8XXX_NUM_PHYS 5 +#define AR8216_PORT_CPU 0 +#define AR8216_NUM_PORTS 6 +#define AR8216_NUM_VLANS 16 +#define AR7240SW_NUM_PORTS 5 +#define AR8316_NUM_VLANS 4096 + +/* size of the vlan table */ +#define AR8X16_MAX_VLANS 128 +#define AR83X7_MAX_VLANS 4096 +#define AR8XXX_MAX_VLANS AR83X7_MAX_VLANS + +#define AR8X16_PROBE_RETRIES 10 +#define AR8X16_MAX_PORTS 8 + +#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS 7 +#define AR8XXX_DEFAULT_ARL_AGE_TIME 300 + +/* Atheros specific MII registers */ +#define MII_ATH_MMD_ADDR 0x0d +#define MII_ATH_MMD_DATA 0x0e +#define MII_ATH_DBG_ADDR 0x1d +#define MII_ATH_DBG_DATA 0x1e + +#define AR8216_REG_CTRL 0x0000 +#define AR8216_CTRL_REVISION BITS(0, 8) +#define AR8216_CTRL_REVISION_S 0 +#define AR8216_CTRL_VERSION BITS(8, 8) +#define AR8216_CTRL_VERSION_S 8 +#define AR8216_CTRL_RESET BIT(31) + +#define AR8216_REG_FLOOD_MASK 0x002C +#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) +#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) +#define AR8216_FM_CPU_BROADCAST_EN BIT(26) +#define AR8229_FLOOD_MASK_UC_DP(_p) BIT(_p) +#define AR8229_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p)) +#define AR8229_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p)) + +#define AR8216_REG_GLOBAL_CTRL 0x0030 +#define AR8216_GCTRL_MTU BITS(0, 11) +#define AR8236_GCTRL_MTU BITS(0, 14) +#define AR8316_GCTRL_MTU BITS(0, 14) + +#define AR8216_REG_VTU 0x0040 +#define AR8216_VTU_OP BITS(0, 3) +#define AR8216_VTU_OP_NOOP 0x0 +#define AR8216_VTU_OP_FLUSH 0x1 +#define AR8216_VTU_OP_LOAD 0x2 +#define AR8216_VTU_OP_PURGE 0x3 +#define AR8216_VTU_OP_REMOVE_PORT 0x4 +#define AR8216_VTU_ACTIVE BIT(3) +#define AR8216_VTU_FULL BIT(4) +#define AR8216_VTU_PORT BITS(8, 4) +#define AR8216_VTU_PORT_S 8 +#define AR8216_VTU_VID BITS(16, 12) +#define AR8216_VTU_VID_S 16 +#define AR8216_VTU_PRIO BITS(28, 3) +#define AR8216_VTU_PRIO_S 28 +#define AR8216_VTU_PRIO_EN BIT(31) + +#define AR8216_REG_VTU_DATA 0x0044 +#define AR8216_VTUDATA_MEMBER BITS(0, 10) +#define AR8236_VTUDATA_MEMBER BITS(0, 7) +#define AR8216_VTUDATA_VALID BIT(11) + +#define AR8216_REG_ATU_FUNC0 0x0050 +#define AR8216_ATU_OP BITS(0, 3) +#define AR8216_ATU_OP_NOOP 0x0 +#define AR8216_ATU_OP_FLUSH 0x1 +#define AR8216_ATU_OP_LOAD 0x2 +#define AR8216_ATU_OP_PURGE 0x3 +#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4 +#define AR8216_ATU_OP_FLUSH_PORT 0x5 +#define AR8216_ATU_OP_GET_NEXT 0x6 +#define AR8216_ATU_ACTIVE BIT(3) +#define AR8216_ATU_PORT_NUM BITS(8, 4) +#define AR8216_ATU_PORT_NUM_S 8 +#define AR8216_ATU_FULL_VIO BIT(12) +#define AR8216_ATU_ADDR5 BITS(16, 8) +#define AR8216_ATU_ADDR5_S 16 +#define AR8216_ATU_ADDR4 BITS(24, 8) +#define AR8216_ATU_ADDR4_S 24 + +#define AR8216_REG_ATU_FUNC1 0x0054 +#define AR8216_ATU_ADDR3 BITS(0, 8) +#define AR8216_ATU_ADDR3_S 0 +#define AR8216_ATU_ADDR2 BITS(8, 8) +#define AR8216_ATU_ADDR2_S 8 +#define AR8216_ATU_ADDR1 BITS(16, 8) +#define AR8216_ATU_ADDR1_S 16 +#define AR8216_ATU_ADDR0 BITS(24, 8) +#define AR8216_ATU_ADDR0_S 24 + +#define AR8216_REG_ATU_FUNC2 0x0058 +#define AR8216_ATU_PORTS BITS(0, 6) +#define AR8216_ATU_PORTS_S 0 +#define AR8216_ATU_PORT0 BIT(0) +#define AR8216_ATU_PORT1 BIT(1) +#define AR8216_ATU_PORT2 BIT(2) +#define AR8216_ATU_PORT3 BIT(3) +#define AR8216_ATU_PORT4 BIT(4) +#define AR8216_ATU_PORT5 BIT(5) +#define AR8216_ATU_STATUS BITS(16, 4) +#define AR8216_ATU_STATUS_S 16 + +#define AR8216_REG_ATU_CTRL 0x005C +#define AR8216_ATU_CTRL_AGE_EN BIT(17) +#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) +#define AR8216_ATU_CTRL_AGE_TIME_S 0 +#define AR8236_ATU_CTRL_RES BIT(20) +#define AR8216_ATU_CTRL_LEARN_CHANGE BIT(18) +#define AR8216_ATU_CTRL_RESERVED BIT(19) +#define AR8216_ATU_CTRL_ARP_EN BIT(20) + +#define AR8216_REG_TAG_PRIORITY 0x0070 + +#define AR8216_REG_SERVICE_TAG 0x0074 +#define AR8216_SERVICE_TAG_M BITS(0, 16) + +#define AR8216_REG_MIB_FUNC 0x0080 +#define AR8216_MIB_TIMER BITS(0, 16) +#define AR8216_MIB_AT_HALF_EN BIT(16) +#define AR8216_MIB_BUSY BIT(17) +#define AR8216_MIB_FUNC BITS(24, 3) +#define AR8216_MIB_FUNC_S 24 +#define AR8216_MIB_FUNC_NO_OP 0x0 +#define AR8216_MIB_FUNC_FLUSH 0x1 +#define AR8216_MIB_FUNC_CAPTURE 0x3 +#define AR8236_MIB_EN BIT(30) + +#define AR8216_REG_GLOBAL_CPUPORT 0x0078 +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4) +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4 +#define AR8216_GLOBAL_CPUPORT_EN BIT(8) + +#define AR8216_REG_MDIO_CTRL 0x98 +#define AR8216_MDIO_CTRL_DATA_M BITS(0, 16) +#define AR8216_MDIO_CTRL_REG_ADDR_S 16 +#define AR8216_MDIO_CTRL_PHY_ADDR_S 21 +#define AR8216_MDIO_CTRL_CMD_WRITE 0 +#define AR8216_MDIO_CTRL_CMD_READ BIT(27) +#define AR8216_MDIO_CTRL_MASTER_EN BIT(30) +#define AR8216_MDIO_CTRL_BUSY BIT(31) + +#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) +#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) +#define AR8216_PORT_STATUS_SPEED BITS(0,2) +#define AR8216_PORT_STATUS_SPEED_S 0 +#define AR8216_PORT_STATUS_TXMAC BIT(2) +#define AR8216_PORT_STATUS_RXMAC BIT(3) +#define AR8216_PORT_STATUS_TXFLOW BIT(4) +#define AR8216_PORT_STATUS_RXFLOW BIT(5) +#define AR8216_PORT_STATUS_DUPLEX BIT(6) +#define AR8216_PORT_STATUS_LINK_UP BIT(8) +#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) +#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) +#define AR8216_PORT_STATUS_FLOW_CONTROL BIT(12) + +#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) + +/* port forwarding state */ +#define AR8216_PORT_CTRL_STATE BITS(0, 3) +#define AR8216_PORT_CTRL_STATE_S 0 + +#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) + +/* egress 802.1q mode */ +#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) +#define AR8216_PORT_CTRL_VLAN_MODE_S 8 + +#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) +#define AR8216_PORT_CTRL_HEADER BIT(11) +#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) +#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) +#define AR8216_PORT_CTRL_LEARN BIT(14) +#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) +#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) + +#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) + +#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) +#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 + +#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) +#define AR8216_PORT_VLAN_DEST_PORTS_S 16 + +/* bit0 added to the priority field of egress frames */ +#define AR8216_PORT_VLAN_TX_PRIO BIT(27) + +/* port default priority */ +#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) +#define AR8216_PORT_VLAN_PRIORITY_S 28 + +/* ingress 802.1q mode */ +#define AR8216_PORT_VLAN_MODE BITS(30, 2) +#define AR8216_PORT_VLAN_MODE_S 30 + +#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) +#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) + +#define AR8216_STATS_RXBROAD 0x00 +#define AR8216_STATS_RXPAUSE 0x04 +#define AR8216_STATS_RXMULTI 0x08 +#define AR8216_STATS_RXFCSERR 0x0c +#define AR8216_STATS_RXALIGNERR 0x10 +#define AR8216_STATS_RXRUNT 0x14 +#define AR8216_STATS_RXFRAGMENT 0x18 +#define AR8216_STATS_RX64BYTE 0x1c +#define AR8216_STATS_RX128BYTE 0x20 +#define AR8216_STATS_RX256BYTE 0x24 +#define AR8216_STATS_RX512BYTE 0x28 +#define AR8216_STATS_RX1024BYTE 0x2c +#define AR8216_STATS_RXMAXBYTE 0x30 +#define AR8216_STATS_RXTOOLONG 0x34 +#define AR8216_STATS_RXGOODBYTE 0x38 +#define AR8216_STATS_RXBADBYTE 0x40 +#define AR8216_STATS_RXOVERFLOW 0x48 +#define AR8216_STATS_FILTERED 0x4c +#define AR8216_STATS_TXBROAD 0x50 +#define AR8216_STATS_TXPAUSE 0x54 +#define AR8216_STATS_TXMULTI 0x58 +#define AR8216_STATS_TXUNDERRUN 0x5c +#define AR8216_STATS_TX64BYTE 0x60 +#define AR8216_STATS_TX128BYTE 0x64 +#define AR8216_STATS_TX256BYTE 0x68 +#define AR8216_STATS_TX512BYTE 0x6c +#define AR8216_STATS_TX1024BYTE 0x70 +#define AR8216_STATS_TXMAXBYTE 0x74 +#define AR8216_STATS_TXOVERSIZE 0x78 +#define AR8216_STATS_TXBYTE 0x7c +#define AR8216_STATS_TXCOLLISION 0x84 +#define AR8216_STATS_TXABORTCOL 0x88 +#define AR8216_STATS_TXMULTICOL 0x8c +#define AR8216_STATS_TXSINGLECOL 0x90 +#define AR8216_STATS_TXEXCDEFER 0x94 +#define AR8216_STATS_TXDEFER 0x98 +#define AR8216_STATS_TXLATECOL 0x9c + +#define AR8216_MIB_RXB_ID 14 /* RxGoodByte */ +#define AR8216_MIB_TXB_ID 29 /* TxByte */ + +#define AR8229_REG_OPER_MODE0 0x04 +#define AR8229_OPER_MODE0_MAC_GMII_EN BIT(6) +#define AR8229_OPER_MODE0_PHY_MII_EN BIT(10) + +#define AR8229_REG_OPER_MODE1 0x08 +#define AR8229_REG_OPER_MODE1_PHY4_MII_EN BIT(28) + +#define AR8229_REG_QM_CTRL 0x3c +#define AR8229_QM_CTRL_ARP_EN BIT(15) + +#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008) +#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12) +#define AR8236_PORT_VLAN_DEFAULT_ID_S 16 +#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3) +#define AR8236_PORT_VLAN_PRIORITY_S 28 + +#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c) +#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7) +#define AR8236_PORT_VLAN2_MEMBER_S 16 +#define AR8236_PORT_VLAN2_TX_PRIO BIT(23) +#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2) +#define AR8236_PORT_VLAN2_VLAN_MODE_S 30 + +#define AR8236_STATS_RXBROAD 0x00 +#define AR8236_STATS_RXPAUSE 0x04 +#define AR8236_STATS_RXMULTI 0x08 +#define AR8236_STATS_RXFCSERR 0x0c +#define AR8236_STATS_RXALIGNERR 0x10 +#define AR8236_STATS_RXRUNT 0x14 +#define AR8236_STATS_RXFRAGMENT 0x18 +#define AR8236_STATS_RX64BYTE 0x1c +#define AR8236_STATS_RX128BYTE 0x20 +#define AR8236_STATS_RX256BYTE 0x24 +#define AR8236_STATS_RX512BYTE 0x28 +#define AR8236_STATS_RX1024BYTE 0x2c +#define AR8236_STATS_RX1518BYTE 0x30 +#define AR8236_STATS_RXMAXBYTE 0x34 +#define AR8236_STATS_RXTOOLONG 0x38 +#define AR8236_STATS_RXGOODBYTE 0x3c +#define AR8236_STATS_RXBADBYTE 0x44 +#define AR8236_STATS_RXOVERFLOW 0x4c +#define AR8236_STATS_FILTERED 0x50 +#define AR8236_STATS_TXBROAD 0x54 +#define AR8236_STATS_TXPAUSE 0x58 +#define AR8236_STATS_TXMULTI 0x5c +#define AR8236_STATS_TXUNDERRUN 0x60 +#define AR8236_STATS_TX64BYTE 0x64 +#define AR8236_STATS_TX128BYTE 0x68 +#define AR8236_STATS_TX256BYTE 0x6c +#define AR8236_STATS_TX512BYTE 0x70 +#define AR8236_STATS_TX1024BYTE 0x74 +#define AR8236_STATS_TX1518BYTE 0x78 +#define AR8236_STATS_TXMAXBYTE 0x7c +#define AR8236_STATS_TXOVERSIZE 0x80 +#define AR8236_STATS_TXBYTE 0x84 +#define AR8236_STATS_TXCOLLISION 0x8c +#define AR8236_STATS_TXABORTCOL 0x90 +#define AR8236_STATS_TXMULTICOL 0x94 +#define AR8236_STATS_TXSINGLECOL 0x98 +#define AR8236_STATS_TXEXCDEFER 0x9c +#define AR8236_STATS_TXDEFER 0xa0 +#define AR8236_STATS_TXLATECOL 0xa4 + +#define AR8236_MIB_RXB_ID 15 /* RxGoodByte */ +#define AR8236_MIB_TXB_ID 31 /* TxByte */ + +#define AR8316_REG_POSTRIP 0x0008 +#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) +#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) +#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2) +#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3) +#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4) +#define AR8316_POSTRIP_RTL_MODE BIT(5) +#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6) +#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7) +#define AR8316_POSTRIP_SERDES_EN BIT(8) +#define AR8316_POSTRIP_SEL_ANA_RST BIT(9) +#define AR8316_POSTRIP_GATE_25M_EN BIT(10) +#define AR8316_POSTRIP_SEL_CLK25M BIT(11) +#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12) +#define AR8316_POSTRIP_DBG_MODE_I BIT(13) +#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14) +#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15) +#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16) +#define AR8316_POSTRIP_LPW_STATE_EN BIT(17) +#define AR8316_POSTRIP_MAN_EN BIT(18) +#define AR8316_POSTRIP_PHY_PLL_ON BIT(19) +#define AR8316_POSTRIP_LPW_EXIT BIT(20) +#define AR8316_POSTRIP_TXDELAY_S0 BIT(21) +#define AR8316_POSTRIP_TXDELAY_S1 BIT(22) +#define AR8316_POSTRIP_RXDELAY_S0 BIT(23) +#define AR8316_POSTRIP_LED_OPEN_EN BIT(24) +#define AR8316_POSTRIP_SPI_EN BIT(25) +#define AR8316_POSTRIP_RXDELAY_S1 BIT(26) +#define AR8316_POSTRIP_POWER_ON_SEL BIT(31) + +/* port speed */ +enum { + AR8216_PORT_SPEED_10M = 0, + AR8216_PORT_SPEED_100M = 1, + AR8216_PORT_SPEED_1000M = 2, + AR8216_PORT_SPEED_ERR = 3, +}; + +/* ingress 802.1q mode */ +enum { + AR8216_IN_PORT_ONLY = 0, + AR8216_IN_PORT_FALLBACK = 1, + AR8216_IN_VLAN_ONLY = 2, + AR8216_IN_SECURE = 3 +}; + +/* egress 802.1q mode */ +enum { + AR8216_OUT_KEEP = 0, + AR8216_OUT_STRIP_VLAN = 1, + AR8216_OUT_ADD_VLAN = 2 +}; + +/* port forwarding state */ +enum { + AR8216_PORT_STATE_DISABLED = 0, + AR8216_PORT_STATE_BLOCK = 1, + AR8216_PORT_STATE_LISTEN = 2, + AR8216_PORT_STATE_LEARN = 3, + AR8216_PORT_STATE_FORWARD = 4 +}; + +/* mib counter type */ +enum { + AR8XXX_MIB_BASIC = 0, + AR8XXX_MIB_EXTENDED = 1 +}; + +enum { + AR8XXX_VER_AR8216 = 0x01, + AR8XXX_VER_AR8236 = 0x03, + AR8XXX_VER_AR8316 = 0x10, + AR8XXX_VER_AR8327 = 0x12, + AR8XXX_VER_AR8337 = 0x13, +}; + +#define AR8XXX_NUM_ARL_RECORDS 100 + +enum arl_op { + AR8XXX_ARL_INITIALIZE, + AR8XXX_ARL_GET_NEXT +}; + +struct arl_entry { + u16 portmap; + u8 mac[6]; +}; + +struct ar8xxx_priv; + +struct ar8xxx_mib_desc { + unsigned int size; + unsigned int offset; + const char *name; + u8 type; +}; + +struct ar8xxx_chip { + unsigned long caps; + bool config_at_probe; + bool mii_lo_first; + + /* parameters to calculate REG_PORT_STATS_BASE */ + unsigned reg_port_stats_start; + unsigned reg_port_stats_length; + + unsigned reg_arl_ctrl; + + int (*hw_init)(struct ar8xxx_priv *priv); + void (*cleanup)(struct ar8xxx_priv *priv); + + const char *name; + int vlans; + int ports; + const struct switch_dev_ops *swops; + + void (*init_globals)(struct ar8xxx_priv *priv); + void (*init_port)(struct ar8xxx_priv *priv, int port); + void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); + u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); + u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); + int (*atu_flush)(struct ar8xxx_priv *priv); + int (*atu_flush_port)(struct ar8xxx_priv *priv, int port); + void (*vtu_flush)(struct ar8xxx_priv *priv); + void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); + void (*phy_fixup)(struct ar8xxx_priv *priv, int phy); + void (*set_mirror_regs)(struct ar8xxx_priv *priv); + void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a, + u32 *status, enum arl_op op); + int (*sw_hw_apply)(struct switch_dev *dev); + void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev); + int (*phy_read)(struct ar8xxx_priv *priv, int addr, int regnum); + int (*phy_write)(struct ar8xxx_priv *priv, int addr, int regnum, u16 val); + + const struct ar8xxx_mib_desc *mib_decs; + unsigned num_mibs; + unsigned mib_func; + int mib_rxb_id; + int mib_txb_id; +}; + +struct ar8xxx_priv { + struct switch_dev dev; + struct mii_bus *mii_bus; + struct mii_bus *sw_mii_bus; + struct phy_device *phy; + struct device *pdev; + + int (*get_port_link)(unsigned port); + + const struct net_device_ops *ndo_old; + struct net_device_ops ndo; + struct mutex reg_mutex; + u8 chip_ver; + u8 chip_rev; + const struct ar8xxx_chip *chip; + void *chip_data; + bool initialized; + bool port4_phy; + char buf[2048]; + struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS]; + char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256]; + bool link_up[AR8X16_MAX_PORTS]; + + bool init; + + struct mutex mib_lock; + struct delayed_work mib_work; + u64 *mib_stats; + u32 mib_poll_interval; + u8 mib_type; + + struct list_head list; + unsigned int use_count; + + /* all fields below are cleared on reset */ + struct_group(ar8xxx_priv_volatile, + bool vlan; + + u16 vlan_id[AR8XXX_MAX_VLANS]; + u8 vlan_table[AR8XXX_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[AR8X16_MAX_PORTS]; + int arl_age_time; + + /* mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; + u8 port_vlan_prio[AR8X16_MAX_PORTS]; + ); +}; + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum); +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val); +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg); +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val); +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +void +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 *dbg_data); +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data); +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data); +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg); +void +ar8xxx_phy_init(struct ar8xxx_priv *priv); +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan); +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan); +int +ar8xxx_sw_hw_apply(struct switch_dev *dev); +int +ar8xxx_sw_reset_switch(struct switch_dev *dev); +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link); +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats); +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +static inline struct ar8xxx_priv * +swdev_to_ar8xxx(struct switch_dev *swdev) +{ + return container_of(swdev, struct ar8xxx_priv, dev); +} + +static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_GIGE; +} + +static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS; +} + +static inline bool chip_is_ar8216(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8216; +} + +static inline bool chip_is_ar8236(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8236; +} + +static inline bool chip_is_ar8316(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8316; +} + +static inline bool chip_is_ar8327(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8327; +} + +static inline bool chip_is_ar8337(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8337; +} + +static inline void +ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, 0, val); +} + +static inline void +ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, val, 0); +} + +static inline void +split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +{ + regaddr >>= 1; + *r1 = regaddr & 0x1e; + + regaddr >>= 5; + *r2 = regaddr & 0x7; + + regaddr >>= 3; + *page = regaddr & 0x1ff; +} + +static inline void +wait_for_page_switch(void) +{ + udelay(5); +} + +#endif diff --git a/drivers/net/phy/ar8327.c b/drivers/net/phy/ar8327.c new file mode 100644 index 000000000000..d6749ad70ed2 --- /dev/null +++ b/drivers/net/phy/ar8327.c @@ -0,0 +1,1589 @@ +/* + * ar8327.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" +#include "ar8327.h" + +extern const struct ar8xxx_mib_desc ar8236_mibs[39]; +extern const struct switch_attr ar8xxx_sw_attr_vlan[1]; + +static u32 +ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) +{ + u32 t; + + if (!cfg) + return 0; + + t = 0; + switch (cfg->mode) { + case AR8327_PAD_NC: + break; + + case AR8327_PAD_MAC2MAC_MII: + t = AR8327_PAD_MAC_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2MAC_GMII: + t = AR8327_PAD_MAC_GMII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_SGMII: + t = AR8327_PAD_SGMII_EN; + + /* + * WAR for the QUalcomm Atheros AP136 board. + * It seems that RGMII TX/RX delay settings needs to be + * applied for SGMII mode as well, The ethernet is not + * reliable without this. + */ + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + + if (cfg->sgmii_delay_en) + t |= AR8327_PAD_SGMII_DELAY_EN; + + break; + + case AR8327_PAD_MAC2PHY_MII: + t = AR8327_PAD_PHY_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2PHY_GMII: + t = AR8327_PAD_PHY_GMII_EN; + if (cfg->pipe_rxclk_sel) + t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_RGMII: + t = AR8327_PAD_RGMII_EN; + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + break; + + case AR8327_PAD_PHY_GMII: + t = AR8327_PAD_PHYX_GMII_EN; + break; + + case AR8327_PAD_PHY_RGMII: + t = AR8327_PAD_PHYX_RGMII_EN; + break; + + case AR8327_PAD_PHY_MII: + t = AR8327_PAD_PHYX_MII_EN; + break; + } + + return t; +} + +static void +ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev) +{ + u16 phy_val = 0; + int phyaddr = phydev->mdio.addr; + struct device_node *np = phydev->mdio.dev.of_node; + + if (!np) + return; + + if (!of_property_read_bool(np, "qca,phy-rgmii-en")) { + pr_err("ar8327: qca,phy-rgmii-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_MODE_SEL, &phy_val); + phy_val |= AR8327_PHY_MODE_SEL_RGMII; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_MODE_SEL, phy_val); + + /* set rgmii tx clock delay if needed */ + if (!of_property_read_bool(np, "qca,txclk-delay-en")) { + pr_err("ar8327: qca,txclk-delay-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_SYS_CTRL, &phy_val); + phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_SYS_CTRL, phy_val); + + /* set rgmii rx clock delay if needed */ + if (!of_property_read_bool(np, "qca,rxclk-delay-en")) { + pr_err("ar8327: qca,rxclk-delay-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_TEST_CTRL, &phy_val); + phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_TEST_CTRL, phy_val); +} + +static void +ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) +{ + switch (priv->chip_rev) { + case 1: + /* For 100M waveform */ + ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea); + /* Turn on Gigabit clock */ + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0); + break; + + case 2: + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0); + fallthrough; + case 4: + ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f); + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); + ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46); + ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000); + break; + } +} + +static u32 +ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) +{ + u32 t; + + if (!cfg->force_link) + return AR8216_PORT_STATUS_LINK_AUTO; + + t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC; + t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0; + t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0; + t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0; + + switch (cfg->speed) { + case AR8327_PORT_SPEED_10: + t |= AR8216_PORT_SPEED_10M; + break; + case AR8327_PORT_SPEED_100: + t |= AR8216_PORT_SPEED_100M; + break; + case AR8327_PORT_SPEED_1000: + t |= AR8216_PORT_SPEED_1000M; + break; + } + + return t; +} + +#define AR8327_LED_ENTRY(_num, _reg, _shift) \ + [_num] = { .reg = (_reg), .shift = (_shift) } + +static const struct ar8327_led_entry +ar8327_led_map[AR8327_NUM_LEDS] = { + AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), + + AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), + AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), + AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), + + AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), + AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), + + AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), + AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), + AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), + + AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), +}; + +static void +ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, + enum ar8327_led_pattern pattern) +{ + const struct ar8327_led_entry *entry; + + entry = &ar8327_led_map[led_num]; + ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), + (3 << entry->shift), pattern << entry->shift); +} + +static void +ar8327_led_work_func(struct work_struct *work) +{ + struct ar8327_led *aled; + u8 pattern; + + aled = container_of(work, struct ar8327_led, led_work); + + pattern = aled->pattern; + + ar8327_set_led_pattern(aled->sw_priv, aled->led_num, + pattern); +} + +static void +ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) +{ + if (aled->pattern == pattern) + return; + + aled->pattern = pattern; + schedule_work(&aled->led_work); +} + +static inline struct ar8327_led * +led_cdev_to_ar8327_led(struct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct ar8327_led, cdev); +} + +static int +ar8327_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + + if (*delay_on == 0 && *delay_off == 0) { + *delay_on = 125; + *delay_off = 125; + } + + if (*delay_on != 125 || *delay_off != 125) { + /* + * The hardware only supports blinking at 4Hz. Fall back + * to software implementation in other cases. + */ + return -EINVAL; + } + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); + + spin_unlock(&aled->lock); + + return 0; +} + +static void +ar8327_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + bool active; + + active = (brightness != LED_OFF) != aled->active_low; + + pattern = (active) ? AR8327_LED_PATTERN_ON : + AR8327_LED_PATTERN_OFF; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); +} + +static ssize_t +ar8327_led_enable_hw_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + ssize_t ret = 0; + + ret += scnprintf(buf, PAGE_SIZE, "%d\n", aled->enable_hw_mode); + + return ret; +} + +static ssize_t +ar8327_led_enable_hw_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + u8 value; + int ret; + + ret = kstrtou8(buf, 10, &value); + if (ret < 0) + return -EINVAL; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = !!value; + if (aled->enable_hw_mode) + pattern = AR8327_LED_PATTERN_RULE; + else + pattern = AR8327_LED_PATTERN_OFF; + + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); + + return size; +} + +static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR, + ar8327_led_enable_hw_mode_show, + ar8327_led_enable_hw_mode_store); + +static int +ar8327_led_register(struct ar8327_led *aled) +{ + int ret; + struct led_init_data init_data = { + .fwnode = aled->fwnode + }; + + ret = led_classdev_register_ext(NULL, &aled->cdev, &init_data); + if (ret < 0) + return ret; + + if (aled->mode == AR8327_LED_MODE_HW) { + ret = device_create_file(aled->cdev.dev, + &dev_attr_enable_hw_mode); + if (ret) + goto err_unregister; + } + + return 0; + +err_unregister: + led_classdev_unregister(&aled->cdev); + return ret; +} + +static void +ar8327_led_unregister(struct ar8327_led *aled) +{ + if (aled->mode == AR8327_LED_MODE_HW) + device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); + + led_classdev_unregister(&aled->cdev); + cancel_work_sync(&aled->led_work); +} + +static int +ar8327_led_create(struct ar8xxx_priv *priv, + const struct ar8327_led_info *led_info) +{ + struct ar8327_data *data = priv->chip_data; + struct ar8327_led *aled; + int ret; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return 0; + + if (!led_info->name) + return -EINVAL; + + if (led_info->led_num >= AR8327_NUM_LEDS) + return -EINVAL; + + aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, + GFP_KERNEL); + if (!aled) + return -ENOMEM; + + aled->sw_priv = priv; + aled->led_num = led_info->led_num; + aled->active_low = led_info->active_low; + aled->mode = led_info->mode; + aled->fwnode = led_info->fwnode; + + if (aled->mode == AR8327_LED_MODE_HW) + aled->enable_hw_mode = true; + + aled->name = (char *)(aled + 1); + strcpy(aled->name, led_info->name); + + aled->cdev.name = aled->name; + aled->cdev.brightness_set = ar8327_led_set_brightness; + aled->cdev.blink_set = ar8327_led_blink_set; + aled->cdev.default_trigger = led_info->default_trigger; + + spin_lock_init(&aled->lock); + mutex_init(&aled->mutex); + INIT_WORK(&aled->led_work, ar8327_led_work_func); + + ret = ar8327_led_register(aled); + if (ret) + goto err_free; + + data->leds[data->num_leds++] = aled; + + return 0; + +err_free: + kfree(aled); + return ret; +} + +static void +ar8327_led_destroy(struct ar8327_led *aled) +{ + ar8327_led_unregister(aled); + kfree(aled); +} + +static void +ar8327_leds_init(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + + if (aled->enable_hw_mode) + aled->pattern = AR8327_LED_PATTERN_RULE; + else + aled->pattern = aled->active_low ? + AR8327_LED_PATTERN_ON : AR8327_LED_PATTERN_OFF; + + ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); + } +} + +static void +ar8327_leds_cleanup(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + ar8327_led_destroy(aled); + } + + kfree(data->leds); +} + +static int +ar8327_hw_config_pdata(struct ar8xxx_priv *priv, + struct ar8327_platform_data *pdata) +{ + struct ar8327_led_cfg *led_cfg; + struct ar8327_data *data = priv->chip_data; + u32 pos, new_pos; + u32 t; + + if (!pdata) + return -EINVAL; + + priv->get_port_link = pdata->get_port_link; + + data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg); + data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg); + + t = ar8327_get_pad_cfg(pdata->pad0_cfg); + if (chip_is_ar8337(priv) && !pdata->pad0_cfg->mac06_exchange_dis) + t |= AR8337_PAD_MAC06_EXCHANGE_EN; + ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t); + + t = ar8327_get_pad_cfg(pdata->pad5_cfg); + ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t); + t = ar8327_get_pad_cfg(pdata->pad6_cfg); + ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t); + + pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRAP); + new_pos = pos; + + led_cfg = pdata->led_cfg; + if (led_cfg) { + if (led_cfg->open_drain) + new_pos |= AR8327_POWER_ON_STRAP_LED_OPEN_EN; + else + new_pos &= ~AR8327_POWER_ON_STRAP_LED_OPEN_EN; + + ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0); + ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1); + ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2); + ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3); + + if (new_pos != pos) + new_pos |= AR8327_POWER_ON_STRAP_POWER_ON_SEL; + } + + if (pdata->sgmii_cfg) { + t = pdata->sgmii_cfg->sgmii_ctrl; + if (priv->chip_rev == 1) + t |= AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX; + else + t &= ~(AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX); + + ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t); + + if (pdata->sgmii_cfg->serdes_aen) + new_pos &= ~AR8327_POWER_ON_STRAP_SERDES_AEN; + else + new_pos |= AR8327_POWER_ON_STRAP_SERDES_AEN; + } + + ar8xxx_write(priv, AR8327_REG_POWER_ON_STRAP, new_pos); + + if (pdata->leds && pdata->num_leds) { + int i; + + data->leds = kzalloc(pdata->num_leds * sizeof(void *), + GFP_KERNEL); + if (!data->leds) + return -ENOMEM; + + for (i = 0; i < pdata->num_leds; i++) + ar8327_led_create(priv, &pdata->leds[i]); + } + + return 0; +} + +#ifdef CONFIG_OF +static int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + struct ar8327_data *data = priv->chip_data; + const __be32 *paddr; + int len; + int i; + struct device_node *leds, *child; + + paddr = of_get_property(np, "qca,ar8327-initvals", &len); + if (!paddr || len < (2 * sizeof(*paddr))) + return -EINVAL; + + len /= sizeof(*paddr); + + for (i = 0; i < len - 1; i += 2) { + u32 reg; + u32 val; + + reg = be32_to_cpup(paddr + i); + val = be32_to_cpup(paddr + i + 1); + + switch (reg) { + case AR8327_REG_PORT_STATUS(0): + data->port0_status = val; + break; + case AR8327_REG_PORT_STATUS(6): + data->port6_status = val; + break; + default: + ar8xxx_write(priv, reg, val); + break; + } + } + + leds = of_get_child_by_name(np, "leds"); + if (!leds) + return 0; + + data->leds = kvcalloc(of_get_child_count(leds), sizeof(void *), + GFP_KERNEL); + if (!data->leds) + return -ENOMEM; + + for_each_available_child_of_node(leds, child) { + u32 reg = 0, mode = 0; + struct ar8327_led_info info; + int ret; + + ret = of_property_read_u32(child, "reg", ®); + if (ret) { + pr_err("ar8327: LED %s is missing reg node\n", child->name); + continue; + } + + of_property_read_u32(child, "qca,led-mode", &mode); + + info = (struct ar8327_led_info) { + .name = of_get_property(child, "label", NULL) ? : child->name, + .fwnode = of_fwnode_handle(child), + .active_low = of_property_read_bool(child, "active-low"), + .led_num = (enum ar8327_led_num) reg, + .mode = (enum ar8327_led_mode) mode + }; + ar8327_led_create(priv, &info); + } + + of_node_put(leds); + return 0; +} +#else +static inline int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + return -EINVAL; +} +#endif + +static int +ar8327_hw_init(struct ar8xxx_priv *priv) +{ + int ret; + + priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL); + if (!priv->chip_data) + return -ENOMEM; + + if (priv->pdev->of_node) + ret = ar8327_hw_config_of(priv, priv->pdev->of_node); + else + ret = ar8327_hw_config_pdata(priv, + priv->phy->mdio.dev.platform_data); + + if (ret) + return ret; + + ar8327_leds_init(priv); + + ar8xxx_phy_init(priv); + + return 0; +} + +static void +ar8327_cleanup(struct ar8xxx_priv *priv) +{ + ar8327_leds_cleanup(priv); +} + +static void +ar8327_init_globals(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + int i; + + /* enable CPU port and disable mirror port */ + t = AR8327_FWD_CTRL0_CPU_PORT_EN | + AR8327_FWD_CTRL0_MIRROR_PORT; + ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t); + + /* forward multicast and broadcast frames to CPU */ + t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); + ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE, + AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN, + AR8327_MODULE_EN_MIB); + + /* Disable EEE on all phy's due to stability issues */ + for (i = 0; i < AR8XXX_NUM_PHYS; i++) + data->eee[i] = false; +} + +static void +ar8327_init_port(struct ar8xxx_priv *priv, int port) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + + if (port == AR8216_PORT_CPU) + t = data->port0_status; + else if (port == 6) + t = data->port6_status; + else + t = AR8216_PORT_STATUS_LINK_AUTO; + + if (port != AR8216_PORT_CPU && port != 6) { + /*hw limitation:if configure mac when there is traffic, + port MAC may work abnormal. Need disable lan&wan mac at fisrt*/ + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), 0); + msleep(100); + t |= AR8216_PORT_STATUS_FLOW_CONTROL; + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); + } else { + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); + } + + ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0); + + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), 0); + + t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = AR8327_PORT_LOOKUP_LEARN; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static u32 +ar8327_read_port_status(struct ar8xxx_priv *priv, int port) +{ + u32 t; + + t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); + /* map the flow control autoneg result bits to the flow control bits + * used in forced mode to allow ar8216_read_port_link detect + * flow control properly if autoneg is used + */ + if (t & AR8216_PORT_STATUS_LINK_UP && + t & AR8216_PORT_STATUS_LINK_AUTO) { + t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW); + if (t & AR8327_PORT_STATUS_TXFLOW_AUTO) + t |= AR8216_PORT_STATUS_TXFLOW; + if (t & AR8327_PORT_STATUS_RXFLOW_AUTO) + t |= AR8216_PORT_STATUS_RXFLOW; + } + + return t; +} + +static u32 +ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) +{ + int phy; + u16 t; + + if (port >= priv->dev.ports) + return 0; + + if (port == 0 || port == 6) + return 0; + + phy = port - 1; + + /* EEE Ability Auto-negotiation Result */ + t = ar8xxx_phy_mmd_read(priv, phy, 0x7, 0x8000); + + return mmd_eee_adv_to_ethtool_adv_t(t); +} + +static int +ar8327_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_OP_FLUSH | + AR8327_ATU_FUNC_BUSY); + + return ret; +} + +static int +ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) { + t = (port << AR8327_ATU_PORT_NUM_S); + t |= AR8327_ATU_FUNC_OP_FLUSH_PORT; + t |= AR8327_ATU_FUNC_BUSY; + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t); + } + + return ret; +} + +static int +ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port) +{ + u32 fwd_ctrl, frame_ack; + + fwd_ctrl = (BIT(port) << AR8327_FWD_CTRL1_IGMP_S); + frame_ack = ((AR8327_FRAME_ACK_CTRL_IGMP_MLD | + AR8327_FRAME_ACK_CTRL_IGMP_JOIN | + AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << + AR8327_FRAME_ACK_CTRL_S(port)); + + return (ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) & + fwd_ctrl) == fwd_ctrl && + (ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL(port)) & + frame_ack) == frame_ack; +} + +static void +ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable) +{ + int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL(port); + u32 val_frame_ack = (AR8327_FRAME_ACK_CTRL_IGMP_MLD | + AR8327_FRAME_ACK_CTRL_IGMP_JOIN | + AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << + AR8327_FRAME_ACK_CTRL_S(port); + + if (enable) { + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, + BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S, + BIT(port) << AR8327_FWD_CTRL1_IGMP_S); + ar8xxx_reg_set(priv, reg_frame_ack, val_frame_ack); + } else { + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, + BIT(port) << AR8327_FWD_CTRL1_IGMP_S, + BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S); + ar8xxx_reg_clear(priv, reg_frame_ack, val_frame_ack); + } +} + +static void +ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1, + AR8327_VTU_FUNC1_BUSY, 0)) + return; + + if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD) + ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val); + + op |= AR8327_VTU_FUNC1_BUSY; + ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op); +} + +static void +ar8327_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0); +} + +static void +ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + u32 val; + int i; + + op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S); + val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL; + for (i = 0; i < AR8327_NUM_PORTS; i++) { + u32 mode; + + if ((port_mask & BIT(i)) == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_NOT; + else if (priv->vlan == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_KEEP; + else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid)) + mode = AR8327_VTU_FUNC0_EG_MODE_TAG; + else + mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG; + + val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i); + } + ar8327_vtu_op(priv, op, val); +} + +static void +ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 t; + u32 egress, ingress; + u32 pvid = priv->vlan_id[priv->pvid[port]]; + + if (priv->vlan) { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD; + ingress = AR8216_IN_SECURE; + } else { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; + ingress = AR8216_IN_PORT_ONLY; + } + + t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S; + t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S; + if (priv->vlan && priv->port_vlan_prio[port]) { + u32 prio = priv->port_vlan_prio[port]; + + t |= prio << AR8327_PORT_VLAN0_DEF_SPRI_S; + t |= prio << AR8327_PORT_VLAN0_DEF_CPRI_S; + } + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); + + t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; + t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S; + if (priv->vlan && priv->port_vlan_prio[port]) + t |= AR8327_PORT_VLAN1_VLAN_PRI_PROP; + + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = members; + t |= AR8327_PORT_LOOKUP_LEARN; + t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static int +ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (val->port_vlan == priv->pvid[p->id]) { + priv->vlan_tagged |= (1 << p->id); + } + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8327_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + for (port = 0; port < AR8327_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8327_NUM_PORTS || + priv->monitor_port >= AR8327_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); +} + +static int +ar8327_sw_set_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + data->eee[phy] = !!(val->value.i); + + return 0; +} + +static int +ar8327_sw_get_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + val->value.i = data->eee[phy]; + + return 0; +} + +static void +ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) { + udelay(10); + cond_resched(); + } + + if (!timeout) + pr_err("ar8327: timeout waiting for atu to become ready\n"); +} + +static void ar8327_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_data0, r1_data1, r1_data2, r1_func; + u32 val0, val1, val2; + + split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page); + r2 |= 0x10; + + r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e; + r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e; + r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8327_wait_atu_ready(priv, r2, r1_func); + + ar8xxx_mii_write32(priv, r2, r1_data0, 0); + ar8xxx_mii_write32(priv, r2, r1_data1, 0); + ar8xxx_mii_write32(priv, r2, r1_data2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + ar8xxx_mii_write32(priv, r2, r1_func, + AR8327_ATU_FUNC_OP_GET_NEXT | + AR8327_ATU_FUNC_BUSY); + ar8327_wait_atu_ready(priv, r2, r1_func); + + val0 = ar8xxx_mii_read32(priv, r2, r1_data0); + val1 = ar8xxx_mii_read32(priv, r2, r1_data1); + val2 = ar8xxx_mii_read32(priv, r2, r1_data2); + + *status = val2 & AR8327_ATU_STATUS; + if (!*status) + break; + + a->portmap = (val1 & AR8327_ATU_PORTS) >> AR8327_ATU_PORTS_S; + a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S; + a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S; + a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S; + a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S; + a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S; + a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S; + break; + } +} + +static int +ar8327_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int ret, i; + + ret = ar8xxx_sw_hw_apply(dev); + if (ret) + return ret; + + for (i=0; i < AR8XXX_NUM_PHYS; i++) { + if (data->eee[i]) + ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + else + ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + } + + return 0; +} + +static int +ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + val->value.i = ar8327_get_port_igmp(priv, port); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +static int +ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + ar8327_set_port_igmp(priv, port, val->value.i); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +static int +ar8327_sw_get_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int port; + + for (port = 0; port < dev->ports; port++) { + val->port_vlan = port; + if (ar8327_sw_get_port_igmp_snooping(dev, attr, val) || + !val->value.i) + break; + } + + return 0; +} + +static int +ar8327_sw_set_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int port; + + for (port = 0; port < dev->ports; port++) { + val->port_vlan = port; + if (ar8327_sw_set_port_igmp_snooping(dev, attr, val)) + break; + } + + return 0; +} + +static int +ar8327_sw_get_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u32 val_reg; + + mutex_lock(&priv->reg_mutex); + val_reg = ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL1); + val->value.i = ((val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN) != 0); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +static int +ar8327_sw_set_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + if (val->value.i) + ar8xxx_reg_set(priv, AR8327_REG_FRAME_ACK_CTRL1, + AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); + else + ar8xxx_reg_clear(priv, AR8327_REG_FRAME_ACK_CTRL1, + AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +static int +ar8327_sw_set_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + if (val->value.i < 0 || val->value.i > 7) + return -EINVAL; + + priv->port_vlan_prio[port] = val->value.i; + + return 0; +} + +static int +ar8327_sw_get_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + val->value.i = priv->port_vlan_prio[port]; + + return 0; +} + +static const struct switch_attr ar8327_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_poll_interval", + .description = "MIB polling interval in msecs (0 to disable)", + .set = ar8xxx_sw_set_mib_poll_interval, + .get = ar8xxx_sw_get_mib_poll_interval + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_type", + .description = "MIB type (0=basic 1=extended)", + .set = ar8xxx_sw_set_mib_type, + .get = ar8xxx_sw_get_mib_type + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "arl_age_time", + .description = "ARL age time (secs)", + .set = ar8xxx_sw_set_arl_age_time, + .get = ar8xxx_sw_get_arl_age_time, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_snooping", + .description = "Enable IGMP Snooping", + .set = ar8327_sw_set_igmp_snooping, + .get = ar8327_sw_get_igmp_snooping, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_v3", + .description = "Enable IGMPv3 support", + .set = ar8327_sw_set_igmp_v3, + .get = ar8327_sw_get_igmp_v3, + .max = 1 + }, +}; + +static const struct switch_attr ar8327_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_eee", + .description = "Enable EEE PHY sleep mode", + .set = ar8327_sw_set_eee, + .get = ar8327_sw_get_eee, + .max = 1, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_snooping", + .description = "Enable port's IGMP Snooping", + .set = ar8327_sw_set_port_igmp_snooping, + .get = ar8327_sw_get_port_igmp_snooping, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "vlan_prio", + .description = "Port VLAN default priority (VLAN PCP) (0-7)", + .set = ar8327_sw_set_port_vlan_prio, + .get = ar8327_sw_get_port_vlan_prio, + .max = 7, + }, +}; + +static const struct switch_dev_ops ar8327_sw_ops = { + .attr_global = { + .attr = ar8327_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), + }, + .attr_port = { + .attr = ar8327_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8327_sw_get_ports, + .set_vlan_ports = ar8327_sw_set_ports, + .apply_config = ar8327_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, + .get_port_stats = ar8xxx_sw_get_port_stats, +}; + +const struct ar8xxx_chip ar8327_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8327", + .ports = AR8327_NUM_PORTS, + .vlans = AR83X7_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8327_REG_ARL_CTRL, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +const struct ar8xxx_chip ar8337_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8337", + .ports = AR8327_NUM_PORTS, + .vlans = AR83X7_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8327_REG_ARL_CTRL, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + .phy_rgmii_set = ar8327_phy_rgmii_set, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; diff --git a/drivers/net/phy/ar8327.h b/drivers/net/phy/ar8327.h new file mode 100644 index 000000000000..53a82d1f76a3 --- /dev/null +++ b/drivers/net/phy/ar8327.h @@ -0,0 +1,334 @@ +/* + * ar8327.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AR8327_H +#define __AR8327_H + +#define AR8327_NUM_PORTS 7 +#define AR8327_NUM_LEDS 15 +#define AR8327_PORTS_ALL 0x7f +#define AR8327_NUM_LED_CTRL_REGS 4 + +#define AR8327_REG_MASK 0x000 + +#define AR8327_REG_PAD0_MODE 0x004 +#define AR8327_REG_PAD5_MODE 0x008 +#define AR8327_REG_PAD6_MODE 0x00c +#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0) +#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1) +#define AR8327_PAD_MAC_MII_EN BIT(2) +#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4) +#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5) +#define AR8327_PAD_MAC_GMII_EN BIT(6) +#define AR8327_PAD_SGMII_EN BIT(7) +#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8) +#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9) +#define AR8327_PAD_PHY_MII_EN BIT(10) +#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11) +#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12) +#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13) +#define AR8327_PAD_PHY_GMII_EN BIT(14) +#define AR8327_PAD_PHYX_GMII_EN BIT(16) +#define AR8327_PAD_PHYX_RGMII_EN BIT(17) +#define AR8327_PAD_PHYX_MII_EN BIT(18) +#define AR8327_PAD_SGMII_DELAY_EN BIT(19) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20 +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2) +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22 +#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24) +#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25) +#define AR8327_PAD_RGMII_EN BIT(26) + +#define AR8327_REG_POWER_ON_STRAP 0x010 +#define AR8327_POWER_ON_STRAP_POWER_ON_SEL BIT(31) +#define AR8327_POWER_ON_STRAP_LED_OPEN_EN BIT(24) +#define AR8327_POWER_ON_STRAP_SERDES_AEN BIT(7) + +#define AR8327_REG_INT_STATUS0 0x020 +#define AR8327_INT0_VT_DONE BIT(20) + +#define AR8327_REG_INT_STATUS1 0x024 +#define AR8327_REG_INT_MASK0 0x028 +#define AR8327_REG_INT_MASK1 0x02c + +#define AR8327_REG_MODULE_EN 0x030 +#define AR8327_MODULE_EN_MIB BIT(0) + +#define AR8327_REG_MIB_FUNC 0x034 +#define AR8327_MIB_CPU_KEEP BIT(20) + +#define AR8327_REG_SERVICE_TAG 0x048 +#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4) +#define AR8327_REG_LED_CTRL0 0x050 +#define AR8327_REG_LED_CTRL1 0x054 +#define AR8327_REG_LED_CTRL2 0x058 +#define AR8327_REG_LED_CTRL3 0x05c +#define AR8327_REG_MAC_ADDR0 0x060 +#define AR8327_REG_MAC_ADDR1 0x064 + +#define AR8327_REG_MAX_FRAME_SIZE 0x078 +#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14) + +#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) +#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10) +#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11) + +#define AR8327_REG_HEADER_CTRL 0x098 +#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) + +#define AR8327_REG_SGMII_CTRL 0x0e0 +#define AR8327_SGMII_CTRL_EN_PLL BIT(1) +#define AR8327_SGMII_CTRL_EN_RX BIT(2) +#define AR8327_SGMII_CTRL_EN_TX BIT(3) + +#define AR8327_REG_EEE_CTRL 0x100 +#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) + +#define AR8327_REG_FRAME_ACK_CTRL0 0x210 +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0 BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0 BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0 BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN0 BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN0 BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0 BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0 BIT(6) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1 BIT(8) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1 BIT(9) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1 BIT(10) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN1 BIT(11) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN1 BIT(12) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1 BIT(13) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1 BIT(14) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2 BIT(16) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2 BIT(17) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2 BIT(18) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN2 BIT(19) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN2 BIT(20) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2 BIT(21) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2 BIT(22) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3 BIT(24) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3 BIT(25) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3 BIT(26) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN3 BIT(27) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN3 BIT(28) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3 BIT(29) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3 BIT(30) + +#define AR8327_REG_FRAME_ACK_CTRL1 0x214 +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4 BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4 BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4 BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN4 BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN4 BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4 BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4 BIT(6) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5 BIT(8) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5 BIT(9) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5 BIT(10) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN5 BIT(11) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN5 BIT(12) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5 BIT(13) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5 BIT(14) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6 BIT(16) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6 BIT(17) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6 BIT(18) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN6 BIT(19) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN6 BIT(20) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6 BIT(21) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6 BIT(22) +#define AR8327_FRAME_ACK_CTRL_IGMP_V3_EN BIT(24) +#define AR8327_FRAME_ACK_CTRL_PPPOE_EN BIT(25) + +#define AR8327_REG_FRAME_ACK_CTRL(_i) (0x210 + ((_i) / 4) * 0x4) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ BIT(6) +#define AR8327_FRAME_ACK_CTRL_S(_i) (((_i) % 4) * 8) + +#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) +#define AR8327_PORT_VLAN0_DEF_PRI_MASK BITS(0, 3) +#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12) +#define AR8327_PORT_VLAN0_DEF_SVID_S 0 +#define AR8327_PORT_VLAN0_DEF_SPRI BITS(13, 3) +#define AR8327_PORT_VLAN0_DEF_SPRI_S 13 +#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12) +#define AR8327_PORT_VLAN0_DEF_CVID_S 16 +#define AR8327_PORT_VLAN0_DEF_CPRI BITS(29, 3) +#define AR8327_PORT_VLAN0_DEF_CPRI_S 29 + +#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) +#define AR8327_PORT_VLAN1_VLAN_PRI_PROP BIT(4) +#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6) +#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2) +#define AR8327_PORT_VLAN1_OUT_MODE_S 12 +#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1 +#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3 + +#define AR8327_REG_ATU_DATA0 0x600 +#define AR8327_ATU_ADDR0 BITS(0, 8) +#define AR8327_ATU_ADDR0_S 0 +#define AR8327_ATU_ADDR1 BITS(8, 8) +#define AR8327_ATU_ADDR1_S 8 +#define AR8327_ATU_ADDR2 BITS(16, 8) +#define AR8327_ATU_ADDR2_S 16 +#define AR8327_ATU_ADDR3 BITS(24, 8) +#define AR8327_ATU_ADDR3_S 24 +#define AR8327_REG_ATU_DATA1 0x604 +#define AR8327_ATU_ADDR4 BITS(0, 8) +#define AR8327_ATU_ADDR4_S 0 +#define AR8327_ATU_ADDR5 BITS(8, 8) +#define AR8327_ATU_ADDR5_S 8 +#define AR8327_ATU_PORTS BITS(16, 7) +#define AR8327_ATU_PORTS_S 16 +#define AR8327_ATU_PORT0 BIT(16) +#define AR8327_ATU_PORT1 BIT(17) +#define AR8327_ATU_PORT2 BIT(18) +#define AR8327_ATU_PORT3 BIT(19) +#define AR8327_ATU_PORT4 BIT(20) +#define AR8327_ATU_PORT5 BIT(21) +#define AR8327_ATU_PORT6 BIT(22) +#define AR8327_REG_ATU_DATA2 0x608 +#define AR8327_ATU_STATUS BITS(0, 4) + +#define AR8327_REG_ATU_FUNC 0x60c +#define AR8327_ATU_FUNC_OP BITS(0, 4) +#define AR8327_ATU_FUNC_OP_NOOP 0x0 +#define AR8327_ATU_FUNC_OP_FLUSH 0x1 +#define AR8327_ATU_FUNC_OP_LOAD 0x2 +#define AR8327_ATU_FUNC_OP_PURGE 0x3 +#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4 +#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5 +#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6 +#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7 +#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8 +#define AR8327_ATU_PORT_NUM BITS(8, 4) +#define AR8327_ATU_PORT_NUM_S 8 +#define AR8327_ATU_FUNC_BUSY BIT(31) + +#define AR8327_REG_VTU_FUNC0 0x0610 +#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14) +#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) +#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0 +#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1 +#define AR8327_VTU_FUNC0_EG_MODE_TAG 2 +#define AR8327_VTU_FUNC0_EG_MODE_NOT 3 +#define AR8327_VTU_FUNC0_IVL BIT(19) +#define AR8327_VTU_FUNC0_VALID BIT(20) + +#define AR8327_REG_VTU_FUNC1 0x0614 +#define AR8327_VTU_FUNC1_OP BITS(0, 3) +#define AR8327_VTU_FUNC1_OP_NOOP 0 +#define AR8327_VTU_FUNC1_OP_FLUSH 1 +#define AR8327_VTU_FUNC1_OP_LOAD 2 +#define AR8327_VTU_FUNC1_OP_PURGE 3 +#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4 +#define AR8327_VTU_FUNC1_OP_GET_NEXT 5 +#define AR8327_VTU_FUNC1_OP_GET_ONE 6 +#define AR8327_VTU_FUNC1_FULL BIT(4) +#define AR8327_VTU_FUNC1_PORT BIT(8, 4) +#define AR8327_VTU_FUNC1_PORT_S 8 +#define AR8327_VTU_FUNC1_VID BIT(16, 12) +#define AR8327_VTU_FUNC1_VID_S 16 +#define AR8327_VTU_FUNC1_BUSY BIT(31) + +#define AR8327_REG_ARL_CTRL 0x0618 + +#define AR8327_REG_FWD_CTRL0 0x620 +#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10) +#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4) +#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4 + +#define AR8327_REG_FWD_CTRL1 0x624 +#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7) +#define AR8327_FWD_CTRL1_UC_FLOOD_S 0 +#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7) +#define AR8327_FWD_CTRL1_MC_FLOOD_S 8 +#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7) +#define AR8327_FWD_CTRL1_BC_FLOOD_S 16 +#define AR8327_FWD_CTRL1_IGMP BITS(24, 7) +#define AR8327_FWD_CTRL1_IGMP_S 24 + +#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) +#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7) +#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2) +#define AR8327_PORT_LOOKUP_IN_MODE_S 8 +#define AR8327_PORT_LOOKUP_STATE BITS(16, 3) +#define AR8327_PORT_LOOKUP_STATE_S 16 +#define AR8327_PORT_LOOKUP_LEARN BIT(20) +#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) + +#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) + +#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) + +#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31) + +#define AR8327_PHY_MODE_SEL 0x12 +#define AR8327_PHY_MODE_SEL_RGMII BIT(3) +#define AR8327_PHY_TEST_CTRL 0x0 +#define AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY BIT(15) +#define AR8327_PHY_SYS_CTRL 0x5 +#define AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY BIT(8) + +enum ar8327_led_pattern { + AR8327_LED_PATTERN_OFF = 0, + AR8327_LED_PATTERN_BLINK, + AR8327_LED_PATTERN_ON, + AR8327_LED_PATTERN_RULE, +}; + +struct ar8327_led_entry { + unsigned reg; + unsigned shift; +}; + +struct ar8327_led { + struct led_classdev cdev; + struct ar8xxx_priv *sw_priv; + + char *name; + bool active_low; + u8 led_num; + enum ar8327_led_mode mode; + + struct mutex mutex; + spinlock_t lock; + struct work_struct led_work; + bool enable_hw_mode; + enum ar8327_led_pattern pattern; + struct fwnode_handle *fwnode; +}; + +struct ar8327_data { + u32 port0_status; + u32 port6_status; + + struct ar8327_led **leds; + unsigned int num_leds; + + /* all fields below are cleared on reset */ + bool eee[AR8XXX_NUM_PHYS]; +}; + +#endif diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig new file mode 100644 index 000000000000..08287e7adf79 --- /dev/null +++ b/drivers/net/phy/b53/Kconfig @@ -0,0 +1,37 @@ +menuconfig SWCONFIG_B53 + tristate "Broadcom bcm53xx managed switch support" + depends on SWCONFIG + help + This driver adds support for Broadcom managed switch chips. It supports + BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX + integrated switches. + +config SWCONFIG_B53_SPI_DRIVER + tristate "B53 SPI connected switch driver" + depends on SWCONFIG_B53 && SPI + help + Select to enable support for registering switches configured through SPI. + +config SWCONFIG_B53_PHY_DRIVER + tristate "B53 MDIO connected switch driver" + depends on SWCONFIG_B53 + select SWCONFIG_B53_PHY_FIXUP + help + Select to enable support for registering switches configured through MDIO. + +config SWCONFIG_B53_MMAP_DRIVER + tristate "B53 MMAP connected switch driver" + depends on SWCONFIG_B53 + help + Select to enable support for memory-mapped switches like the BCM63XX + integrated switches. + +config SWCONFIG_B53_SRAB_DRIVER + tristate "B53 SRAB connected switch driver" + depends on SWCONFIG_B53 + help + Select to enable support for memory-mapped Switch Register Access + Bridge Registers (SRAB) like it is found on the BCM53010 + +config SWCONFIG_B53_PHY_FIXUP + bool diff --git a/drivers/net/phy/b53/Makefile b/drivers/net/phy/b53/Makefile new file mode 100644 index 000000000000..13ff366448df --- /dev/null +++ b/drivers/net/phy/b53/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_SWCONFIG_B53) += b53_common.o + +obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP) += b53_phy_fixup.o + +obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER) += b53_mmap.o +obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER) += b53_srab.o +obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER) += b53_mdio.o +obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER) += b53_spi.o + +ccflags-y += -Werror diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c new file mode 100644 index 000000000000..d5f9bfc2f043 --- /dev/null +++ b/drivers/net/phy/b53/b53_common.c @@ -0,0 +1,1724 @@ +/* + * B53 switch driver main logic + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b53_regs.h" +#include "b53_priv.h" + +/* buffer size needed for displaying all MIBs with max'd values */ +#define B53_BUF_SIZE 1188 + +struct b53_mib_desc { + u8 size; + u8 offset; + const char *name; +}; + +/* BCM5365 MIB counters */ +static const struct b53_mib_desc b53_mibs_65[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { }, +}; + +#define B63XX_MIB_TXB_ID 0 /* TxOctets */ +#define B63XX_MIB_RXB_ID 14 /* RxOctets */ + +/* BCM63xx MIB counters */ +static const struct b53_mib_desc b53_mibs_63xx[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x0c, "TxQoSPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x3c, "TxQoSOctets" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { 4, 0xa0, "RxSymbolErrors" }, + { 4, 0xa4, "RxQoSPkts" }, + { 8, 0xa8, "RxQoSOctets" }, + { 4, 0xb0, "Pkts1523to2047Octets" }, + { 4, 0xb4, "Pkts2048to4095Octets" }, + { 4, 0xb8, "Pkts4096to8191Octets" }, + { 4, 0xbc, "Pkts8192to9728Octets" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +#define B53XX_MIB_TXB_ID 0 /* TxOctets */ +#define B53XX_MIB_RXB_ID 12 /* RxOctets */ + +/* MIB counters */ +static const struct b53_mib_desc b53_mibs[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x50, "RxOctets" }, + { 4, 0x58, "RxUndersizePkts" }, + { 4, 0x5c, "RxPausePkts" }, + { 4, 0x60, "Pkts64Octets" }, + { 4, 0x64, "Pkts65to127Octets" }, + { 4, 0x68, "Pkts128to255Octets" }, + { 4, 0x6c, "Pkts256to511Octets" }, + { 4, 0x70, "Pkts512to1023Octets" }, + { 4, 0x74, "Pkts1024to1522Octets" }, + { 4, 0x78, "RxOversizePkts" }, + { 4, 0x7c, "RxJabbers" }, + { 4, 0x80, "RxAlignmentErrors" }, + { 4, 0x84, "RxFCSErrors" }, + { 8, 0x88, "RxGoodOctets" }, + { 4, 0x90, "RxDropPkts" }, + { 4, 0x94, "RxUnicastPkts" }, + { 4, 0x98, "RxMulticastPkts" }, + { 4, 0x9c, "RxBroadcastPkts" }, + { 4, 0xa0, "RxSAChanges" }, + { 4, 0xa4, "RxFragments" }, + { 4, 0xa8, "RxJumboPkts" }, + { 4, 0xac, "RxSymbolErrors" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +static int b53_do_vlan_op(struct b53_device *dev, u8 op) +{ + unsigned int i; + + b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); + + for (i = 0; i < 10; i++) { + u8 vta; + + b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); + if (!(vta & VTA_START_CMD)) + return 0; + + usleep_range(100, 200); + } + + return -EIO; +} + +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, + u16 untag) +{ + if (is5325(dev)) { + u32 entry = 0; + + if (members) { + entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | + members; + if (dev->core_rev >= 3) + entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; + else + entry |= VA_VALID_25; + } + + b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else if (is5365(dev)) { + u16 entry = 0; + + if (members) + entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | + members | VA_VALID_65; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else { + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); + b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], + (untag << VTE_UNTAG_S) | members); + + b53_do_vlan_op(dev, VTA_CMD_WRITE); + } +} + +void b53_set_forwarding(struct b53_device *dev, int enable) +{ + u8 mgmt; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (enable) + mgmt |= SM_SW_FWD_EN; + else + mgmt &= ~SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static void b53_enable_vlan(struct b53_device *dev, int enable) +{ + u8 mgmt, vc0, vc1, vc4 = 0, vc5; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); + + if (is5325(dev) || is5365(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); + } else if (is63xx(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); + } else { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + + mgmt &= ~SM_SW_FWD_MODE; + + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; + vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + + if (is5325(dev)) + vc0 &= ~VC0_RESERVED_1; + + if (is5325(dev) || is5365(dev)) + vc1 |= VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) { + if (dev->allow_vid_4095) + vc5 |= VC5_VID_FFF_EN; + else + vc5 &= ~VC5_VID_FFF_EN; + } + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); + vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + + if (is5325(dev) || is5365(dev)) + vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; + else + vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; + + if (is5325(dev) || is5365(dev)) + vc1 &= ~VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) + vc5 &= ~VC5_VID_FFF_EN; + } + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); + + if (is5325(dev) || is5365(dev)) { + /* enable the high 8 bit vid check on 5325 */ + if (is5325(dev) && enable) + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, + VC3_HIGH_8BIT_EN); + else + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); + } else if (is63xx(dev)) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); + } else { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); + } + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100) +{ + u32 port_mask = 0; + u16 max_size = JMS_MIN_SIZE; + + if (is5325(dev) || is5365(dev)) + return -EINVAL; + + if (enable) { + port_mask = dev->enabled_ports; + max_size = JMS_MAX_SIZE; + if (allow_10_100) + port_mask |= JPM_10_100_JUMBO_EN; + } + + b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); + return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); +} + +static int b53_flush_arl(struct b53_device *dev) +{ + unsigned int i; + + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); + + for (i = 0; i < 10; i++) { + u8 fast_age_ctrl; + + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + &fast_age_ctrl); + + if (!(fast_age_ctrl & FAST_AGE_DONE)) + return 0; + + mdelay(1); + } + + pr_warn("time out while flushing ARL\n"); + + return -EINVAL; +} + +static void b53_enable_ports(struct b53_device *dev) +{ + unsigned i; + + b53_for_each_port(dev, i) { + u8 port_ctrl; + u16 pvlan_mask; + + /* + * prevent leaking packets between wan and lan in unmanaged + * mode through port vlans. + */ + if (dev->enable_vlan || is_cpu_port(dev, i)) + pvlan_mask = 0x1ff; + else if (is531x5(dev) || is5301x(dev)) + /* BCM53115 may use a different port as cpu port */ + pvlan_mask = BIT(dev->sw_dev.cpu_port); + else + pvlan_mask = BIT(B53_CPU_PORT); + + /* BCM5325 CPU port is at 8 */ + if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25) + i = B53_CPU_PORT; + + if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7)) + /* disable unused ports 6 & 7 */ + port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; + else if (i == B53_CPU_PORT) + port_ctrl = PORT_CTRL_RX_BCST_EN | + PORT_CTRL_RX_MCST_EN | + PORT_CTRL_RX_UCST_EN; + else + port_ctrl = 0; + + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), + pvlan_mask); + + /* port state is handled by bcm63xx_enet driver */ + if (!is63xx(dev) && !(is5301x(dev) && i == 6)) + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i), + port_ctrl); + } +} + +static void b53_enable_mib(struct b53_device *dev) +{ + u8 gc; + + b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); + + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); +} + +static int b53_apply(struct b53_device *dev) +{ + int i; + + /* clear all vlan entries */ + if (is5325(dev) || is5365(dev)) { + for (i = 1; i < dev->sw_dev.vlans; i++) + b53_set_vlan_entry(dev, i, 0, 0); + } else { + b53_do_vlan_op(dev, VTA_CMD_CLEAR); + } + + b53_enable_vlan(dev, dev->enable_vlan); + + /* fill VLAN table */ + if (dev->enable_vlan) { + for (i = 0; i < dev->sw_dev.vlans; i++) { + struct b53_vlan *vlan = &dev->vlans[i]; + + if (!vlan->members) + continue; + + b53_set_vlan_entry(dev, i, vlan->members, vlan->untag); + } + + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), + dev->ports[i].pvid); + } else { + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), 1); + + } + + b53_enable_ports(dev); + + if (!is5325(dev) && !is5365(dev)) + b53_set_jumbo(dev, dev->enable_jumbo, 1); + + return 0; +} + +static void b53_switch_reset_gpio(struct b53_device *dev) +{ + int gpio = dev->reset_gpio; + + if (gpio < 0) + return; + + /* + * Reset sequence: RESET low(50ms)->high(20ms) + */ + gpio_set_value(gpio, 0); + mdelay(50); + + gpio_set_value(gpio, 1); + mdelay(20); + + dev->current_page = 0xff; +} + +static int b53_configure_ports_of(struct b53_device *dev) +{ + struct device_node *dn, *pn; + u32 port_num; + + dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); + + for_each_available_child_of_node(dn, pn) { + struct device_node *fixed_link; + + if (of_property_read_u32(pn, "reg", &port_num)) + continue; + + if (port_num > B53_CPU_PORT) + continue; + + fixed_link = of_get_child_by_name(pn, "fixed-link"); + if (fixed_link) { + u32 spd; + u8 po = GMII_PO_LINK; + phy_interface_t mode; + + of_get_phy_mode(pn, &mode); + + if (!of_property_read_u32(fixed_link, "speed", &spd)) { + switch (spd) { + case 10: + po |= GMII_PO_SPEED_10M; + break; + case 100: + po |= GMII_PO_SPEED_100M; + break; + case 2000: + if (is_imp_port(dev, port_num)) + po |= PORT_OVERRIDE_SPEED_2000M; + else + po |= GMII_PO_SPEED_2000M; + fallthrough; + case 1000: + po |= GMII_PO_SPEED_1000M; + break; + } + } + + if (of_property_read_bool(fixed_link, "full-duplex")) + po |= PORT_OVERRIDE_FULL_DUPLEX; + if (of_property_read_bool(fixed_link, "pause")) + po |= GMII_PO_RX_FLOW; + if (of_property_read_bool(fixed_link, "asym-pause")) + po |= GMII_PO_TX_FLOW; + + if (is_imp_port(dev, port_num)) { + po |= PORT_OVERRIDE_EN; + + if (is5325(dev) && + mode == PHY_INTERFACE_MODE_REVMII) + po |= PORT_OVERRIDE_RV_MII_25; + + b53_write8(dev, B53_CTRL_PAGE, + B53_PORT_OVERRIDE_CTRL, po); + + if (is5325(dev) && + mode == PHY_INTERFACE_MODE_REVMII) { + b53_read8(dev, B53_CTRL_PAGE, + B53_PORT_OVERRIDE_CTRL, &po); + if (!(po & PORT_OVERRIDE_RV_MII_25)) + pr_err("Failed to enable reverse MII mode\n"); + return -EINVAL; + } + } else { + po |= GMII_PO_EN; + b53_write8(dev, B53_CTRL_PAGE, + B53_GMII_PORT_OVERRIDE_CTRL(port_num), + po); + } + } + } + + return 0; +} + +static int b53_configure_ports(struct b53_device *dev) +{ + u8 cpu_port = dev->sw_dev.cpu_port; + + /* configure MII port if necessary */ + if (is5325(dev)) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + /* reverse mii needs to be enabled */ + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_RV_MII_25); + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + pr_err("Failed to enable reverse MII mode\n"); + return -EINVAL; + } + } + } else if (is531x5(dev) && cpu_port == B53_CPU_PORT) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_EN | + PORT_OVERRIDE_LINK); + + /* BCM47189 has another interface connected to the port 5 */ + if (dev->enabled_ports & BIT(5)) { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(5); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } else if (is5301x(dev)) { + if (cpu_port == 8) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + mii_port_override |= PORT_OVERRIDE_LINK | + PORT_OVERRIDE_RX_FLOW | + PORT_OVERRIDE_TX_FLOW | + PORT_OVERRIDE_SPEED_2000M | + PORT_OVERRIDE_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override); + + /* TODO: Ports 5 & 7 require some extra handling */ + } else { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN | + GMII_PO_SPEED_2000M; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } + + return 0; +} + +static int b53_switch_reset(struct b53_device *dev) +{ + int ret = 0; + u8 mgmt; + + b53_switch_reset_gpio(dev); + + if (is539x(dev)) { + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); + } + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + mgmt &= ~SM_SW_FWD_MODE; + mgmt |= SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + pr_err("Failed to enable switch!\n"); + return -EINVAL; + } + } + + /* enable all ports */ + b53_enable_ports(dev); + + if (dev->dev->of_node) + ret = b53_configure_ports_of(dev); + else + ret = b53_configure_ports(dev); + + if (ret) + return ret; + + b53_enable_mib(dev); + + return b53_flush_arl(dev); +} + +/* + * Swconfig glue functions + */ + +static int b53_global_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_vlan; + + return 0; +} + +static int b53_global_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_vlan = val->value.i; + + return 0; +} + +static int b53_global_get_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_jumbo; + + return 0; +} + +static int b53_global_set_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_jumbo = val->value.i; + + return 0; +} + +static int b53_global_get_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->allow_vid_4095; + + return 0; +} + +static int b53_global_set_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->allow_vid_4095 = val->value.i; + + return 0; +} + +static int b53_global_get_ports(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x", + priv->enabled_ports); + val->value.s = priv->buf; + + return 0; +} + +static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + *val = priv->ports[port].pvid; + + return 0; +} + +static int b53_port_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (val > 15 && is5325(priv)) + return -EINVAL; + if (val == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + priv->ports[port].pvid = val; + + return 0; +} + +static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port = &val->value.ports[0]; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + val->len = 0; + + if (!vlan->members) + return 0; + + for (i = 0; i < dev->ports; i++) { + if (!(vlan->members & BIT(i))) + continue; + + + if (!(vlan->untag & BIT(i))) + port->flags = BIT(SWITCH_PORT_FLAG_TAGGED); + else + port->flags = 0; + + port->id = i; + val->len++; + port++; + } + + return 0; +} + +static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + /* only BCM5325 and BCM5365 supports VID 0 */ + if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv)) + return -EINVAL; + + /* VLAN 4095 needs special handling */ + if (val->port_vlan == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + port = &val->value.ports[0]; + vlan->members = 0; + vlan->untag = 0; + for (i = 0; i < val->len; i++, port++) { + vlan->members |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) { + vlan->untag |= BIT(port->id); + priv->ports[port->id].pvid = val->port_vlan; + }; + } + + /* ignore disabled ports */ + vlan->members &= priv->enabled_ports; + vlan->untag &= priv->enabled_ports; + + return 0; +} + +static int b53_port_get_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (is_cpu_port(priv, port)) { + link->link = 1; + link->duplex = 1; + link->speed = is5325(priv) || is5365(priv) ? + SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000; + link->aneg = 0; + } else if (priv->enabled_ports & BIT(port)) { + u32 speed; + u16 lnk, duplex; + + b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk); + b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex); + + lnk = (lnk >> port) & 1; + duplex = (duplex >> port) & 1; + + if (is5325(priv) || is5365(priv)) { + u16 tmp; + + b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp); + speed = SPEED_PORT_FE(tmp, port); + } else { + b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed); + speed = SPEED_PORT_GE(speed, port); + } + + link->link = lnk; + if (lnk) { + link->duplex = duplex; + switch (speed) { + case SPEED_STAT_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case SPEED_STAT_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case SPEED_STAT_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + } + } + + link->aneg = 1; + } else { + link->link = 0; + } + + return 0; + +} + +static int b53_port_set_link(struct switch_dev *sw_dev, int port, + struct switch_port_link *link) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + + /* + * TODO: BCM63XX requires special handling as it can have external phys + * and ports might be GE or only FE + */ + if (is63xx(dev)) + return -ENOTSUPP; + + if (port == sw_dev->cpu_port) + return -EINVAL; + + if (!(BIT(port) & dev->enabled_ports)) + return -EINVAL; + + if (link->speed == SWITCH_PORT_SPEED_1000 && + (is5325(dev) || is5365(dev))) + return -EINVAL; + + if (link->speed == SWITCH_PORT_SPEED_1000 && !link->duplex) + return -EINVAL; + + return switch_generic_set_link(sw_dev, port, link); +} + +static int b53_phy_read16(struct switch_dev *dev, int addr, u8 reg, u16 *value) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (priv->ops->phy_read16) + return priv->ops->phy_read16(priv, addr, reg, value); + + return b53_read16(priv, B53_PORT_MII_PAGE(addr), reg, value); +} + +static int b53_phy_write16(struct switch_dev *dev, int addr, u8 reg, u16 value) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (priv->ops->phy_write16) + return priv->ops->phy_write16(priv, addr, reg, value); + + return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg, value); +} + +static int b53_global_reset_switch(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* reset vlans */ + priv->enable_vlan = 0; + priv->enable_jumbo = 0; + priv->allow_vid_4095 = 0; + + memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans); + memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports); + + return b53_switch_reset(priv); +} + +static int b53_global_apply_config(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* disable switching */ + b53_set_forwarding(priv, 0); + + b53_apply(priv); + + /* enable switching */ + b53_set_forwarding(priv, 1); + + return 0; +} + + +static int b53_global_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + u8 gc; + + b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); + mdelay(1); + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); + mdelay(1); + + return 0; +} + +static int b53_port_get_mib(struct switch_dev *sw_dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + const struct b53_mib_desc *mibs; + int port = val->port_vlan; + int len = 0; + + if (!(BIT(port) & dev->enabled_ports)) + return -1; + + if (is5365(dev)) { + if (port == 5) + port = 8; + + mibs = b53_mibs_65; + } else if (is63xx(dev)) { + mibs = b53_mibs_63xx; + } else { + mibs = b53_mibs; + } + + dev->buf[0] = 0; + + for (; mibs->size > 0; mibs++) { + u64 val; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs->offset, + &val32); + val = val32; + } + + len += snprintf(dev->buf + len, B53_BUF_SIZE - len, + "%-20s: %llu\n", mibs->name, val); + } + + val->len = len; + val->value.s = dev->buf; + + return 0; +} + +static int b53_port_get_stats(struct switch_dev *sw_dev, int port, + struct switch_port_stats *stats) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + const struct b53_mib_desc *mibs; + int txb_id, rxb_id; + u64 rxb, txb; + + if (!(BIT(port) & dev->enabled_ports)) + return -EINVAL; + + txb_id = B53XX_MIB_TXB_ID; + rxb_id = B53XX_MIB_RXB_ID; + + if (is5365(dev)) { + if (port == 5) + port = 8; + + mibs = b53_mibs_65; + } else if (is63xx(dev)) { + mibs = b53_mibs_63xx; + txb_id = B63XX_MIB_TXB_ID; + rxb_id = B63XX_MIB_RXB_ID; + } else { + mibs = b53_mibs; + } + + dev->buf[0] = 0; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &txb); + b53_read64(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &rxb); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &val32); + txb = val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &val32); + rxb = val32; + } + + stats->tx_bytes = txb; + stats->rx_bytes = rxb; + + return 0; +} + +static struct switch_attr b53_global_ops_25[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, +}; + +static struct switch_attr b53_global_ops_65[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, +}; + +static struct switch_attr b53_global_ops[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available Ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_jumbo", + .description = "Enable Jumbo Frames", + .set = b53_global_set_jumbo_enable, + .get = b53_global_get_jumbo_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "allow_vid_4095", + .description = "Allow VID 4095", + .set = b53_global_set_4095_enable, + .get = b53_global_get_4095_enable, + .max = 1, + }, +}; + +static struct switch_attr b53_port_ops[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .get = b53_port_get_mib, + }, +}; + +static struct switch_attr b53_no_ops[] = { +}; + +static const struct switch_dev_ops b53_switch_ops_25 = { + .attr_global = { + .attr = b53_global_ops_25, + .n_attr = ARRAY_SIZE(b53_global_ops_25), + }, + .attr_port = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +static const struct switch_dev_ops b53_switch_ops_65 = { + .attr_global = { + .attr = b53_global_ops_65, + .n_attr = ARRAY_SIZE(b53_global_ops_65), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +static const struct switch_dev_ops b53_switch_ops = { + .attr_global = { + .attr = b53_global_ops, + .n_attr = ARRAY_SIZE(b53_global_ops), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +struct b53_chip_data { + u32 chip_id; + const char *dev_name; + const char *alias; + u16 vlans; + u16 enabled_ports; + u8 cpu_port; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + const struct switch_dev_ops *sw_ops; +}; + +#define B53_VTA_REGS \ + { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } +#define B53_VTA_REGS_9798 \ + { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } +#define B53_VTA_REGS_63XX \ + { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } + +static const struct b53_chip_data b53_switch_chips[] = { + { + .chip_id = BCM5325_DEVICE_ID, + .dev_name = "BCM5325", + .alias = "bcm5325", + .vlans = 16, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_25, + }, + { + .chip_id = BCM5365_DEVICE_ID, + .dev_name = "BCM5365", + .alias = "bcm5365", + .vlans = 256, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_65, + }, + { + .chip_id = BCM5395_DEVICE_ID, + .dev_name = "BCM5395", + .alias = "bcm5395", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5397_DEVICE_ID, + .dev_name = "BCM5397", + .alias = "bcm5397", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5398_DEVICE_ID, + .dev_name = "BCM5398", + .alias = "bcm5398", + .vlans = 4096, + .enabled_ports = 0x7f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", + .alias = "bcm53115", + .vlans = 4096, + .enabled_ports = 0x1f, + .vta_regs = B53_VTA_REGS, + .cpu_port = B53_CPU_PORT, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53125_DEVICE_ID, + .dev_name = "BCM53125", + .alias = "bcm53125", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53128_DEVICE_ID, + .dev_name = "BCM53128", + .alias = "bcm53128", + .vlans = 4096, + .enabled_ports = 0x1ff, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM63XX_DEVICE_ID, + .dev_name = "BCM63xx", + .alias = "bcm63xx", + .vlans = 4096, + .enabled_ports = 0, /* pdata must provide them */ + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_63XX, + .duplex_reg = B53_DUPLEX_STAT_63XX, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53011_DEVICE_ID, + .dev_name = "BCM53011", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53012_DEVICE_ID, + .dev_name = "BCM53012", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53018_DEVICE_ID, + .dev_name = "BCM53018", + .alias = "bcm53018", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53019_DEVICE_ID, + .dev_name = "BCM53019", + .alias = "bcm53019", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, +}; + +static int b53_switch_init_of(struct b53_device *dev) +{ + struct device_node *dn, *pn; + const char *alias; + u32 port_num; + u16 ports = 0; + + dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); + if (!dn) + return -EINVAL; + + for_each_available_child_of_node(dn, pn) { + const char *label; + int len; + + if (of_property_read_u32(pn, "reg", &port_num)) + continue; + + if (port_num > B53_CPU_PORT) + continue; + + ports |= BIT(port_num); + + label = of_get_property(pn, "label", &len); + if (label && !strcmp(label, "cpu")) + dev->sw_dev.cpu_port = port_num; + } + + dev->enabled_ports = ports; + + if (!of_property_read_string(dev_of_node(dev->dev), "lede,alias", + &alias)) + dev->sw_dev.alias = devm_kstrdup(dev->dev, alias, GFP_KERNEL); + + return 0; +} + +static int b53_switch_init(struct b53_device *dev) +{ + struct switch_dev *sw_dev = &dev->sw_dev; + unsigned i; + int ret; + + for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { + const struct b53_chip_data *chip = &b53_switch_chips[i]; + + if (chip->chip_id == dev->chip_id) { + sw_dev->name = chip->dev_name; + if (!sw_dev->alias) + sw_dev->alias = chip->alias; + if (!dev->enabled_ports) + dev->enabled_ports = chip->enabled_ports; + dev->duplex_reg = chip->duplex_reg; + dev->vta_regs[0] = chip->vta_regs[0]; + dev->vta_regs[1] = chip->vta_regs[1]; + dev->vta_regs[2] = chip->vta_regs[2]; + dev->jumbo_pm_reg = chip->jumbo_pm_reg; + sw_dev->ops = chip->sw_ops; + sw_dev->cpu_port = chip->cpu_port; + sw_dev->vlans = chip->vlans; + break; + } + } + + if (!sw_dev->name) + return -EINVAL; + + /* check which BCM5325x version we have */ + if (is5325(dev)) { + u8 vc4; + + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + + /* check reserved bits */ + switch (vc4 & 3) { + case 1: + /* BCM5325E */ + break; + case 3: + /* BCM5325F - do not use port 4 */ + dev->enabled_ports &= ~BIT(4); + break; + default: +/* On the BCM47XX SoCs this is the supported internal switch.*/ +#ifndef CONFIG_BCM47XX + /* BCM5325M */ + return -EINVAL; +#else + break; +#endif + } + } else if (dev->chip_id == BCM53115_DEVICE_ID) { + u64 strap_value; + + b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); + /* use second IMP port if GMII is enabled */ + if (strap_value & SV_GMII_CTRL_115) + sw_dev->cpu_port = 5; + } + + if (dev_of_node(dev->dev)) { + ret = b53_switch_init_of(dev); + if (ret) + return ret; + } + + dev->enabled_ports |= BIT(sw_dev->cpu_port); + sw_dev->ports = fls(dev->enabled_ports); + + dev->ports = devm_kzalloc(dev->dev, + sizeof(struct b53_port) * sw_dev->ports, + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + + dev->vlans = devm_kzalloc(dev->dev, + sizeof(struct b53_vlan) * sw_dev->vlans, + GFP_KERNEL); + if (!dev->vlans) + return -ENOMEM; + + dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + + dev->reset_gpio = b53_switch_get_reset_gpio(dev); + if (dev->reset_gpio >= 0) { + ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, + GPIOF_OUT_INIT_HIGH, "robo_reset"); + if (ret) + return ret; + } + + return b53_switch_reset(dev); +} + +struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv) +{ + struct b53_device *dev; + + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev = base; + dev->ops = ops; + dev->priv = priv; + mutex_init(&dev->reg_mutex); + + return dev; +} +EXPORT_SYMBOL(b53_swconfig_switch_alloc); + +int b53_swconfig_switch_detect(struct b53_device *dev) +{ + u32 id32; + u16 tmp; + u8 id8; + int ret; + + ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); + if (ret) + return ret; + + switch (id8) { + case 0: + /* + * BCM5325 and BCM5365 do not have this register so reads + * return 0. But the read operation did succeed, so assume + * this is one of them. + * + * Next check if we can write to the 5325's VTA register; for + * 5365 it is read only. + */ + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); + + if (tmp == 0xf) + dev->chip_id = BCM5325_DEVICE_ID; + else + dev->chip_id = BCM5365_DEVICE_ID; + break; + case BCM5395_DEVICE_ID: + case BCM5397_DEVICE_ID: + case BCM5398_DEVICE_ID: + dev->chip_id = id8; + break; + default: + ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); + if (ret) + return ret; + + switch (id32) { + case BCM53115_DEVICE_ID: + case BCM53125_DEVICE_ID: + case BCM53128_DEVICE_ID: + case BCM53010_DEVICE_ID: + case BCM53011_DEVICE_ID: + case BCM53012_DEVICE_ID: + case BCM53018_DEVICE_ID: + case BCM53019_DEVICE_ID: + dev->chip_id = id32; + break; + default: + pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", + id8, id32); + return -ENODEV; + } + } + + if (dev->chip_id == BCM5325_DEVICE_ID) + return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, + &dev->core_rev); + else + return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, + &dev->core_rev); +} +EXPORT_SYMBOL(b53_swconfig_switch_detect); + +int b53_swconfig_switch_register(struct b53_device *dev) +{ + int ret; + + if (dev->pdata) { + dev->chip_id = dev->pdata->chip_id; + dev->enabled_ports = dev->pdata->enabled_ports; + dev->sw_dev.alias = dev->pdata->alias; + } + + if (!dev->chip_id && b53_swconfig_switch_detect(dev)) + return -EINVAL; + + ret = b53_switch_init(dev); + if (ret) + return ret; + + pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev); + + return register_switch(&dev->sw_dev, NULL); +} +EXPORT_SYMBOL(b53_swconfig_switch_register); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 switch library"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/b53/b53_mdio.c b/drivers/net/phy/b53/b53_mdio.c new file mode 100644 index 000000000000..c85df1f30558 --- /dev/null +++ b/drivers/net/phy/b53/b53_mdio.c @@ -0,0 +1,436 @@ +/* + * B53 register access through MII registers + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "b53_priv.h" + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +/* MII registers */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +#define REG_MII_PAGE_ENABLE BIT(0) +#define REG_MII_ADDR_WRITE BIT(0) +#define REG_MII_ADDR_READ BIT(1) + +static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) +{ + int i; + u16 v; + int ret; + struct mii_bus *bus = dev->priv; + + if (dev->current_page != page) { + /* set page number */ + v = (page << 8) | REG_MII_PAGE_ENABLE; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v); + if (ret) + return ret; + dev->current_page = page; + } + + /* set register address */ + v = (reg << 8) | op; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v); + if (ret) + return ret; + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR); + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff; + + return 0; +} + +static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + + return 0; +} + +static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + *val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16; + + return 0; +} + +static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 2; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u32 temp = value; + + for (i = 0; i < 2; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 3; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 4; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg, + u16 *value) +{ + struct mii_bus *bus = dev->priv; + + *value = mdiobus_read(bus, addr, reg); + + return 0; +} + +static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + + return mdiobus_write(bus, addr, reg, value); +} + +static struct b53_io_ops b53_mdio_ops = { + .read8 = b53_mdio_read8, + .read16 = b53_mdio_read16, + .read32 = b53_mdio_read32, + .read48 = b53_mdio_read48, + .read64 = b53_mdio_read64, + .write8 = b53_mdio_write8, + .write16 = b53_mdio_write16, + .write32 = b53_mdio_write32, + .write48 = b53_mdio_write48, + .write64 = b53_mdio_write64, + .phy_read16 = b53_mdio_phy_read16, + .phy_write16 = b53_mdio_phy_write16, +}; + +static int b53_phy_probe(struct phy_device *phydev) +{ + struct b53_device *dev; + int ret; + + /* allow the generic phy driver to take over */ + if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0) + return -ENODEV; + + dev = b53_swconfig_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus); + if (!dev) + return -ENOMEM; + + dev->current_page = 0xff; + dev->priv = phydev->mdio.bus; + dev->ops = &b53_mdio_ops; + dev->pdata = NULL; + mutex_init(&dev->reg_mutex); + + ret = b53_swconfig_switch_detect(dev); + if (ret) + return ret; + + linkmode_zero(phydev->supported); + if (is5325(dev) || is5365(dev)) + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported); + else + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); + + linkmode_copy(phydev->advertising, phydev->supported); + + ret = b53_swconfig_switch_register(dev); + if (ret) { + dev_err(dev->dev, "failed to register switch: %i\n", ret); + return ret; + } + + phydev->priv = dev; + + return 0; +} + +static int b53_phy_config_init(struct phy_device *phydev) +{ + struct b53_device *dev = phydev->priv; + + /* we don't use page 0xff, so force a page set */ + dev->current_page = 0xff; + /* force the ethX as alias */ + dev->sw_dev.alias = phydev->attached_dev->name; + + return 0; +} + +static void b53_phy_remove(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (!priv) + return; + + b53_switch_remove(priv); + + phydev->priv = NULL; +} + +static int b53_phy_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int b53_phy_read_status(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (is5325(priv) || is5365(priv)) + phydev->speed = 100; + else + phydev->speed = 1000; + + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + phydev->state = PHY_RUNNING; + + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +/* BCM5325, BCM539x */ +static struct phy_driver b53_phy_driver_id1 = { + .phy_id = 0x0143bc00, + .name = "Broadcom B53 (1)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, +}; + +/* BCM53125, BCM53128 */ +static struct phy_driver b53_phy_driver_id2 = { + .phy_id = 0x03625c00, + .name = "Broadcom B53 (2)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, +}; + +/* BCM5365 */ +static struct phy_driver b53_phy_driver_id3 = { + .phy_id = 0x00406300, + .name = "Broadcom B53 (3)", + .phy_id_mask = 0x1fffff00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, +}; + +int __init b53_phy_driver_register(void) +{ + int ret; + + ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE); + if (ret) + return ret; + + ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE); + if (ret) + goto err1; + + ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE); + if (!ret) + return 0; + + phy_driver_unregister(&b53_phy_driver_id2); +err1: + phy_driver_unregister(&b53_phy_driver_id1); + return ret; +} + +void __exit b53_phy_driver_unregister(void) +{ + phy_driver_unregister(&b53_phy_driver_id3); + phy_driver_unregister(&b53_phy_driver_id2); + phy_driver_unregister(&b53_phy_driver_id1); +} + +module_init(b53_phy_driver_register); +module_exit(b53_phy_driver_unregister); + +MODULE_DESCRIPTION("B53 MDIO access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/b53/b53_mmap.c b/drivers/net/phy/b53/b53_mmap.c new file mode 100644 index 000000000000..62dfe1c24282 --- /dev/null +++ b/drivers/net/phy/b53/b53_mmap.c @@ -0,0 +1,239 @@ +/* + * B53 register access through memory mapped registers + * + * Copyright (C) 2012-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + + *val = readb(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readw_be(regs + (page << 8) + reg); + else + *val = readw(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readl_be(regs + (page << 8) + reg); + else + *val = readl(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u16 lo; + u32 hi; + + b53_mmap_read16(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 2, &hi); + + *val = ((u64)hi << 16) | lo; + } else { + u32 lo; + u16 hi; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read16(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + } + + return 0; +} + +static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u32 hi, lo; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + + return 0; +} + +static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + + writeb(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writew_be(value, regs + (page << 8) + reg); + else + writew(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writel_be(value, regs + (page << 8) + reg); + else + writel(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u32 hi = (u32)(value >> 16); + u16 lo = (u16)value; + + b53_mmap_write16(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 2, hi); + } else { + u16 hi = (u16)(value >> 32); + u32 lo = (u32)value; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write16(dev, page, reg + 4, hi); + } + + return 0; +} + +static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u32 hi, lo; + + hi = (u32)(value >> 32); + lo = (u32)value; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 4, hi); + + return 0; +} + +static struct b53_io_ops b53_mmap_ops = { + .read8 = b53_mmap_read8, + .read16 = b53_mmap_read16, + .read32 = b53_mmap_read32, + .read48 = b53_mmap_read48, + .read64 = b53_mmap_read64, + .write8 = b53_mmap_write8, + .write16 = b53_mmap_write16, + .write32 = b53_mmap_write32, + .write48 = b53_mmap_write48, + .write64 = b53_mmap_write64, +}; + +static int b53_mmap_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_swconfig_switch_register(dev); +} + +static void b53_mmap_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); +} + +static struct platform_driver b53_mmap_driver = { + .probe = b53_mmap_probe, + .remove_new = b53_mmap_remove, + .driver = { + .name = "b53-switch", + }, +}; + +module_platform_driver(b53_mmap_driver); +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 MMAP access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/b53/b53_phy_fixup.c b/drivers/net/phy/b53/b53_phy_fixup.c new file mode 100644 index 000000000000..a19eccefd14c --- /dev/null +++ b/drivers/net/phy/b53/b53_phy_fixup.c @@ -0,0 +1,55 @@ +/* + * B53 PHY Fixup call + * + * Copyright (C) 2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +#define B53_BRCM_OUI_1 0x0143bc00 +#define B53_BRCM_OUI_2 0x03625c00 +#define B53_BRCM_OUI_3 0x00406300 + +static int b53_phy_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u32 phy_id; + + if (dev->mdio.addr != B53_PSEUDO_PHY) + return 0; + + /* read the first port's id */ + phy_id = mdiobus_read(bus, 0, 2) << 16; + phy_id |= mdiobus_read(bus, 0, 3); + + if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 || + (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 || + (phy_id & 0xffffff00) == B53_BRCM_OUI_3) { + dev->phy_id = phy_id; + } + + return 0; +} + +int __init b53_phy_fixup_register(void) +{ + return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup); +} + +subsys_initcall(b53_phy_fixup_register); diff --git a/drivers/net/phy/b53/b53_priv.h b/drivers/net/phy/b53/b53_priv.h new file mode 100644 index 000000000000..e455c755bf22 --- /dev/null +++ b/drivers/net/phy/b53/b53_priv.h @@ -0,0 +1,336 @@ +/* + * B53 common definitions + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_PRIV_H +#define __B53_PRIV_H + +#include +#include +#include + +struct b53_device; + +struct b53_io_ops { + int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); + int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); + int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); + int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); + int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); + int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); + int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value); + int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value); +}; + +enum { + BCM5325_DEVICE_ID = 0x25, + BCM5365_DEVICE_ID = 0x65, + BCM5395_DEVICE_ID = 0x95, + BCM5397_DEVICE_ID = 0x97, + BCM5398_DEVICE_ID = 0x98, + BCM53115_DEVICE_ID = 0x53115, + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, + BCM63XX_DEVICE_ID = 0x6300, + BCM53010_DEVICE_ID = 0x53010, + BCM53011_DEVICE_ID = 0x53011, + BCM53012_DEVICE_ID = 0x53012, + BCM53018_DEVICE_ID = 0x53018, + BCM53019_DEVICE_ID = 0x53019, +}; + +#define B53_N_PORTS 9 +#define B53_N_PORTS_25 6 + +struct b53_vlan { + unsigned int members:B53_N_PORTS; + unsigned int untag:B53_N_PORTS; +}; + +struct b53_port { + unsigned int pvid:12; +}; + +struct b53_device { + struct switch_dev sw_dev; + struct b53_platform_data *pdata; + + struct mutex reg_mutex; + const struct b53_io_ops *ops; + + /* chip specific data */ + u32 chip_id; + u8 core_rev; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + int reset_gpio; + + /* used ports mask */ + u16 enabled_ports; + + /* connect specific data */ + u8 current_page; + struct device *dev; + void *priv; + + /* run time configuration */ + unsigned enable_vlan:1; + unsigned enable_jumbo:1; + unsigned allow_vid_4095:1; + + struct b53_port *ports; + struct b53_vlan *vlans; + + char *buf; +}; + +#define b53_for_each_port(dev, i) \ + for (i = 0; i < B53_N_PORTS; i++) \ + if (dev->enabled_ports & BIT(i)) + + + +static inline int is5325(struct b53_device *dev) +{ + return dev->chip_id == BCM5325_DEVICE_ID; +} + +static inline int is5365(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + return dev->chip_id == BCM5365_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5397_98(struct b53_device *dev) +{ + return dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is539x(struct b53_device *dev) +{ + return dev->chip_id == BCM5395_DEVICE_ID || + dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is531x5(struct b53_device *dev) +{ + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || + dev->chip_id == BCM53128_DEVICE_ID; +} + +static inline int is63xx(struct b53_device *dev) +{ +#ifdef CONFIG_BCM63XX + return dev->chip_id == BCM63XX_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5301x(struct b53_device *dev) +{ + return dev->chip_id == BCM53010_DEVICE_ID || + dev->chip_id == BCM53011_DEVICE_ID || + dev->chip_id == BCM53012_DEVICE_ID || + dev->chip_id == BCM53018_DEVICE_ID || + dev->chip_id == BCM53019_DEVICE_ID; +} + +#define B53_CPU_PORT_25 5 +#define B53_CPU_PORT 8 + +static inline int is_cpu_port(struct b53_device *dev, int port) +{ + return dev->sw_dev.cpu_port == port; +} + +static inline int is_imp_port(struct b53_device *dev, int port) +{ + if (is5325(dev) || is5365(dev)) + return port == B53_CPU_PORT_25; + else + return port == B53_CPU_PORT; +} + +static inline struct b53_device *sw_to_b53(struct switch_dev *sw) +{ + return container_of(sw, struct b53_device, sw_dev); +} + +struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv); + +int b53_swconfig_switch_detect(struct b53_device *dev); + +int b53_swconfig_switch_register(struct b53_device *dev); + +static inline void b53_switch_remove(struct b53_device *dev) +{ + unregister_switch(&dev->sw_dev); +} + +static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read48(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read64(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write48(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write64(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +#ifdef CONFIG_BCM47XX +#include +#endif + +#include +#include + +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + return 8; + default: + break; + } +#endif + + return bcm47xx_nvram_gpio_pin("robo_reset"); +} + +#endif diff --git a/drivers/net/phy/b53/b53_regs.h b/drivers/net/phy/b53/b53_regs.h new file mode 100644 index 000000000000..f0bf6744a75c --- /dev/null +++ b/drivers/net/phy/b53/b53_regs.h @@ -0,0 +1,348 @@ +/* + * B53 register definitions + * + * Copyright (C) 2004 Broadcom Corporation + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_REGS_H +#define __B53_REGS_H + +/* Management Port (SMP) Page offsets */ +#define B53_CTRL_PAGE 0x00 /* Control */ +#define B53_STAT_PAGE 0x01 /* Status */ +#define B53_MGMT_PAGE 0x02 /* Management Mode */ +#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ +#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ +#define B53_ARLIO_PAGE 0x05 /* ARL Access */ +#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ +#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ + +/* PHY Registers */ +#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ +#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ +#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ + +/* MIB registers */ +#define B53_MIB_PAGE(i) (0x20 + (i)) + +/* Quality of Service (QoS) Registers */ +#define B53_QOS_PAGE 0x30 + +/* Port VLAN Page */ +#define B53_PVLAN_PAGE 0x31 + +/* VLAN Registers */ +#define B53_VLAN_PAGE 0x34 + +/* Jumbo Frame Registers */ +#define B53_JUMBO_PAGE 0x40 + +/* CFP Configuration Registers Page */ +#define B53_CFP_PAGE 0xa1 + +/************************************************************************* + * Control Page registers + *************************************************************************/ + +/* Port Control Register (8 bit) */ +#define B53_PORT_CTRL(i) (0x00 + (i)) +#define PORT_CTRL_RX_DISABLE BIT(0) +#define PORT_CTRL_TX_DISABLE BIT(1) +#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ +#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ +#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ +#define PORT_CTRL_STP_STATE_S 5 +#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) + +/* SMP Control Register (8 bit) */ +#define B53_SMP_CTRL 0x0a + +/* Switch Mode Control Register (8 bit) */ +#define B53_SWITCH_MODE 0x0b +#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ +#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ + +/* IMP Port state override register (8 bit) */ +#define B53_PORT_OVERRIDE_CTRL 0x0e +#define PORT_OVERRIDE_LINK BIT(0) +#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define PORT_OVERRIDE_SPEED_S 2 +#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ +#define PORT_OVERRIDE_RX_FLOW BIT(4) +#define PORT_OVERRIDE_TX_FLOW BIT(5) +#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ +#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ + +/* Power-down mode control */ +#define B53_PD_MODE_CTRL_25 0x0f + +/* IP Multicast control (8 bit) */ +#define B53_IP_MULTICAST_CTRL 0x21 +#define B53_IPMC_FWD_EN BIT(1) +#define B53_UC_FWD_EN BIT(6) +#define B53_MC_FWD_EN BIT(7) + +/* (16 bit) */ +#define B53_UC_FLOOD_MASK 0x32 +#define B53_MC_FLOOD_MASK 0x34 +#define B53_IPMC_FLOOD_MASK 0x36 + +/* + * Override Ports 0-7 State on devices with xMII interfaces (8 bit) + * + * For port 8 still use B53_PORT_OVERRIDE_CTRL + * Please note that not all ports are available on every hardware, e.g. BCM5301X + * don't include overriding port 6, BCM63xx also have some limitations. + */ +#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) +#define GMII_PO_LINK BIT(0) +#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define GMII_PO_SPEED_S 2 +#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) +#define GMII_PO_RX_FLOW BIT(4) +#define GMII_PO_TX_FLOW BIT(5) +#define GMII_PO_EN BIT(6) /* Use the register contents */ +#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ + +/* Software reset register (8 bit) */ +#define B53_SOFTRESET 0x79 + +/* Fast Aging Control register (8 bit) */ +#define B53_FAST_AGE_CTRL 0x88 +#define FAST_AGE_STATIC BIT(0) +#define FAST_AGE_DYNAMIC BIT(1) +#define FAST_AGE_PORT BIT(2) +#define FAST_AGE_VLAN BIT(3) +#define FAST_AGE_STP BIT(4) +#define FAST_AGE_MC BIT(5) +#define FAST_AGE_DONE BIT(7) + +/************************************************************************* + * Status Page registers + *************************************************************************/ + +/* Link Status Summary Register (16bit) */ +#define B53_LINK_STAT 0x00 + +/* Link Status Change Register (16 bit) */ +#define B53_LINK_STAT_CHANGE 0x02 + +/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ +#define B53_SPEED_STAT 0x04 +#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) +#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) +#define SPEED_STAT_10M 0 +#define SPEED_STAT_100M 1 +#define SPEED_STAT_1000M 2 + +/* Duplex Status Summary (16 bit) */ +#define B53_DUPLEX_STAT_FE 0x06 +#define B53_DUPLEX_STAT_GE 0x08 +#define B53_DUPLEX_STAT_63XX 0x0c + +/* Revision ID register for BCM5325 */ +#define B53_REV_ID_25 0x50 + +/* Strap Value (48 bit) */ +#define B53_STRAP_VALUE 0x70 +#define SV_GMII_CTRL_115 BIT(27) + +/************************************************************************* + * Management Mode Page Registers + *************************************************************************/ + +/* Global Management Config Register (8 bit) */ +#define B53_GLOBAL_CONFIG 0x00 +#define GC_RESET_MIB 0x01 +#define GC_RX_BPDU_EN 0x02 +#define GC_MIB_AC_HDR_EN 0x10 +#define GC_MIB_AC_EN 0x20 +#define GC_FRM_MGMT_PORT_M 0xC0 +#define GC_FRM_MGMT_PORT_04 0x00 +#define GC_FRM_MGMT_PORT_MII 0x80 + +/* Broadcom Header control register (8 bit) */ +#define B53_BRCM_HDR 0x03 +#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */ +#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ + +/* Device ID register (8 or 32 bit) */ +#define B53_DEVICE_ID 0x30 + +/* Revision ID register (8 bit) */ +#define B53_REV_ID 0x40 + +/************************************************************************* + * ARL Access Page Registers + *************************************************************************/ + +/* VLAN Table Access Register (8 bit) */ +#define B53_VT_ACCESS 0x80 +#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ +#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ +#define VTA_CMD_WRITE 0 +#define VTA_CMD_READ 1 +#define VTA_CMD_CLEAR 2 +#define VTA_START_CMD BIT(7) + +/* VLAN Table Index Register (16 bit) */ +#define B53_VT_INDEX 0x81 +#define B53_VT_INDEX_9798 0x61 +#define B53_VT_INDEX_63XX 0x62 + +/* VLAN Table Entry Register (32 bit) */ +#define B53_VT_ENTRY 0x83 +#define B53_VT_ENTRY_9798 0x63 +#define B53_VT_ENTRY_63XX 0x64 +#define VTE_MEMBERS 0x1ff +#define VTE_UNTAG_S 9 +#define VTE_UNTAG (0x1ff << 9) + +/************************************************************************* + * Port VLAN Registers + *************************************************************************/ + +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ +#define B53_PVLAN_PORT_MASK(i) ((i) * 2) + +/************************************************************************* + * 802.1Q Page Registers + *************************************************************************/ + +/* Global QoS Control (8 bit) */ +#define B53_QOS_GLOBAL_CTL 0x00 + +/* Enable 802.1Q for individual Ports (16 bit) */ +#define B53_802_1P_EN 0x04 + +/************************************************************************* + * VLAN Page Registers + *************************************************************************/ + +/* VLAN Control 0 (8 bit) */ +#define B53_VLAN_CTRL0 0x00 +#define VC0_8021PF_CTRL_MASK 0x3 +#define VC0_8021PF_CTRL_NONE 0x0 +#define VC0_8021PF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021PF_CTRL_CHANGE_VID 0x2 +#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 +#define VC0_8021QF_CTRL_MASK 0xc +#define VC0_8021QF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021QF_CTRL_CHANGE_VID 0x2 +#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 +#define VC0_RESERVED_1 BIT(1) +#define VC0_DROP_VID_MISS BIT(4) +#define VC0_VID_HASH_VID BIT(5) +#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ +#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ + +/* VLAN Control 1 (8 bit) */ +#define B53_VLAN_CTRL1 0x01 +#define VC1_RX_MCST_TAG_EN BIT(1) +#define VC1_RX_MCST_FWD_EN BIT(2) +#define VC1_RX_MCST_UNTAG_EN BIT(3) + +/* VLAN Control 2 (8 bit) */ +#define B53_VLAN_CTRL2 0x02 + +/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ +#define B53_VLAN_CTRL3 0x03 +#define B53_VLAN_CTRL3_63XX 0x04 +#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ +#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ + +/* VLAN Control 4 (8 bit) */ +#define B53_VLAN_CTRL4 0x05 +#define B53_VLAN_CTRL4_25 0x04 +#define B53_VLAN_CTRL4_63XX 0x06 +#define VC4_ING_VID_CHECK_S 6 +#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) +#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ +#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ +#define VC4_NO_ING_VID_CHK 2 /* do not check */ +#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ + +/* VLAN Control 5 (8 bit) */ +#define B53_VLAN_CTRL5 0x06 +#define B53_VLAN_CTRL5_25 0x05 +#define B53_VLAN_CTRL5_63XX 0x07 +#define VC5_VID_FFF_EN BIT(2) +#define VC5_DROP_VTABLE_MISS BIT(3) + +/* VLAN Control 6 (8 bit) */ +#define B53_VLAN_CTRL6 0x07 +#define B53_VLAN_CTRL6_63XX 0x08 + +/* VLAN Table Access Register (16 bit) */ +#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ +#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ +#define VTA_VID_LOW_MASK_25 0xf +#define VTA_VID_LOW_MASK_65 0xff +#define VTA_VID_HIGH_S_25 4 +#define VTA_VID_HIGH_S_65 8 +#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) +#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) +#define VTA_RW_STATE BIT(12) +#define VTA_RW_STATE_RD 0 +#define VTA_RW_STATE_WR BIT(12) +#define VTA_RW_OP_EN BIT(13) + +/* VLAN Read/Write Registers for (16/32 bit) */ +#define B53_VLAN_WRITE_25 0x08 +#define B53_VLAN_WRITE_65 0x0a +#define B53_VLAN_READ 0x0c +#define VA_MEMBER_MASK 0x3f +#define VA_UNTAG_S_25 6 +#define VA_UNTAG_MASK_25 0x3f +#define VA_UNTAG_S_65 7 +#define VA_UNTAG_MASK_65 0x1f +#define VA_VID_HIGH_S 12 +#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) +#define VA_VALID_25 BIT(20) +#define VA_VALID_25_R4 BIT(24) +#define VA_VALID_65 BIT(14) + +/* VLAN Port Default Tag (16 bit) */ +#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) + +/************************************************************************* + * Jumbo Frame Page Registers + *************************************************************************/ + +/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ +#define B53_JUMBO_PORT_MASK 0x01 +#define B53_JUMBO_PORT_MASK_63XX 0x04 +#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ + +/* Good Frame Max Size without 802.1Q TAG (16 bit) */ +#define B53_JUMBO_MAX_SIZE 0x05 +#define B53_JUMBO_MAX_SIZE_63XX 0x08 +#define JMS_MIN_SIZE 1518 +#define JMS_MAX_SIZE 9724 + +/************************************************************************* + * CFP Configuration Page Registers + *************************************************************************/ + +/* CFP Control Register with ports map (8 bit) */ +#define B53_CFP_CTRL 0x00 + +#endif /* !__B53_REGS_H */ diff --git a/drivers/net/phy/b53/b53_spi.c b/drivers/net/phy/b53/b53_spi.c new file mode 100644 index 000000000000..400454df18c1 --- /dev/null +++ b/drivers/net/phy/b53/b53_spi.c @@ -0,0 +1,344 @@ +/* + * B53 register access through SPI + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +#define B53_SPI_DATA 0xf0 + +#define B53_SPI_STATUS 0xfe +#define B53_SPI_CMD_SPIF BIT(7) +#define B53_SPI_CMD_RACK BIT(5) + +#define B53_SPI_CMD_READ 0x00 +#define B53_SPI_CMD_WRITE 0x01 +#define B53_SPI_CMD_NORMAL 0x60 +#define B53_SPI_CMD_FAST 0x10 + +#define B53_SPI_PAGE_SELECT 0xff + +static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, + unsigned len) +{ + u8 txbuf[2]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; + txbuf[1] = reg; + + return spi_write_then_read(spi, txbuf, 2, val, len); +} + +static inline int b53_spi_clear_status(struct spi_device *spi) +{ + unsigned int i; + u8 rxbuf; + int ret; + + for (i = 0; i < 10; i++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (!(rxbuf & B53_SPI_CMD_SPIF)) + break; + + mdelay(1); + } + + if (i == 10) + return -EIO; + + return 0; +} + +static inline int b53_spi_set_page(struct spi_device *spi, u8 page) +{ + u8 txbuf[3]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = B53_SPI_PAGE_SELECT; + txbuf[2] = page; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) +{ + int ret = b53_spi_clear_status(spi); + + if (ret) + return ret; + + return b53_spi_set_page(spi, page); +} + +static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) +{ + u8 rxbuf; + int retry_count; + int ret; + + ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); + if (ret) + return ret; + + for (retry_count = 0; retry_count < 10; retry_count++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (rxbuf & B53_SPI_CMD_RACK) + break; + + mdelay(1); + } + + if (retry_count == 10) + return -EIO; + + return 0; +} + +static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, + unsigned len) +{ + struct spi_device *spi = dev->priv; + int ret; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + ret = b53_spi_prepare_reg_read(spi, reg); + if (ret) + return ret; + + return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); +} + +static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + return b53_spi_read(dev, page, reg, val, 1); +} + +static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); + + if (!ret) + *val = le16_to_cpu(*val); + + return ret; +} + +static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); + + if (!ret) + *val = le32_to_cpu(*val); + + return ret; +} + +static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + *val = 0; + ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); + + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[3]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + txbuf[2] = value; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[4]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le16(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[6]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le32(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf) - 2); +} + +static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static struct b53_io_ops b53_spi_ops = { + .read8 = b53_spi_read8, + .read16 = b53_spi_read16, + .read32 = b53_spi_read32, + .read48 = b53_spi_read48, + .read64 = b53_spi_read64, + .write8 = b53_spi_write8, + .write16 = b53_spi_write16, + .write32 = b53_spi_write32, + .write48 = b53_spi_write48, + .write64 = b53_spi_write64, +}; + +static int b53_spi_probe(struct spi_device *spi) +{ + struct b53_device *dev; + int ret; + + dev = b53_swconfig_switch_alloc(&spi->dev, &b53_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = b53_swconfig_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int b53_spi_remove(struct spi_device *spi) +{ + struct b53_device *dev = spi_get_drvdata(spi); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static const struct of_device_id b53_of_match[] = { + { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, + { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5395" }, + { .compatible = "brcm,bcm5397" }, + { .compatible = "brcm,bcm5398" }, + { /* sentinel */ }, +}; + +static struct spi_driver b53_spi_driver = { + .driver = { + .name = "b53-switch", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = b53_of_match, + }, + .probe = b53_spi_probe, + .remove = b53_spi_remove, +}; + +module_spi_driver(b53_spi_driver); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 SPI access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/b53/b53_srab.c b/drivers/net/phy/b53/b53_srab.c new file mode 100644 index 000000000000..f8cb99383ff1 --- /dev/null +++ b/drivers/net/phy/b53/b53_srab.c @@ -0,0 +1,376 @@ +/* + * B53 register access through Switch Register Access Bridge Registers + * + * Copyright (C) 2013 Hauke Mehrtens + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +/* command and status register of the SRAB */ +#define B53_SRAB_CMDSTAT 0x2c +#define B53_SRAB_CMDSTAT_RST BIT(2) +#define B53_SRAB_CMDSTAT_WRITE BIT(1) +#define B53_SRAB_CMDSTAT_GORDYN BIT(0) +#define B53_SRAB_CMDSTAT_PAGE 24 +#define B53_SRAB_CMDSTAT_REG 16 + +/* high order word of write data to switch registe */ +#define B53_SRAB_WD_H 0x30 + +/* low order word of write data to switch registe */ +#define B53_SRAB_WD_L 0x34 + +/* high order word of read data from switch register */ +#define B53_SRAB_RD_H 0x38 + +/* low order word of read data from switch register */ +#define B53_SRAB_RD_L 0x3c + +/* command and status register of the SRAB */ +#define B53_SRAB_CTRLS 0x40 +#define B53_SRAB_CTRLS_RCAREQ BIT(3) +#define B53_SRAB_CTRLS_RCAGNT BIT(4) +#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) + +/* the register captures interrupt pulses from the switch */ +#define B53_SRAB_INTR 0x44 + +static int b53_srab_request_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + int i; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls |= B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); + + for (i = 0; i < 20; i++) { + ctrls = readl(regs + B53_SRAB_CTRLS); + if (ctrls & B53_SRAB_CTRLS_RCAGNT) + break; + usleep_range(10, 100); + } + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static void b53_srab_release_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls &= ~B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); +} + +static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) +{ + int i; + u32 cmdstat; + u8 __iomem *regs = dev->priv; + + /* set register address */ + cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | + (reg << B53_SRAB_CMDSTAT_REG) | + B53_SRAB_CMDSTAT_GORDYN | + op; + writel(cmdstat, regs + B53_SRAB_CMDSTAT); + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + cmdstat = readl(regs + B53_SRAB_CMDSTAT); + if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xffff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u16)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u32)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static struct b53_io_ops b53_srab_ops = { + .read8 = b53_srab_read8, + .read16 = b53_srab_read16, + .read32 = b53_srab_read32, + .read48 = b53_srab_read48, + .read64 = b53_srab_read64, + .write8 = b53_srab_write8, + .write16 = b53_srab_write16, + .write32 = b53_srab_write32, + .write48 = b53_srab_write48, + .write64 = b53_srab_write64, +}; + +static int b53_srab_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_swconfig_switch_register(dev); +} + +static void b53_srab_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); +} + +static struct platform_driver b53_srab_driver = { + .probe = b53_srab_probe, + .remove_new = b53_srab_remove, + .driver = { + .name = "b53-srab-switch", + }, +}; + +module_platform_driver(b53_srab_driver); +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/phy/en8801sc.c b/drivers/net/phy/en8801sc.c new file mode 100644 index 000000000000..08774e3b8889 --- /dev/null +++ b/drivers/net/phy/en8801sc.c @@ -0,0 +1,1117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* FILE NAME: en8801sc.c + * PURPOSE: + * EN8801SC phy driver for Linux + * NOTES: + * + */ + +/* INCLUDE FILE DECLARATIONS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "en8801sc.h" + +MODULE_DESCRIPTION("Airoha EN8801S PHY drivers for MediaTek SoC"); +MODULE_AUTHOR("Airoha"); +MODULE_LICENSE("GPL"); + +#define airoha_mdio_lock(bus) mutex_lock(&((bus)->mdio_lock)) +#define airoha_mdio_unlock(bus) mutex_unlock(&((bus)->mdio_lock)) + +#define phydev_mdio_bus(_dev) (_dev->mdio.bus) +#define phydev_phy_addr(_dev) (_dev->mdio.addr) +#define phydev_dev(_dev) (&_dev->mdio.dev) +#define phydev_pbus_addr(dev) ((dev)->mdio.addr + 1) + +enum { + PHY_STATE_DONE = 0, + PHY_STATE_INIT = 1, + PHY_STATE_PROCESS = 2, + PHY_STATE_FAIL = 3, +}; + +struct en8801s_priv { + bool first_init; + u16 count; + u16 pro_version; +}; + +/* +The following led_cfg example is for reference only. +LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, +LED6 10/100M/LINK/ACT (GPIO9) <-> BASE_T_LED1, +LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, +*/ +/* User-defined.B */ +#define AIR_LED_SUPPORT +#ifdef AIR_LED_SUPPORT +static const struct AIR_BASE_T_LED_CFG_S led_cfg[4] = { +/* +* {LED Enable, GPIO, LED Polarity, LED ON, LED Blink} +*/ + /* BASE-T LED0 */ + {LED_ENABLE, 5, AIR_ACTIVE_LOW, + BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, + /* BASE-T LED1 */ + {LED_ENABLE, 9, AIR_ACTIVE_LOW, + BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, + /* BASE-T LED2 */ + {LED_ENABLE, 8, AIR_ACTIVE_LOW, + BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, + /* BASE-T LED3 */ + {LED_DISABLE, 1, AIR_ACTIVE_LOW, + BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG}, +}; +static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M; +#endif + +/* User-defined.E */ + +/************************************************************************ +* F U N C T I O N S +************************************************************************/ +static int en8801s_phase2_init(struct phy_device *phydev); + +static int __airoha_cl45_write(struct mii_bus *bus, int port, + u32 devad, u32 reg, u16 val) +{ + int ret = 0; + struct device *dev = &bus->dev; + + ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, + MMD_OP_MODE_DATA | devad); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, val); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + + return ret; +} + +static int __airoha_cl45_read(struct mii_bus *bus, int port, + u32 devad, u32 reg, u16 *read_data) +{ + int ret = 0; + struct device *dev = &bus->dev; + + ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, devad); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + ret = __mdiobus_write(bus, port, MII_MMD_ADDR_DATA_REG, reg); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + ret = __mdiobus_write(bus, port, MII_MMD_ACC_CTL_REG, + MMD_OP_MODE_DATA | devad); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return ret; + } + *read_data = __mdiobus_read(bus, port, MII_MMD_ADDR_DATA_REG); + + return ret; +} + +static int airoha_cl45_write(struct mii_bus *bus, int port, + u32 devad, u32 reg, u16 val) +{ + int ret = 0; + + airoha_mdio_lock(bus); + ret = __airoha_cl45_write(bus, port, devad, reg, val); + airoha_mdio_unlock(bus); + + return ret; +} + +static int airoha_cl45_read(struct mii_bus *bus, int port, + u32 devad, u32 reg, u16 *read_data) +{ + int ret = 0; + + airoha_mdio_lock(bus); + ret = __airoha_cl45_read(bus, port, devad, reg, read_data); + airoha_mdio_unlock(bus); + + return ret; +} + +static int __airoha_pbus_write(struct mii_bus *ebus, int pbus_id, + unsigned long pbus_address, unsigned long pbus_data) +{ + int ret = 0; + + ret = __mdiobus_write(ebus, pbus_id, 0x1F, + (unsigned int)(pbus_address >> 6)); + if (ret < 0) + return ret; + ret = __mdiobus_write(ebus, pbus_id, + (unsigned int)((pbus_address >> 2) & 0xf), + (unsigned int)(pbus_data & 0xFFFF)); + if (ret < 0) + return ret; + ret = __mdiobus_write(ebus, pbus_id, 0x10, + (unsigned int)(pbus_data >> 16)); + if (ret < 0) + return ret; + return ret; +} + +static unsigned long __airoha_pbus_read(struct mii_bus *ebus, int pbus_id, + unsigned long pbus_address) +{ + unsigned long pbus_data; + unsigned int pbus_data_low, pbus_data_high; + int ret = 0; + struct device *dev = &ebus->dev; + + ret = __mdiobus_write(ebus, pbus_id, 0x1F, + (unsigned int)(pbus_address >> 6)); + if (ret < 0) { + dev_err(dev, "%s fail. (ret=%d)\n", __func__, ret); + return INVALID_DATA; + } + pbus_data_low = __mdiobus_read(ebus, pbus_id, + (unsigned int)((pbus_address >> 2) & 0xf)); + pbus_data_high = __mdiobus_read(ebus, pbus_id, 0x10); + pbus_data = (pbus_data_high << 16) + pbus_data_low; + return pbus_data; +} + +static int airoha_pbus_write(struct mii_bus *ebus, int pbus_id, + unsigned long pbus_address, unsigned long pbus_data) +{ + int ret = 0; + + airoha_mdio_lock(ebus); + ret = __airoha_pbus_write(ebus, pbus_id, pbus_address, pbus_data); + airoha_mdio_unlock(ebus); + + return ret; +} + +static unsigned long airoha_pbus_read(struct mii_bus *ebus, int pbus_id, + unsigned long pbus_address) +{ + unsigned long pbus_data; + + airoha_mdio_lock(ebus); + pbus_data = __airoha_pbus_read(ebus, pbus_id, pbus_address); + airoha_mdio_unlock(ebus); + + return pbus_data; +} + +/* Airoha Token Ring Write function */ +static int airoha_tr_reg_write(struct phy_device *phydev, + unsigned long tr_address, unsigned long tr_data) +{ + int ret = 0; + int phy_addr = phydev_phy_addr(phydev); + struct mii_bus *ebus = phydev_mdio_bus(phydev); + + airoha_mdio_lock(ebus); + ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x52b5); /* page select */ + ret = __mdiobus_write(ebus, phy_addr, 0x11, + (unsigned int)(tr_data & 0xffff)); + ret = __mdiobus_write(ebus, phy_addr, 0x12, + (unsigned int)(tr_data >> 16)); + ret = __mdiobus_write(ebus, phy_addr, 0x10, + (unsigned int)(tr_address | TrReg_WR)); + ret = __mdiobus_write(ebus, phy_addr, 0x1F, 0x0); /* page resetore */ + airoha_mdio_unlock(ebus); + + return ret; +} + +#ifdef AIR_LED_SUPPORT +static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, + int polar, u16 on_evt, u16 blk_evt) +{ + int ret = 0; + int phy_addr = phydev_phy_addr(phydev); + struct mii_bus *mbus = phydev_mdio_bus(phydev); + + if (polar == AIR_ACTIVE_HIGH) + on_evt |= LED_ON_POL; + else + on_evt &= ~LED_ON_POL; + + ret = airoha_cl45_write(mbus, phy_addr, 0x1f, + LED_ON_CTRL(entity), on_evt | LED_ON_EN); + if (ret < 0) + return ret; + + ret = airoha_cl45_write(mbus, phy_addr, 0x1f, + LED_BLK_CTRL(entity), blk_evt); + if (ret < 0) + return ret; + + return 0; +} + +static int airoha_led_set_mode(struct phy_device *phydev, u8 mode) +{ + u16 cl45_data; + int err = 0; + int phy_addr = phydev_phy_addr(phydev); + struct mii_bus *mbus = phydev_mdio_bus(phydev); + + err = airoha_cl45_read(mbus, phy_addr, 0x1f, LED_BCR, &cl45_data); + if (err < 0) + return err; + + switch (mode) { + case AIR_LED_MODE_DISABLE: + cl45_data &= ~LED_BCR_EXT_CTRL; + cl45_data &= ~LED_BCR_MODE_MASK; + cl45_data |= LED_BCR_MODE_DISABLE; + break; + case AIR_LED_MODE_USER_DEFINE: + cl45_data |= LED_BCR_EXT_CTRL; + cl45_data |= LED_BCR_CLK_EN; + break; + default: + return -EINVAL; + } + + err = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BCR, cl45_data); + if (err < 0) + return err; + return 0; +} + +static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state) +{ + u16 cl45_data; + int err; + int phy_addr = phydev_phy_addr(phydev); + struct mii_bus *mbus = phydev_mdio_bus(phydev); + + err = airoha_cl45_read(mbus, phy_addr, 0x1f, + LED_ON_CTRL(entity), &cl45_data); + if (err < 0) + return err; + if (state == LED_ENABLE) + cl45_data |= LED_ON_EN; + else + cl45_data &= ~LED_ON_EN; + + err = airoha_cl45_write(mbus, phy_addr, 0x1f, + LED_ON_CTRL(entity), cl45_data); + if (err < 0) + return err; + return 0; +} + +static int en8801s_led_init(struct phy_device *phydev) +{ + + unsigned long led_gpio = 0, reg_value = 0; + int ret = 0, led_id; + struct mii_bus *mbus = phydev_mdio_bus(phydev); + int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878}; + u16 cl45_data = led_dur; + struct device *dev = phydev_dev(phydev); + int phy_addr = phydev_phy_addr(phydev); + int pbus_addr = phydev_pbus_addr(phydev); + + ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_BLK_DUR, cl45_data); + if (ret < 0) + return ret; + cl45_data >>= 1; + ret = airoha_cl45_write(mbus, phy_addr, 0x1f, LED_ON_DUR, cl45_data); + if (ret < 0) + return ret; + ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); + if (ret != 0) { + dev_err(dev, "LED fail to set mode, ret %d !\n", ret); + return ret; + } + for (led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) { + reg_value = 0; + ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en); + if (ret != 0) { + dev_err(dev, "LED fail to set state, ret %d !\n", ret); + return ret; + } + if (led_cfg[led_id].en == LED_ENABLE) { + if ((led_cfg[led_id].gpio < 0) + || led_cfg[led_id].gpio > 9) { + dev_err(dev, "GPIO%d is out of range!! GPIO number is 0~9.\n", + led_cfg[led_id].gpio); + return -EIO; + } + led_gpio |= BIT(led_cfg[led_id].gpio); + reg_value = airoha_pbus_read(mbus, pbus_addr, + gpio_led_rg[led_cfg[led_id].gpio / 4]); + LED_SET_GPIO_SEL(led_cfg[led_id].gpio, + led_id, reg_value); + dev_dbg(dev, "[Airoha] gpio%d, reg_value 0x%lx\n", + led_cfg[led_id].gpio, reg_value); + ret = airoha_pbus_write(mbus, pbus_addr, + gpio_led_rg[led_cfg[led_id].gpio / 4], + reg_value); + if (ret < 0) + return ret; + ret = airoha_led_set_usr_def(phydev, led_id, + led_cfg[led_id].pol, + led_cfg[led_id].on_cfg, + led_cfg[led_id].blk_cfg); + if (ret != 0) { + dev_err(dev, "LED fail to set usr def, ret %d !\n", + ret); + return ret; + } + } + } + reg_value = (airoha_pbus_read(mbus, pbus_addr, 0x1880) & ~led_gpio); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1880, reg_value); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x186c, led_gpio); + if (ret < 0) + return ret; + dev_info(dev, "LED initialize OK !\n"); + return 0; +} +#endif +static int en8801s_phy_process(struct phy_device *phydev) +{ + struct mii_bus *mbus = phydev_mdio_bus(phydev); + unsigned long reg_value = 0; + int ret = 0; + int pbus_addr = phydev_pbus_addr(phydev); + + reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); + reg_value |= BIT(0); + ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); + if (ret < 0) + return ret; + reg_value = airoha_pbus_read(mbus, pbus_addr, 0x19e0); + reg_value &= ~BIT(0); + ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, reg_value); + if (ret < 0) + return ret; + return ret; +} + +static int en8801s_phase1_init(struct phy_device *phydev) +{ + unsigned long pbus_data; + int pbus_addr = EN8801S_PBUS_DEFAULT_ADDR; + u16 reg_value; + int retry, ret = 0; + struct mii_bus *mbus = phydev_mdio_bus(phydev); + struct device *dev = phydev_dev(phydev); + struct en8801s_priv *priv = phydev->priv; + + priv->count = 1; + msleep(1000); + + retry = MAX_OUI_CHECK; + while (1) { + pbus_data = airoha_pbus_read(mbus, pbus_addr, + EN8801S_RG_ETHER_PHY_OUI); /* PHY OUI */ + if (pbus_data == EN8801S_PBUS_OUI) { + dev_info(dev, "PBUS addr 0x%x: Start initialized.\n", + pbus_addr); + break; + } + pbus_addr = phydev_pbus_addr(phydev); + if (0 == --retry) { + dev_err(dev, "Probe fail !\n"); + return 0; + } + } + + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_BUCK_CTL, 0x03); + if (ret < 0) + return ret; + pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_PROD_VER); + priv->pro_version = pbus_data & 0xf; + dev_info(dev, "EN8801S Procduct Version :E%d\n", priv->pro_version); + mdelay(10); + pbus_data = (airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL) + & 0xfffffffc) | BIT(2); + ret = airoha_pbus_write(mbus, pbus_addr, + EN8801S_RG_LTR_CTL, pbus_data); + if (ret < 0) + return ret; + mdelay(500); + pbus_data = (pbus_data & ~BIT(2)) | + EN8801S_RX_POLARITY_NORMAL | + EN8801S_TX_POLARITY_NORMAL; + ret = airoha_pbus_write(mbus, pbus_addr, + EN8801S_RG_LTR_CTL, pbus_data); + if (ret < 0) + return ret; + mdelay(500); + if (priv->pro_version == 4) { + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900); + dev_dbg(dev, "Before 0x1900 0x%lx\n", pbus_data); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1900, 0x101009f); + if (ret < 0) + return ret; + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1900); + dev_dbg(dev, "After 0x1900 0x%lx\n", pbus_data); + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8); + dev_dbg(dev, "Before 19a8 0x%lx\n", pbus_data); + ret = airoha_pbus_write(mbus, pbus_addr, + 0x19a8, pbus_data & ~BIT(16)); + if (ret < 0) + return ret; + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19a8); + dev_dbg(dev, "After 19a8 0x%lx\n", pbus_data); + } + pbus_data = airoha_pbus_read(mbus, pbus_addr, + EN8801S_RG_SMI_ADDR); /* SMI ADDR */ + pbus_data = (pbus_data & 0xffff0000) | + (unsigned long)(phydev_pbus_addr(phydev) << 8) | + (unsigned long)(phydev_phy_addr(phydev)); + dev_info(phydev_dev(phydev), "SMI_ADDR=%lx (renew)\n", pbus_data); + ret = airoha_pbus_write(mbus, pbus_addr, + EN8801S_RG_SMI_ADDR, pbus_data); + mdelay(10); + + retry = MAX_RETRY; + while (1) { + mdelay(10); + reg_value = phy_read(phydev, MII_PHYSID2); + if (reg_value == EN8801S_PHY_ID2) + break; /* wait GPHY ready */ + + retry--; + if (retry == 0) { + dev_err(dev, "Initialize fail !\n"); + return 0; + } + } + /* Software Reset PHY */ + reg_value = phy_read(phydev, MII_BMCR); + reg_value |= BMCR_RESET; + ret = phy_write(phydev, MII_BMCR, reg_value); + if (ret < 0) + return ret; + retry = MAX_RETRY; + do { + mdelay(10); + reg_value = phy_read(phydev, MII_BMCR); + retry--; + if (retry == 0) { + dev_err(dev, "Reset fail !\n"); + return 0; + } + } while (reg_value & BMCR_RESET); + + phydev->dev_flags = PHY_STATE_INIT; + + dev_info(dev, "Phase1 initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION); + if (priv->pro_version == 4) { + ret = en8801s_phase2_init(phydev); + if (ret != 0) { + dev_info(dev, "en8801_phase2_init failed\n"); + phydev->dev_flags = PHY_STATE_FAIL; + return 0; + } + phydev->dev_flags = PHY_STATE_PROCESS; + } + + return 0; +} + +static int en8801s_phase2_init(struct phy_device *phydev) +{ + union gephy_all_REG_LpiReg1Ch GPHY_RG_LPI_1C; + union gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324; + union gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012; + union gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017; + unsigned long pbus_data; + int phy_addr = phydev_phy_addr(phydev); + int pbus_addr = phydev_pbus_addr(phydev); + u16 cl45_value; + int retry, ret = 0; + struct mii_bus *mbus = phydev_mdio_bus(phydev); + struct device *dev = phydev_dev(phydev); + struct en8801s_priv *priv = phydev->priv; + + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690); + pbus_data |= BIT(31); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00); + if (ret < 0) + return ret; + /* Set FCM control */ + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505); + if (ret < 0) + return ret; + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11)); + if (ret < 0) + return ret; + + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5)); + if (ret < 0) + return ret; + + /* Set GPHY Perfomance*/ + /* Token Ring */ + ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h, 0x00001E); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h, 0x6FB90A); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h, 0x060671); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h, 0x0E2F00); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h, 0x444444); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h, 0x000000); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h, 0x2EBAEF); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h, 0x00000B); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch, 0x00504D); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh, 0x02314F); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh, 0x003028); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h, 0x005010); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h, 0x040001); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h, 0x018670); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h, 0x00024A); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh, 0x000072); + if (ret < 0) + return ret; + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch, 0x003210); + if (ret < 0) + return ret; + + /* CL22 & CL45 */ + ret = phy_write(phydev, 0x1f, 0x03); + if (ret < 0) + return ret; + GPHY_RG_LPI_1C.DATA = phy_read(phydev, RgAddr_LPI_1Ch); + GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C; + ret = phy_write(phydev, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA); + if (ret < 0) + return ret; + ret = phy_write(phydev, RgAddr_LPI_1Ch, 0xC92); + if (ret < 0) + return ret; + ret = phy_write(phydev, RgAddr_AUXILIARY_1Dh, 0x1); + if (ret < 0) + return ret; + ret = phy_write(phydev, 0x1f, 0x0); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x120, 0x8014); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x122, 0xffff); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x123, 0xffff); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x144, 0x0200); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x14A, 0xEE20); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x189, 0x0110); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19B, 0x0111); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x234, 0x0181); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x238, 0x0120); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x239, 0x0117); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x268, 0x07F4); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x2D1, 0x0733); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x323, 0x0011); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, 0x013F); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x326, 0x0037); + if (ret < 0) + return ret; + + ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x324, &cl45_value); + if (ret < 0) + return ret; + GPHY_RG_1E_324.DATA = cl45_value; + GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, + GPHY_RG_1E_324.DATA); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x19E, 0xC2); + if (ret < 0) + return ret; + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x013, 0x0); + if (ret < 0) + return ret; + + /* EFUSE */ + airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040); + retry = MAX_RETRY; + while (retry != 0) { + mdelay(1); + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); + if ((pbus_data & BIT(30)) == 0) + break; + + retry--; + } + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */ + ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x12, &cl45_value); + if (ret < 0) + return ret; + GPHY_RG_1E_012.DATA = cl45_value; + GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = + (u16)(pbus_data & 0x03f); + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x12, + GPHY_RG_1E_012.DATA); + if (ret < 0) + return ret; + ret = airoha_cl45_read(mbus, phy_addr, 0x1E, 0x17, &cl45_value); + if (ret < 0) + return ret; + GPHY_RG_1E_017.DATA = cl45_value; + GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = + (u16)((pbus_data >> 8) & 0x03f); + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x17, + GPHY_RG_1E_017.DATA); + if (ret < 0) + return ret; + + airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040); + retry = MAX_RETRY; + while (retry != 0) { + mdelay(1); + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08); + if ((pbus_data & BIT(30)) == 0) + break; + + retry--; + } + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */ + GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = + (u16)((pbus_data >> 12) & 0x01); + ret = airoha_cl45_write(mbus, phy_addr, 0x1E, 0x324, + GPHY_RG_1E_324.DATA); + if (ret < 0) + return ret; +#ifdef AIR_LED_SUPPORT + ret = en8801s_led_init(phydev); + if (ret != 0) + dev_err(dev, "en8801s_led_init fail (ret:%d) !\n", ret); +#endif + + ret = airoha_cl45_read(mbus, phy_addr, MDIO_MMD_AN, + MDIO_AN_EEE_ADV, &cl45_value); + if (ret < 0) + return ret; + if (cl45_value == 0) { + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); + if (0xA == ((pbus_data & 0x07c00000) >> 22)) { + pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + if (ret < 0) + return ret; + mdelay(10); + pbus_data = (pbus_data & 0xf83fffff) | (0xE << 22); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + if (ret < 0) + return ret; + mdelay(10); + } + } else { + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1960); + if (0xE == ((pbus_data & 0x07c00000) >> 22)) { + pbus_data = (pbus_data & 0xf83fffff) | (0xC << 22); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + if (ret < 0) + return ret; + mdelay(10); + pbus_data = (pbus_data & 0xf83fffff) | (0xA << 22); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + if (ret < 0) + return ret; + mdelay(10); + } + } + + priv->first_init = false; + dev_info(phydev_dev(phydev), "Phase2 initialize OK !\n"); + return 0; +} + +static int en8801s_read_status(struct phy_device *phydev) +{ + int ret = 0, preSpeed = phydev->speed; + struct mii_bus *mbus = phydev_mdio_bus(phydev); + u32 reg_value; + struct device *dev = phydev_dev(phydev); + int pbus_addr = phydev_pbus_addr(phydev); + struct en8801s_priv *priv = phydev->priv; + + ret = genphy_read_status(phydev); + if (phydev->link == LINK_DOWN) + preSpeed = phydev->speed = 0; + + if (phydev->dev_flags == PHY_STATE_PROCESS) { + en8801s_phy_process(phydev); + phydev->dev_flags = PHY_STATE_DONE; + } + + if (phydev->dev_flags == PHY_STATE_INIT) { + dev_dbg(dev, "phydev->link %d, count %d\n", + phydev->link, priv->count); + if ((phydev->link) || (priv->count == 5)) { + if (priv->pro_version != 4) { + ret = en8801s_phase2_init(phydev); + if (ret != 0) { + dev_info(dev, "en8801_phase2_init failed\n"); + phydev->dev_flags = PHY_STATE_FAIL; + return 0; + } + phydev->dev_flags = PHY_STATE_PROCESS; + } + } + priv->count++; + } + + if ((preSpeed != phydev->speed) && (phydev->link == LINK_UP)) { + preSpeed = phydev->speed; + + if (preSpeed == SPEED_10) { + reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); + reg_value |= BIT(31); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, + reg_value); + if (ret < 0) + return ret; + phydev->dev_flags = PHY_STATE_PROCESS; + } else { + reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1694); + reg_value &= ~BIT(31); + ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, + reg_value); + if (ret < 0) + return ret; + phydev->dev_flags = PHY_STATE_PROCESS; + } + + airoha_pbus_write(mbus, pbus_addr, 0x0600, + 0x0c000c00); + if (preSpeed == SPEED_1000) { + dev_dbg(dev, "SPEED_1000\n"); + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, + 0xD801); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, + 0x9140); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, + 0x0003); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, + 0x0c000c00); + if (ret < 0) + return ret; + mdelay(2); /* delay 2 ms */ + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, + 0x004b); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, + 0x0007); + if (ret < 0) + return ret; + } else if (preSpeed == SPEED_100) { + dev_dbg(dev, "SPEED_100\n"); + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, + 0xD401); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, + 0x9140); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, + 0x0007); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, + 0x0c11); + if (ret < 0) + return ret; + mdelay(2); /* delay 2 ms */ + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, + 0x0027); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, + 0x0007); + if (ret < 0) + return ret; + } else if (preSpeed == SPEED_10) { + dev_dbg(dev, "SPEED_10\n"); + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, + 0xD001); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, + 0x9140); + if (ret < 0) + return ret; + + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, + 0x000b); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, + 0x0c11); + if (ret < 0) + return ret; + mdelay(2); /* delay 2 ms */ + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, + 0x0027); + if (ret < 0) + return ret; + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, + 0x0007); + if (ret < 0) + return ret; + } + } + return ret; +} + +static int en8801s_probe(struct phy_device *phydev) +{ + struct en8801s_priv *priv; + unsigned long phy_addr = phydev_phy_addr(phydev); + struct mdio_device *mdiodev = &phydev->mdio; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->count = 0; + priv->first_init = true; + + if (mdiodev->reset_gpio) { + dev_dbg(phydev_dev(phydev), + "Assert PHY %lx HWRST until phy_init_hw\n", + phy_addr); + phy_device_reset(phydev, 1); + } + + phydev->priv = priv; + + return 0; +} + +static int airoha_mmd_read(struct phy_device *phydev, + int devad, u16 reg) +{ + struct mii_bus *mbus = phydev_mdio_bus(phydev); + int phy_addr = phydev_phy_addr(phydev); + int ret = 0; + u16 cl45_value; + + ret = __airoha_cl45_read(mbus, phy_addr, devad, reg, &cl45_value); + if (ret < 0) + return ret; + + return cl45_value; +} + +static int airoha_mmd_write(struct phy_device *phydev, + int devad, u16 reg, u16 val) +{ + struct mii_bus *mbus = phydev_mdio_bus(phydev); + int phy_addr = phydev_phy_addr(phydev); + int pbus_addr = phydev_pbus_addr(phydev); + unsigned long pbus_data; + int ret = 0; + + if (MDIO_MMD_AN == devad && MDIO_AN_EEE_ADV == reg) { + if (val == 0) { + pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); + if (0xA == ((pbus_data & 0x07c00000) >> 22)) { + pbus_data = (pbus_data & 0xf83fffff) | + (0xC << 22); + __airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + mdelay(10); + pbus_data = (pbus_data & 0xf83fffff) | + (0xE << 22); + __airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + mdelay(10); + } + } else { + pbus_data = __airoha_pbus_read(mbus, pbus_addr, 0x1960); + if (0xE == ((pbus_data & 0x07c00000) >> 22)) { + pbus_data = (pbus_data & 0xf83fffff) | + (0xC << 22); + __airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + mdelay(10); + pbus_data = (pbus_data & 0xf83fffff) | + (0xA << 22); + __airoha_pbus_write(mbus, pbus_addr, 0x1960, + pbus_data); + mdelay(10); + } + } + } + ret = __airoha_cl45_write(mbus, phy_addr, devad, reg, val); + if (ret < 0) + return ret; + + return 0; +} + +static struct phy_driver Airoha_driver[] = { + { + .phy_id = EN8801SC_PHY_ID, + .name = "Airoha EN8801SC", + .phy_id_mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES, + .probe = en8801s_probe, + .config_init = en8801s_phase1_init, + .config_aneg = genphy_config_aneg, + .read_status = en8801s_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_mmd = airoha_mmd_read, + .write_mmd = airoha_mmd_write, + } +}; + +module_phy_driver(Airoha_driver); + +static struct mdio_device_id __maybe_unused Airoha_tbl[] = { + { EN8801SC_PHY_ID, 0x0ffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, Airoha_tbl); diff --git a/drivers/net/phy/en8801sc.h b/drivers/net/phy/en8801sc.h new file mode 100644 index 000000000000..d1e268c9aa3a --- /dev/null +++ b/drivers/net/phy/en8801sc.h @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* FILE NAME: en8801sc.h + * PURPOSE: + * Define EN8801SC driver function + * + * NOTES: + * + */ + +#ifndef __EN8801SC_H +#define __EN8801SC_H + +/* NAMING DECLARATIONS + */ +#define EN8801S_DRIVER_VERSION "1.1.8_Generic" +#define EN8801S_PBUS_DEFAULT_ADDR 0x1e +#define EN8801S_PHY_DEFAULT_ADDR 0x1d +#define EN8801S_RG_ETHER_PHY_OUI 0x19a4 +#define EN8801S_RG_SMI_ADDR 0x19a8 +#define EN8801S_RG_BUCK_CTL 0x1a20 +#define EN8801S_RG_LTR_CTL 0x0cf8 +#define EN8801S_RG_PROD_VER 0x18e0 + +#define EN8801S_PBUS_OUI 0x17a5 +#define EN8801S_PHY_ID1 0x03a2 +#define EN8801S_PHY_ID2 0x9461 +#define EN8801SC_PHY_ID 0x03a29471 + +#define LED_ON_CTRL(i) (0x024 + ((i)*2)) +#define LED_ON_EN (1 << 15) +#define LED_ON_POL (1 << 14) +#define LED_ON_EVT_MASK (0x7f) +/* LED ON Event Option.B */ +#define LED_ON_EVT_FORCE (1 << 6) +#define LED_ON_EVT_LINK_DOWN (1 << 3) +#define LED_ON_EVT_LINK_10M (1 << 2) +#define LED_ON_EVT_LINK_100M (1 << 1) +#define LED_ON_EVT_LINK_1000M (1 << 0) +/* LED ON Event Option.E */ + +#define LED_BLK_CTRL(i) (0x025 + ((i)*2)) +#define LED_BLK_EVT_MASK (0x3ff) +/* LED Blinking Event Option.B*/ +#define LED_BLK_EVT_FORCE (1 << 9) +#define LED_BLK_EVT_10M_RX_ACT (1 << 5) +#define LED_BLK_EVT_10M_TX_ACT (1 << 4) +#define LED_BLK_EVT_100M_RX_ACT (1 << 3) +#define LED_BLK_EVT_100M_TX_ACT (1 << 2) +#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) +#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) +/* LED Blinking Event Option.E*/ +#define LED_ENABLE 1 +#define LED_DISABLE 0 + +#define LINK_UP 1 +#define LINK_DOWN 0 + +/* +SFP Sample for verification +Tx Reverse, Rx Reverse +*/ +#define EN8801S_TX_POLARITY_NORMAL 0x0 +#define EN8801S_TX_POLARITY_REVERSE 0x1 + +#define EN8801S_RX_POLARITY_NORMAL (0x1 << 1) +#define EN8801S_RX_POLARITY_REVERSE (0x0 << 1) + +/* +The following led_cfg example is for reference only. +LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0, +LED6 10/100M/LINK/ACT(GPIO9) <-> BASE_T_LED1, +LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2, +*/ +/* User-defined.B */ +#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_1000M) +#define BASE_T_LED0_BLK_CFG \ + (LED_BLK_EVT_1000M_TX_ACT | \ + LED_BLK_EVT_1000M_RX_ACT) +#define BASE_T_LED1_ON_CFG \ + (LED_ON_EVT_LINK_100M | \ + LED_ON_EVT_LINK_10M) +#define BASE_T_LED1_BLK_CFG \ + (LED_BLK_EVT_100M_TX_ACT | \ + LED_BLK_EVT_100M_RX_ACT | \ + LED_BLK_EVT_10M_TX_ACT | \ + LED_BLK_EVT_10M_RX_ACT) +#define BASE_T_LED2_ON_CFG \ + (LED_ON_EVT_LINK_100M) +#define BASE_T_LED2_BLK_CFG \ + (LED_BLK_EVT_100M_TX_ACT | \ + LED_BLK_EVT_100M_RX_ACT) +#define BASE_T_LED3_ON_CFG (0x0) +#define BASE_T_LED3_BLK_CFG (0x0) +/* User-defined.E */ + +#define EN8801S_LED_COUNT 4 + +#define MAX_RETRY 5 +#define MAX_OUI_CHECK 2 +/* CL45 MDIO control */ +#define MII_MMD_ACC_CTL_REG 0x0d +#define MII_MMD_ADDR_DATA_REG 0x0e +#define MMD_OP_MODE_DATA BIT(14) + +#define MAX_TRG_COUNTER 5 + +/* CL22 Reg Support Page Select */ +#define RgAddr_Reg1Fh 0x1f +#define CL22_Page_Reg 0x0000 +#define CL22_Page_ExtReg 0x0001 +#define CL22_Page_MiscReg 0x0002 +#define CL22_Page_LpiReg 0x0003 +#define CL22_Page_tReg 0x02A3 +#define CL22_Page_TrReg 0x52B5 + +/* CL45 Reg Support DEVID */ +#define DEVID_03 0x03 +#define DEVID_07 0x07 +#define DEVID_1E 0x1E +#define DEVID_1F 0x1F + +/* TokenRing Reg Access */ +#define TrReg_PKT_XMT_STA 0x8000 +#define TrReg_WR 0x8000 +#define TrReg_RD 0xA000 + +#define RgAddr_LPI_1Ch 0x1c +#define RgAddr_AUXILIARY_1Dh 0x1d +#define RgAddr_PMA_00h 0x0f80 +#define RgAddr_PMA_01h 0x0f82 +#define RgAddr_PMA_17h 0x0fae +#define RgAddr_PMA_18h 0x0fb0 +#define RgAddr_DSPF_03h 0x1686 +#define RgAddr_DSPF_06h 0x168c +#define RgAddr_DSPF_08h 0x1690 +#define RgAddr_DSPF_0Ch 0x1698 +#define RgAddr_DSPF_0Dh 0x169a +#define RgAddr_DSPF_0Fh 0x169e +#define RgAddr_DSPF_10h 0x16a0 +#define RgAddr_DSPF_11h 0x16a2 +#define RgAddr_DSPF_13h 0x16a6 +#define RgAddr_DSPF_14h 0x16a8 +#define RgAddr_DSPF_1Bh 0x16b6 +#define RgAddr_DSPF_1Ch 0x16b8 +#define RgAddr_TR_26h 0x0ecc +#define RgAddr_R1000DEC_15h 0x03aa +#define RgAddr_R1000DEC_17h 0x03ae + +#define LED_BCR (0x021) +#define LED_BCR_EXT_CTRL (1 << 15) +#define LED_BCR_CLK_EN (1 << 3) +#define LED_BCR_TIME_TEST (1 << 2) +#define LED_BCR_MODE_MASK (3) +#define LED_BCR_MODE_DISABLE (0) + +#define LED_ON_DUR (0x022) +#define LED_ON_DUR_MASK (0xffff) + +#define LED_BLK_DUR (0x023) +#define LED_BLK_DUR_MASK (0xffff) + +#define LED_GPIO_SEL_MASK 0x7FFFFFF + +#define UNIT_LED_BLINK_DURATION 1024 + +/* Invalid data */ +#define INVALID_DATA 0xffffffff + +#define LED_SET_GPIO_SEL(gpio, led, val) \ + (val |= (led << (8 * (gpio % 4)))) \ + +#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit) +/* DATA TYPE DECLARATIONS + */ +struct AIR_BASE_T_LED_CFG_S { + u16 en; + u16 gpio; + u16 pol; + u16 on_cfg; + u16 blk_cfg; +}; + +union gephy_all_REG_LpiReg1Ch { + struct { + /* b[15:00] */ + u16 smi_deton_wt : 3; + u16 smi_det_mdi_inv : 1; + u16 smi_detoff_wt : 3; + u16 smi_sigdet_debouncing_en : 1; + u16 smi_deton_th : 6; + u16 rsv_14 : 2; + } DataBitField; + u16 DATA; +}; + +union gephy_all_REG_dev1Eh_reg324h { + struct { + /* b[15:00] */ + u16 rg_smi_detcnt_max : 6; + u16 rsv_6 : 2; + u16 rg_smi_det_max_en : 1; + u16 smi_det_deglitch_off : 1; + u16 rsv_10 : 6; + } DataBitField; + u16 DATA; +}; + +union gephy_all_REG_dev1Eh_reg012h { + struct { + /* b[15:00] */ + u16 da_tx_i2mpb_a_tbt : 6; + u16 rsv_6 : 4; + u16 da_tx_i2mpb_a_gbe : 6; + } DataBitField; + u16 DATA; +}; + +union gephy_all_REG_dev1Eh_reg017h { + struct { + /* b[15:00] */ + u16 da_tx_i2mpb_b_tbt : 6; + u16 rsv_6 : 2; + u16 da_tx_i2mpb_b_gbe : 6; + u16 rsv_14 : 2; + } DataBitField; + u16 DATA; +}; + +enum { + AIR_LED_BLK_DUR_32M, + AIR_LED_BLK_DUR_64M, + AIR_LED_BLK_DUR_128M, + AIR_LED_BLK_DUR_256M, + AIR_LED_BLK_DUR_512M, + AIR_LED_BLK_DUR_1024M, + AIR_LED_BLK_DUR_LAST +}; + +enum { + AIR_ACTIVE_LOW, + AIR_ACTIVE_HIGH, +}; + +enum { + AIR_LED_MODE_DISABLE, + AIR_LED_MODE_USER_DEFINE, + AIR_LED_MODE_LAST +}; + +#endif /* End of __EN8801SC_H */ diff --git a/drivers/net/phy/ip17xx.c b/drivers/net/phy/ip17xx.c new file mode 100644 index 000000000000..c36980339578 --- /dev/null +++ b/drivers/net/phy/ip17xx.c @@ -0,0 +1,1370 @@ +/* + * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family + * + * Copyright (C) 2008 Patrick Horn + * Copyright (C) 2008, 2010 Martin Mares + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_VLANS 16 +#define MAX_PORTS 9 +#undef DUMP_MII_IO + +typedef struct ip17xx_reg { + u16 p; // phy + u16 m; // mii +} reg; +typedef char bitnum; + +#define NOTSUPPORTED {-1,-1} + +#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) + +struct ip17xx_state; + +/*********** CONSTANTS ***********/ +struct register_mappings { + char *NAME; + u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. + bitnum NUM_PORTS; + bitnum CPU_PORT; + +/* The default VLAN for each port. + Default: 0x0001 for Ports 0,1,2,3 + 0x0002 for Ports 4,5 */ + reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; + +/* These ports are tagged. + Default: 0x00 */ + reg ADD_TAG_REG; + reg REMOVE_TAG_REG; + bitnum ADD_TAG_BIT[MAX_PORTS]; +/* These ports are untagged. + Default: 0x00 (i.e. do not alter any VLAN tags...) + Maybe set to 0 if user disables VLANs. */ + bitnum REMOVE_TAG_BIT[MAX_PORTS]; + +/* Port M and Port N are on the same VLAN. + Default: All ports on all VLANs. */ +// Use register {29, 19+N/2} + reg VLAN_LOOKUP_REG; +// Port 5 uses register {30, 18} but same as odd bits. + reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. + bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; + bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; + +/* This VLAN corresponds to which ports. + Default: 0x2f,0x30,0x3f,0x3f... */ + reg TAG_VLAN_MASK_REG; + bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; + bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; + + int RESET_VAL; + reg RESET_REG; + + reg MODE_REG; + int MODE_VAL; + +/* General flags */ + reg ROUTER_CONTROL_REG; + reg VLAN_CONTROL_REG; + bitnum TAG_VLAN_BIT; + bitnum ROUTER_EN_BIT; + bitnum NUMLAN_GROUPS_MAX; + bitnum NUMLAN_GROUPS_BIT; + + reg MII_REGISTER_EN; + bitnum MII_REGISTER_EN_BIT; + + // set to 1 for 178C, 0 for 175C. + bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. + + // Pointers to functions which manipulate hardware state + int (*update_state)(struct ip17xx_state *state); + int (*set_vlan_mode)(struct ip17xx_state *state); + int (*reset)(struct ip17xx_state *state); +}; + +static int ip175c_update_state(struct ip17xx_state *state); +static int ip175c_set_vlan_mode(struct ip17xx_state *state); +static int ip175c_reset(struct ip17xx_state *state); + +static const struct register_mappings IP178C = { + .NAME = "IP178C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, + {30,9},{30,10},{30,11}, + }, + + .ADD_TAG_REG = {30,12}, + .ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, + .REMOVE_TAG_REG = {30,13}, + .REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, + + .SIMPLE_VLAN_REGISTERS = 1, + + .VLAN_LOOKUP_REG = {31,0},// +N + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS + .VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .TAG_VLAN_MASK_REG = {30,14}, // +N + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .RESET_VAL = 0x55AA, + .RESET_REG = {30,0}, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = {30,30}, + .ROUTER_EN_BIT = 11, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 8, // {0-2} + + .VLAN_CONTROL_REG = {30,13}, + .TAG_VLAN_BIT = 3, + + .CPU_PORT = 8, + .NUM_PORTS = 9, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175C = { + .NAME = "IP175C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {29,23}, + .REMOVE_TAG_REG = {29,23}, + .ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = {29,19},// +N/2 + .VLAN_LOOKUP_REG_5 = {30,18}, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = {30,1}, // +N/2 + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, + + .RESET_VAL = 0x175C, + .RESET_REG = {30,0}, + .MODE_VAL = 0x175C, + .MODE_REG = {29,31}, + + .ROUTER_CONTROL_REG = {30,9}, + .ROUTER_EN_BIT = 3, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 0, // {0-2} + + .VLAN_CONTROL_REG = {30,9}, + .TAG_VLAN_BIT = 7, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175A = { + .NAME = "IP175A", + .MODEL_NO = 0x05, + .VLAN_DEFAULT_TAG_REG = { + {0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {0,23}, + .REMOVE_TAG_REG = {0,23}, + .ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + // Only programmable via EEPROM + .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2, + .TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + + .RESET_VAL = -1, + .RESET_REG = NOTSUPPORTED, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_MAX = -1, + .NUMLAN_GROUPS_BIT = -1, // {0-2} + + .NUM_PORTS = 5, + .CPU_PORT = 4, + + .MII_REGISTER_EN = {0, 18}, + .MII_REGISTER_EN_BIT = 7, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + + +static int ip175d_update_state(struct ip17xx_state *state); +static int ip175d_set_vlan_mode(struct ip17xx_state *state); +static int ip175d_reset(struct ip17xx_state *state); + +static const struct register_mappings IP175D = { + .NAME = "IP175D", + .MODEL_NO = 0x18, + + // The IP175D has a completely different interface, so we leave most + // of the registers undefined and switch to different code paths. + + .VLAN_DEFAULT_TAG_REG = { + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + }, + + .ADD_TAG_REG = NOTSUPPORTED, + .REMOVE_TAG_REG = NOTSUPPORTED, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = NOTSUPPORTED, + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .TAG_VLAN_MASK_REG = NOTSUPPORTED, + + .RESET_VAL = 0x175D, + .RESET_REG = {20,2}, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_BIT = -1, + + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175d_update_state, + .set_vlan_mode = ip175d_set_vlan_mode, + .reset = ip175d_reset, +}; + +struct ip17xx_state { + struct switch_dev dev; + struct mii_bus *mii_bus; + bool registered; + + int router_mode; // ROUTER_EN + int vlan_enabled; // TAG_VLAN_EN + struct port_state { + u16 pvid; + unsigned int shareports; + } ports[MAX_PORTS]; + unsigned int add_tag; + unsigned int remove_tag; + int num_vlans; + struct vlan_state { + unsigned int ports; + unsigned int tag; // VLAN tag (IP175D only) + } vlans[MAX_VLANS]; + const struct register_mappings *regs; + reg proc_mii; // phy/reg for the low level register access via swconfig + + char buf[80]; +}; + +#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev) + +static int ip_phy_read(struct ip17xx_state *state, int port, int reg) +{ + int val = mdiobus_read(state->mii_bus, port, reg); + if (val < 0) + pr_warn("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val); +#ifdef DUMP_MII_IO + else + pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val); +#endif + return val; +} + +static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val) +{ + int err; + +#ifdef DUMP_MII_IO + pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val); +#endif + err = mdiobus_write(state->mii_bus, port, reg, val); + if (err < 0) + pr_warn("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err); + return err; +} + +static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data) +{ + int val = ip_phy_read(state, port, reg); + if (val < 0) + return 0; + return ip_phy_write(state, port, reg, (val & ~mask) | data); +} + +static int getPhy(struct ip17xx_state *state, reg mii) +{ + if (!REG_SUPP(mii)) + return -EFAULT; + return ip_phy_read(state, mii.p, mii.m); +} + +static int setPhy(struct ip17xx_state *state, reg mii, u16 value) +{ + int err; + + if (!REG_SUPP(mii)) + return -EFAULT; + err = ip_phy_write(state, mii.p, mii.m, value); + if (err < 0) + return err; + mdelay(2); + getPhy(state, mii); + return 0; +} + + +/** + * These two macros are to simplify the mapping of logical bits to the bits in hardware. + * NOTE: these macros will return if there is an error! + */ + +#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ + do { \ + int i, val = getPhy((state), (addr)); \ + if (val < 0) \ + return val; \ + (bits) = 0; \ + for (i = 0; i < MAX_PORTS; i++) { \ + if ((bit_lookup)[i] == -1) continue; \ + if (val & (1<<(bit_lookup)[i])) \ + (bits) |= (1<>i)<<(bit_lookup)[i]); \ + } \ + val = setPhy((state), (addr), val); \ + if (val < 0) \ + return val; \ + } while (0) + + +static int get_model(struct ip17xx_state *state) +{ + int id1, id2; + int oui_id, model_no, rev_no, chip_no; + + id1 = ip_phy_read(state, 0, 2); + id2 = ip_phy_read(state, 0, 3); + oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); + model_no = (id2 >> 4) & 0x3f; + rev_no = id2 & 0xf; + pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); + + if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway + return -ENODEV; + + if (model_no == IP175A.MODEL_NO) { + state->regs = &IP175A; + } else if (model_no == IP175C.MODEL_NO) { + /* + * Several models share the same model_no: + * 178C has more PHYs, so we try whether the device responds to a read from PHY5 + * 175D has a new chip ID register + * 175C has neither + */ + if (ip_phy_read(state, 5, 2) == 0x0243) { + state->regs = &IP178C; + } else { + chip_no = ip_phy_read(state, 20, 0); + pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no); + if (chip_no == 0x175d) { + state->regs = &IP175D; + } else { + state->regs = &IP175C; + } + } + } else { + pr_warn("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no); + return -EPERM; + } + return 0; +} + +/*** Low-level functions for the older models ***/ + +/** Only set vlan and router flags in the switch **/ +static int ip175c_set_flags(struct ip17xx_state *state) +{ + int val; + + if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { + return 0; + } + + val = getPhy(state, state->regs->ROUTER_CONTROL_REG); + if (val < 0) { + return val; + } + if (state->regs->ROUTER_EN_BIT >= 0) { + if (state->router_mode) { + val |= (1<regs->ROUTER_EN_BIT); + } else { + val &= (~(1<regs->ROUTER_EN_BIT)); + } + } + if (state->regs->TAG_VLAN_BIT >= 0) { + if (state->vlan_enabled) { + val |= (1<regs->TAG_VLAN_BIT); + } else { + val &= (~(1<regs->TAG_VLAN_BIT)); + } + } + if (state->regs->NUMLAN_GROUPS_BIT >= 0) { + val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<regs->NUMLAN_GROUPS_BIT)); + if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { + val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; + } else if (state->num_vlans >= 1) { + val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; + } + } + return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); +} + +/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ +static int ip175c_set_state(struct ip17xx_state *state) +{ + int j; + int i; + SET_PORT_BITS(state, state->add_tag, + state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); + SET_PORT_BITS(state, state->remove_tag, + state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); + + if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { + for (j=0; jregs->NUM_PORTS; j++) { + reg addr; + const bitnum *bit_lookup = (j%2==0)? + state->regs->VLAN_LOOKUP_EVEN_BIT: + state->regs->VLAN_LOOKUP_ODD_BIT; + + addr = state->regs->VLAN_LOOKUP_REG; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + switch (j) { + case 0: + case 1: + break; + case 2: + case 3: + addr.m+=1; + break; + case 4: + addr.m+=2; + break; + case 5: + addr = state->regs->VLAN_LOOKUP_REG_5; + break; + default: + addr.m = -1; // shouldn't get here, but... + break; + } + } + //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); + if (REG_SUPP(addr)) { + SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); + } + } + } + if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { + for (j=0; jregs->TAG_VLAN_MASK_REG; + const bitnum *bit_lookup = (j%2==0)? + state->regs->TAG_VLAN_MASK_EVEN_BIT: + state->regs->TAG_VLAN_MASK_ODD_BIT; + unsigned int vlan_mask; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + addr.m += j/2; + } + vlan_mask = state->vlans[j].ports; + SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); + } + } + + for (i=0; iregs->VLAN_DEFAULT_TAG_REG[i])) { + int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], + state->ports[i].pvid); + if (err < 0) { + return err; + } + } + } + + return ip175c_set_flags(state); +} + +/** + * Uses only the VLAN port mask and the add tag mask to generate the other fields: + * which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. + */ +static void ip175c_correct_vlan_state(struct ip17xx_state *state) +{ + int i, j; + state->num_vlans = 0; + for (i=0; ivlans[i].ports != 0) { + state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... + } + } + + for (i=0; iregs->NUM_PORTS; i++) { + unsigned int portmask = (1<vlan_enabled) { + // Share with everybody! + state->ports[i].shareports = (1<regs->NUM_PORTS)-1; + continue; + } + state->ports[i].shareports = portmask; + for (j=0; jvlans[j].ports & portmask) + state->ports[i].shareports |= state->vlans[j].ports; + } + } +} + +static int ip175c_update_state(struct ip17xx_state *state) +{ + ip175c_correct_vlan_state(state); + return ip175c_set_state(state); +} + +static int ip175c_set_vlan_mode(struct ip17xx_state *state) +{ + return ip175c_update_state(state); +} + +static int ip175c_reset(struct ip17xx_state *state) +{ + int err; + + if (REG_SUPP(state->regs->MODE_REG)) { + err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->MODE_REG); + if (err < 0) + return err; + } + + return ip175c_update_state(state); +} + +/*** Low-level functions for IP175D ***/ + +static int ip175d_update_state(struct ip17xx_state *state) +{ + unsigned int filter_mask = 0; + unsigned int ports[16], add[16], rem[16]; + int i, j; + int err = 0; + + for (i = 0; i < 16; i++) { + ports[i] = 0; + add[i] = 0; + rem[i] = 0; + if (!state->vlan_enabled) { + err |= ip_phy_write(state, 22, 14+i, i+1); // default tags + ports[i] = 0x3f; + continue; + } + if (!state->vlans[i].tag) { + // Reset the filter + err |= ip_phy_write(state, 22, 14+i, 0); // tag + continue; + } + filter_mask |= 1 << i; + err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); + ports[i] = state->vlans[i].ports; + for (j = 0; j < 6; j++) { + if (ports[i] & (1 << j)) { + if (state->add_tag & (1 << j)) + add[i] |= 1 << j; + if (state->remove_tag & (1 << j)) + rem[i] |= 1 << j; + } + } + } + + // Port masks, tag adds and removals + for (i = 0; i < 8; i++) { + err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); + } + err |= ip_phy_write(state, 22, 10, filter_mask); + + // Default VLAN tag for each port + for (i = 0; i < 6; i++) + err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); + + return (err ? -EIO : 0); +} + +static int ip175d_set_vlan_mode(struct ip17xx_state *state) +{ + int i; + int err = 0; + + if (state->vlan_enabled) { + // VLAN classification rules: tag-based VLANs, use VID to classify, + // drop packets that cannot be classified. + err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); + + // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, + // VID=0xfff discarded, admin both tagged and untagged, ingress + // filters enabled. + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + + // Egress rules: IGMP processing off, keep VLAN header off + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } else { + // VLAN classification rules: everything off & clear table + err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); + + // Ingress and egress rules: set to defaults + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } + + // Reset default VLAN for each port to 0 + for (i = 0; i < 6; i++) + state->ports[i].pvid = 0; + + err |= ip175d_update_state(state); + + return (err ? -EIO : 0); +} + +static int ip175d_reset(struct ip17xx_state *state) +{ + int err = 0; + + // Disable the special tagging mode + err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); + + // Set 802.1q protocol type + err |= ip_phy_write(state, 22, 3, 0x8100); + + state->vlan_enabled = 0; + err |= ip175d_set_vlan_mode(state); + + return (err ? -EIO : 0); +} + +/*** High-level functions ***/ + +static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->vlan_enabled; + return 0; +} + +static void ip17xx_reset_vlan_config(struct ip17xx_state *state) +{ + int i; + + state->remove_tag = (state->vlan_enabled ? ((1<regs->NUM_PORTS)-1) : 0x0000); + state->add_tag = 0x0000; + for (i = 0; i < MAX_VLANS; i++) { + state->vlans[i].ports = 0x0000; + state->vlans[i].tag = (i ? i : 16); + } + for (i = 0; i < MAX_PORTS; i++) + state->ports[i].pvid = 0; +} + +static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int enable; + + enable = val->value.i; + if (state->vlan_enabled == enable) { + // Do not change any state. + return 0; + } + state->vlan_enabled = enable; + + // Otherwise, if we are switching state, set fields to a known default. + ip17xx_reset_vlan_config(state); + + return state->regs->set_vlan_mode(state); +} + +static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int b; + int ind; + unsigned int ports; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + ports = state->vlans[val->port_vlan].ports; + b = 0; + ind = 0; + while (b < MAX_PORTS) { + if (ports&1) { + int istagged = ((state->add_tag >> b) & 1); + val->value.ports[ind].id = b; + val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); + ind++; + } + b++; + ports >>= 1; + } + val->len = ind; + + return 0; +} + +static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int i; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + state->vlans[val->port_vlan].ports = 0; + for (i = 0; i < val->len; i++) { + unsigned int bitmask = (1<value.ports[i].id); + state->vlans[val->port_vlan].ports |= bitmask; + if (val->value.ports[i].flags & (1<add_tag |= bitmask; + state->remove_tag &= (~bitmask); + } else { + state->add_tag &= (~bitmask); + state->remove_tag |= bitmask; + } + } + + return state->regs->update_state(state); +} + +static int ip17xx_apply(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + + if (REG_SUPP(state->regs->MII_REGISTER_EN)) { + int val = getPhy(state, state->regs->MII_REGISTER_EN); + if (val < 0) { + return val; + } + val |= (1<regs->MII_REGISTER_EN_BIT); + return setPhy(state, state->regs->MII_REGISTER_EN, val); + } + return 0; +} + +static int ip17xx_reset(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + int i, err; + + if (REG_SUPP(state->regs->RESET_REG)) { + err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->RESET_REG); + + /* + * Data sheet specifies reset period to be 2 msec. + * (I don't see any mention of the 2ms delay in the IP178C spec, only + * in IP175C, but it can't hurt.) + */ + mdelay(2); + } + + /* reset switch ports */ + for (i = 0; i < state->regs->NUM_PORTS-1; i++) { + err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + } + + state->router_mode = 0; + state->vlan_enabled = 0; + ip17xx_reset_vlan_config(state); + + return state->regs->reset(state); +} + +static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + if (state->add_tag & (1<port_vlan)) { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 3; // shouldn't ever happen. + else + val->value.i = 1; + } else { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 0; + else + val->value.i = 2; + } + return 0; +} + +static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + state->add_tag &= ~(1<port_vlan); + state->remove_tag &= ~(1<port_vlan); + + if (val->value.i == 0) + state->remove_tag |= (1<port_vlan); + if (val->value.i == 1) + state->add_tag |= (1<port_vlan); + + return state->regs->update_state(state); +} + +/** Get the current phy address */ +static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.p; + return 0; +} + +/** Set a new phy address for low level access to registers */ +static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.p = (u16)-1; + else + state->proc_mii.p = (u16)new_reg; + return 0; +} + +/** Get the current register number */ +static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.m; + return 0; +} + +/** Set a new register address for low level access to registers */ +static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.m = (u16)-1; + else + state->proc_mii.m = (u16)new_reg; + return 0; +} + +/** Get the register content of state->proc_mii */ +static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int retval = -EINVAL; + if (REG_SUPP(state->proc_mii)) + retval = getPhy(state, state->proc_mii); + + if (retval < 0) { + return retval; + } else { + val->value.i = retval; + return 0; + } +} + +/** Write a value to the register defined by phy/reg above */ +static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int myval, err = -EINVAL; + + myval = val->value.i; + if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { + err = setPhy(state, state->proc_mii, (u16)myval); + } + return err; +} + +static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. + return 0; +} + +static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + val->value.i = state->vlans[vlan].tag; + return 0; +} + +static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + int tag = val->value.i; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + if (tag < 0 || tag > 4095) + return -EINVAL; + + state->vlans[vlan].tag = tag; + return state->regs->update_state(state); +} + +static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int ctrl; + int autoneg; + int speed; + if (val->value.i == 100) { + speed = 1; + autoneg = 0; + } else if (val->value.i == 10) { + speed = 0; + autoneg = 0; + } else { + autoneg = 1; + speed = 1; + } + + /* Can't set speed for cpu port */ + if (nr == state->regs->CPU_PORT) + return -EINVAL; + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + if (ctrl < 0) + return -EIO; + + ctrl &= (~(1<<12)); + ctrl &= (~(1<<13)); + ctrl |= (autoneg<<12); + ctrl |= (speed<<13); + + return ip_phy_write(state, nr, 0, ctrl); +} + +static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int speed, status; + + if (nr == state->regs->CPU_PORT) { + val->value.i = 100; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (status < 0 || speed < 0) + return -EIO; + + if (status & 4) + val->value.i = ((speed & (1<<11)) ? 100 : 10); + else + val->value.i = 0; + + return 0; +} + +static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int ctrl, speed, status; + int nr = val->port_vlan; + int len; + char *buf = state->buf; // fixed-length at 80. + + if (nr == state->regs->CPU_PORT) { + sprintf(buf, "up, 100 Mbps, cpu port"); + val->value.s = buf; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (ctrl < 0 || status < 0 || speed < 0) + return -EIO; + + if (status & 4) + len = sprintf(buf, "up, %d Mbps, %s duplex", + ((speed & (1<<11)) ? 100 : 10), + ((speed & (1<<10)) ? "full" : "half")); + else + len = sprintf(buf, "down"); + + if (ctrl & (1<<12)) { + len += sprintf(buf+len, ", auto-negotiate"); + if (!(status & (1<<5))) + len += sprintf(buf+len, " (in progress)"); + } else { + len += sprintf(buf+len, ", fixed speed (%d)", + ((ctrl & (1<<13)) ? 100 : 10)); + } + + buf[len] = '\0'; + val->value.s = buf; + return 0; +} + +static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct ip17xx_state *state = get_state(dev); + + *val = state->ports[port].pvid; + return 0; +} + +static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct ip17xx_state *state = get_state(dev); + + if (val < 0 || val >= MAX_VLANS) + return -EINVAL; + + state->ports[port].pvid = val; + return state->regs->update_state(state); +} + + +enum Ports { + IP17XX_PORT_STATUS, + IP17XX_PORT_LINK, + IP17XX_PORT_TAGGED, + IP17XX_PORT_PVID, +}; + +enum Globals { + IP17XX_ENABLE_VLAN, + IP17XX_GET_NAME, + IP17XX_REGISTER_PHY, + IP17XX_REGISTER_MII, + IP17XX_REGISTER_VALUE, + IP17XX_REGISTER_ERRNO, +}; + +enum Vlans { + IP17XX_VLAN_TAG, +}; + +static const struct switch_attr ip17xx_global[] = { + [IP17XX_ENABLE_VLAN] = { + .id = IP17XX_ENABLE_VLAN, + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Flag to enable or disable VLANs and tagging", + .get = ip17xx_get_enable_vlan, + .set = ip17xx_set_enable_vlan, + }, + [IP17XX_GET_NAME] = { + .id = IP17XX_GET_NAME, + .type = SWITCH_TYPE_STRING, + .description = "Returns the type of IC+ chip.", + .name = "name", + .get = ip17xx_read_name, + .set = NULL, + }, + /* jal: added for low level debugging etc. */ + [IP17XX_REGISTER_PHY] = { + .id = IP17XX_REGISTER_PHY, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set PHY (0-4, or 29,30,31)", + .name = "phy", + .get = ip17xx_get_phy, + .set = ip17xx_set_phy, + }, + [IP17XX_REGISTER_MII] = { + .id = IP17XX_REGISTER_MII, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set MII register number (0-31)", + .name = "reg", + .get = ip17xx_get_reg, + .set = ip17xx_set_reg, + }, + [IP17XX_REGISTER_VALUE] = { + .id = IP17XX_REGISTER_VALUE, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: read/write to register (0-65535)", + .name = "val", + .get = ip17xx_get_val, + .set = ip17xx_set_val, + }, +}; + +static const struct switch_attr ip17xx_vlan[] = { + [IP17XX_VLAN_TAG] = { + .id = IP17XX_VLAN_TAG, + .type = SWITCH_TYPE_INT, + .description = "VLAN ID (0-4095) [IP175D only]", + .name = "vid", + .get = ip17xx_get_tag, + .set = ip17xx_set_tag, + } +}; + +static const struct switch_attr ip17xx_port[] = { + [IP17XX_PORT_STATUS] = { + .id = IP17XX_PORT_STATUS, + .type = SWITCH_TYPE_STRING, + .description = "Returns Detailed port status", + .name = "status", + .get = ip17xx_get_port_status, + .set = NULL, + }, + [IP17XX_PORT_LINK] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", + .name = "link", + .get = ip17xx_get_port_speed, + .set = ip17xx_set_port_speed, + }, + [IP17XX_PORT_TAGGED] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", + .name = "tagged", + .get = ip17xx_get_tagged, + .set = ip17xx_set_tagged, + }, +}; + +static const struct switch_dev_ops ip17xx_ops = { + .attr_global = { + .attr = ip17xx_global, + .n_attr = ARRAY_SIZE(ip17xx_global), + }, + .attr_port = { + .attr = ip17xx_port, + .n_attr = ARRAY_SIZE(ip17xx_port), + }, + .attr_vlan = { + .attr = ip17xx_vlan, + .n_attr = ARRAY_SIZE(ip17xx_vlan), + }, + + .get_port_pvid = ip17xx_get_pvid, + .set_port_pvid = ip17xx_set_pvid, + .get_vlan_ports = ip17xx_get_ports, + .set_vlan_ports = ip17xx_set_ports, + .apply_config = ip17xx_apply, + .reset_switch = ip17xx_reset, +}; + +static int ip17xx_probe(struct phy_device *pdev) +{ + struct ip17xx_state *state; + struct switch_dev *dev; + int err; + + /* We only attach to PHY 0, but use all available PHYs */ + if (pdev->mdio.addr != 0) + return -ENODEV; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + dev = &state->dev; + + pdev->priv = state; + state->mii_bus = pdev->mdio.bus; + + err = get_model(state); + if (err < 0) + goto error; + + dev->vlans = MAX_VLANS; + dev->cpu_port = state->regs->CPU_PORT; + dev->ports = state->regs->NUM_PORTS; + dev->name = state->regs->NAME; + dev->ops = &ip17xx_ops; + + pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev)); + return 0; + +error: + kfree(state); + return err; +} + +static int ip17xx_config_init(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + struct net_device *dev = pdev->attached_dev; + int err; + + err = register_switch(&state->dev, dev); + if (err < 0) + return err; + + state->registered = true; + ip17xx_reset(&state->dev); + return 0; +} + +static void ip17xx_remove(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + + if (state->registered) + unregister_switch(&state->dev); + kfree(state); +} + +static int ip17xx_config_aneg(struct phy_device *pdev) +{ + return 0; +} + +static int ip17xx_aneg_done(struct phy_device *pdev) +{ + return 1; /* Return any positive value */ +} + +static int ip17xx_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->pause = pdev->asym_pause = 0; + pdev->link = 1; + + return 0; +} + +static struct phy_driver ip17xx_driver[] = { + { + .name = "IC+ IP17xx", + .phy_id = 0x02430c00, + .phy_id_mask = 0x0ffffc00, + .features = PHY_BASIC_FEATURES, + .probe = ip17xx_probe, + .remove = ip17xx_remove, + .config_init = ip17xx_config_init, + .config_aneg = ip17xx_config_aneg, + .aneg_done = ip17xx_aneg_done, + .read_status = ip17xx_read_status, + } +}; + +module_phy_driver(ip17xx_driver); + +MODULE_AUTHOR("Patrick Horn "); +MODULE_AUTHOR("Felix Fietkau "); +MODULE_AUTHOR("Martin Mares "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/psb6970.c b/drivers/net/phy/psb6970.c new file mode 100644 index 000000000000..e8b1b06f6365 --- /dev/null +++ b/drivers/net/phy/psb6970.c @@ -0,0 +1,443 @@ +/* + * Lantiq PSB6970 (Tantos) Switch driver + * + * Copyright (c) 2009,2010 Team Embedded. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * The switch programming done in this driver follows the + * "Ethernet Traffic Separation using VLAN" Application Note as + * published by Lantiq. + */ + +#include +#include +#include +#include +#include + +#define PSB6970_MAX_VLANS 16 +#define PSB6970_NUM_PORTS 7 +#define PSB6970_DEFAULT_PORT_CPU 6 +#define PSB6970_IS_CPU_PORT(x) ((x) > 4) + +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +/* --- Identification --- */ +#define PSB6970_CI0 0x0100 +#define PSB6970_CI0_MASK 0x000f +#define PSB6970_CI1 0x0101 +#define PSB6970_CI1_VAL 0x2599 +#define PSB6970_CI1_MASK 0xffff + +/* --- VLAN filter table --- */ +#define PSB6970_VFxL(i) ((i)*2+0x10) /* VLAN Filter Low */ +#define PSB6970_VFxL_VV (1 << 15) /* VLAN_Valid */ + +#define PSB6970_VFxH(i) ((i)*2+0x11) /* VLAN Filter High */ +#define PSB6970_VFxH_TM_SHIFT 7 /* Tagged Member */ + +/* --- Port registers --- */ +#define PSB6970_EC(p) ((p)*0x20+2) /* Extended Control */ +#define PSB6970_EC_IFNTE (1 << 1) /* Input Force No Tag Enable */ + +#define PSB6970_PBVM(p) ((p)*0x20+3) /* Port Base VLAN Map */ +#define PSB6970_PBVM_VMCE (1 << 8) +#define PSB6970_PBVM_AOVTP (1 << 9) +#define PSB6970_PBVM_VSD (1 << 10) +#define PSB6970_PBVM_VC (1 << 11) /* VID Check with VID table */ +#define PSB6970_PBVM_TBVE (1 << 13) /* Tag-Based VLAN enable */ + +#define PSB6970_DVID(p) ((p)*0x20+4) /* Default VLAN ID & Priority */ + +struct psb6970_priv { + struct switch_dev dev; + struct phy_device *phy; + u16 (*read) (struct phy_device* phydev, int reg); + void (*write) (struct phy_device* phydev, int reg, u16 val); + struct mutex reg_mutex; + + /* all fields below are cleared on reset */ + struct_group(psb6970_priv_volatile, + bool vlan; + u16 vlan_id[PSB6970_MAX_VLANS]; + u8 vlan_table[PSB6970_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[PSB6970_NUM_PORTS]; + ); +}; + +#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev) + +static u16 psb6970_mii_read(struct phy_device *phydev, int reg) +{ + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, PHYADDR(reg)); +} + +static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val) +{ + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, PHYADDR(reg), val); +} + +static int +psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan = !!val->value.i; + return 0; +} + +static int +psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan; + return 0; +} + +static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + + /* make sure no invalid PVIDs get set */ + if (vlan >= dev->vlans) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + *vlan = priv->pvid[port]; + return 0; +} + +static int +psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +static struct switch_attr psb6970_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = psb6970_set_vlan, + .get = psb6970_get_vlan, + .max = 1}, +}; + +static struct switch_attr psb6970_port[] = { +}; + +static struct switch_attr psb6970_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = psb6970_set_vid, + .get = psb6970_get_vid, + .max = 4094, + }, +}; + +static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) + priv->vlan_tagged |= (1 << p->id); + else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static int psb6970_hw_apply(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i, j; + + mutex_lock(&priv->reg_mutex); + + if (priv->vlan) { + /* into the vlan translation unit */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + u8 vp = priv->vlan_table[j]; + + if (vp) { + priv->write(priv->phy, PSB6970_VFxL(j), + PSB6970_VFxL_VV | priv->vlan_id[j]); + priv->write(priv->phy, PSB6970_VFxH(j), + ((vp & priv-> + vlan_tagged) << + PSB6970_VFxH_TM_SHIFT) | vp); + } else /* clear VLAN Valid flag for unused vlans */ + priv->write(priv->phy, PSB6970_VFxL(j), 0); + + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0; + + if (priv->vlan) { + ec = PSB6970_EC_IFNTE; + dvid = priv->vlan_id[priv->pvid[i]]; + pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE; + + if ((i << 1) & priv->vlan_tagged) + pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC; + } + + priv->write(priv->phy, PSB6970_PBVM(i), pbvm); + + if (!PSB6970_IS_CPU_PORT(i)) { + priv->write(priv->phy, PSB6970_EC(i), ec); + priv->write(priv->phy, PSB6970_DVID(i), dvid); + } + } + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int psb6970_reset_switch(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i; + + mutex_lock(&priv->reg_mutex); + + memset(&priv->psb6970_priv_volatile, 0, + sizeof(priv->psb6970_priv_volatile)); + + for (i = 0; i < PSB6970_MAX_VLANS; i++) + priv->vlan_id[i] = i; + + mutex_unlock(&priv->reg_mutex); + + return psb6970_hw_apply(dev); +} + +static const struct switch_dev_ops psb6970_ops = { + .attr_global = { + .attr = psb6970_globals, + .n_attr = ARRAY_SIZE(psb6970_globals), + }, + .attr_port = { + .attr = psb6970_port, + .n_attr = ARRAY_SIZE(psb6970_port), + }, + .attr_vlan = { + .attr = psb6970_vlan, + .n_attr = ARRAY_SIZE(psb6970_vlan), + }, + .get_port_pvid = psb6970_get_pvid, + .set_port_pvid = psb6970_set_pvid, + .get_vlan_ports = psb6970_get_ports, + .set_vlan_ports = psb6970_set_ports, + .apply_config = psb6970_hw_apply, + .reset_switch = psb6970_reset_switch, +}; + +static int psb6970_config_init(struct phy_device *pdev) +{ + struct psb6970_priv *priv; + struct switch_dev *swdev; + int ret; + + priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->phy = pdev; + + if (pdev->mdio.addr == 0) + printk(KERN_INFO "%s: psb6970 switch driver attached.\n", + pdev->attached_dev->name); + + if (pdev->mdio.addr != 0) { + kfree(priv); + return 0; + } + + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + + mutex_init(&priv->reg_mutex); + priv->read = psb6970_mii_read; + priv->write = psb6970_mii_write; + + pdev->priv = priv; + + swdev = &priv->dev; + swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU; + swdev->ops = &psb6970_ops; + + swdev->name = "Lantiq PSB6970"; + swdev->vlans = PSB6970_MAX_VLANS; + swdev->ports = PSB6970_NUM_PORTS; + + if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { + kfree(priv); + goto done; + } + + ret = psb6970_reset_switch(&priv->dev); + if (ret) { + kfree(priv); + goto done; + } + +done: + return ret; +} + +static int psb6970_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int psb6970_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int psb6970_probe(struct phy_device *pdev) +{ + return 0; +} + +static void psb6970_remove(struct phy_device *pdev) +{ + struct psb6970_priv *priv = pdev->priv; + + if (!priv) + return; + + if (pdev->mdio.addr == 0) + unregister_switch(&priv->dev); + kfree(priv); +} + +static int psb6970_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK; + if (reg != PSB6970_CI1_VAL) + return 0; + + dev->phy_id = (reg << 16); + dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK; + + return 0; +} + +static struct phy_driver psb6970_driver = { + .name = "Lantiq PSB6970", + .phy_id = PSB6970_CI1_VAL << 16, + .phy_id_mask = 0xffff0000, + .features = PHY_BASIC_FEATURES, + .probe = psb6970_probe, + .remove = psb6970_remove, + .config_init = &psb6970_config_init, + .config_aneg = &psb6970_config_aneg, + .read_status = &psb6970_read_status, +}; + +static int __init psb6970_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup); + return phy_driver_register(&psb6970_driver, THIS_MODULE); +} + +module_init(psb6970_init); + +static void __exit psb6970_exit(void) +{ + phy_driver_unregister(&psb6970_driver); +} + +module_exit(psb6970_exit); + +MODULE_DESCRIPTION("Lantiq PSB6970 Switch"); +MODULE_AUTHOR("Ithamar R. Adema "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/rtk/Makefile b/drivers/net/phy/rtk/Makefile new file mode 100644 index 000000000000..0f2891ead419 --- /dev/null +++ b/drivers/net/phy/rtk/Makefile @@ -0,0 +1,66 @@ +obj-$(CONFIG_RTL8367S_GSW) += rtl8367s_gsw.o +rtl8367s_gsw-objs := rtl8367s_mdio.o rtl8367s_dbg.o +ifeq ($(CONFIG_SWCONFIG),y) +rtl8367s_gsw-objs += rtl8367s.o +endif +rtl8367s_gsw-objs += rtl8367c/acl.o +rtl8367s_gsw-objs += rtl8367c/cpu.o +rtl8367s_gsw-objs += rtl8367c/dot1x.o +rtl8367s_gsw-objs += rtl8367c/eee.o +rtl8367s_gsw-objs += rtl8367c/igmp.o +rtl8367s_gsw-objs += rtl8367c/interrupt.o +rtl8367s_gsw-objs += rtl8367c/l2.o +rtl8367s_gsw-objs += rtl8367c/leaky.o +rtl8367s_gsw-objs += rtl8367c/led.o +rtl8367s_gsw-objs += rtl8367c/mirror.o +rtl8367s_gsw-objs += rtl8367c/oam.o +rtl8367s_gsw-objs += rtl8367c/port.o +rtl8367s_gsw-objs += rtl8367c/ptp.o +rtl8367s_gsw-objs += rtl8367c/qos.o +rtl8367s_gsw-objs += rtl8367c/rate.o +rtl8367s_gsw-objs += rtl8367c/rldp.o +rtl8367s_gsw-objs += rtl8367c/rtk_switch.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_acl.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_cputag.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_dot1x.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eav.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_eee.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_fc.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_green.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_hsb.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_igmp.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_inbwctrl.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_interrupt.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_led.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_lut.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_meter.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mib.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_mirror.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_misc.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_oam.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_phy.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_port.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_portIsolation.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_qos.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rldp.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_rma.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_scheduling.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_storm.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_svlan.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_trunking.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_unknownMulticast.o +rtl8367s_gsw-objs += rtl8367c/rtl8367c_asicdrv_vlan.o +rtl8367s_gsw-objs += rtl8367c/smi.o +rtl8367s_gsw-objs += rtl8367c/stat.o +rtl8367s_gsw-objs += rtl8367c/storm.o +rtl8367s_gsw-objs += rtl8367c/svlan.o +rtl8367s_gsw-objs += rtl8367c/trap.o +rtl8367s_gsw-objs += rtl8367c/trunk.o +rtl8367s_gsw-objs += rtl8367c/vlan.o + +ccflags-y += -Werror -D_LITTLE_ENDIAN -DMDC_MDIO_OPERATION + +ccflags-y += -Idrivers/net/phy/rtk/rtl8367c/include +ccflags-y += -Iinclude/linux/ + diff --git a/drivers/net/phy/rtk/rtl8367c/acl.c b/drivers/net/phy/rtk/rtl8367c/acl.c new file mode 100644 index 000000000000..85c12b000ff8 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/acl.c @@ -0,0 +1,2061 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in ACL module. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +CONST_T rtk_uint8 filter_templateField[RTL8367C_ACLTEMPLATENO][RTL8367C_ACLRULEFIELDNO] = { + {ACL_DMAC0, ACL_DMAC1, ACL_DMAC2, ACL_SMAC0, ACL_SMAC1, ACL_SMAC2, ACL_ETHERTYPE, ACL_FIELD_SELECT15}, + {ACL_IP4SIP0, ACL_IP4SIP1, ACL_IP4DIP0, ACL_IP4DIP1, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT02, ACL_FIELD_SELECT15}, + {ACL_IP6SIP0WITHIPV4, ACL_IP6SIP1WITHIPV4,ACL_FIELD_SELECT03, ACL_FIELD_SELECT04, ACL_FIELD_SELECT05, ACL_FIELD_SELECT06, ACL_FIELD_SELECT07, ACL_FIELD_SELECT08}, + {ACL_IP6DIP0WITHIPV4, ACL_IP6DIP1WITHIPV4,ACL_FIELD_SELECT09, ACL_FIELD_SELECT10, ACL_FIELD_SELECT11, ACL_FIELD_SELECT12, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14}, + {ACL_VIDRANGE, ACL_IPRANGE, ACL_PORTRANGE, ACL_CTAG, ACL_STAG, ACL_FIELD_SELECT13, ACL_FIELD_SELECT14, ACL_FIELD_SELECT15} +}; + +CONST_T rtk_uint8 filter_advanceCaretagField[RTL8367C_ACLTEMPLATENO][2] = { + {TRUE, 7}, + {TRUE, 7}, + {FALSE, 0}, + {FALSE, 0}, + {TRUE, 7}, +}; + + +CONST_T rtk_uint8 filter_fieldTemplateIndex[FILTER_FIELD_END][RTK_FILTER_FIELD_USED_MAX] = { + {0x00, 0x01,0x02}, + {0x03, 0x04,0x05}, + {0x06}, + {0x43}, + {0x44}, + {0x10, 0x11}, + {0x12, 0x13}, + {0x24}, + {0x25}, + {0x35}, + {0x35}, + {0x20, 0x21,0x22,0x23}, + {0x30, 0x31,0x32,0x33}, + {0x26}, + {0x27}, + {0x14}, + {0x15}, + {0x16}, + {0x14}, + {0x15}, + {0x14}, + {0x14}, + {0x14}, + + {0x40}, + {0x41}, + {0x42}, + + {0x14}, + {0x15}, + {0x16}, + {0x22}, + {0x23}, + {0x24}, + {0x25}, + {0x26}, + {0x27}, + {0x32}, + {0x33}, + {0x34}, + {0x35}, + {0x36}, + {0x37}, + {0x47}, + + {0xFF} /* Pattern Match */ +}; + +CONST_T rtk_uint8 filter_fieldSize[FILTER_FIELD_END] = { + 3, 3, 1, 1, 1, + 2, 2, 1, 1, 1, 1, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 8 +}; + +CONST_T rtk_uint16 field_selector[RTL8367C_FIELDSEL_FORMAT_NUMBER][2] = +{ + {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 0 */ + {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 1 */ + {FIELDSEL_FORMAT_IPPAYLOAD, 12}, /* Field Selector 2 */ + {FIELDSEL_FORMAT_IPV6, 10}, /* Field Selector 3 */ + {FIELDSEL_FORMAT_IPV6, 8}, /* Field Selector 4 */ + {FIELDSEL_FORMAT_IPV4, 0}, /* Field Selector 5 */ + {FIELDSEL_FORMAT_IPV4, 8}, /* Field Selector 6 */ + {FIELDSEL_FORMAT_IPV6, 0}, /* Field Selector 7 */ + {FIELDSEL_FORMAT_IPV6, 6}, /* Field Selector 8 */ + {FIELDSEL_FORMAT_IPV6, 26}, /* Field Selector 9 */ + {FIELDSEL_FORMAT_IPV6, 24}, /* Field Selector 10 */ + {FIELDSEL_FORMAT_DEFAULT, 0}, /* Field Selector 11 */ + {FIELDSEL_FORMAT_IPV4, 6}, /* Field Selector 12 */ + {FIELDSEL_FORMAT_IPPAYLOAD, 0}, /* Field Selector 13 */ + {FIELDSEL_FORMAT_IPPAYLOAD, 2}, /* Field Selector 14 */ + {FIELDSEL_FORMAT_DEFAULT, 0} /* Field Selector 15 */ +}; + + +static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr); + + +/* Function Name: + * rtk_filter_igrAcl_init + * Description: + * ACL initialization function + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * Note: + * This function enable and initialize ACL function + */ +rtk_api_ret_t rtk_filter_igrAcl_init(void) +{ + rtl8367c_acltemplate_t aclTemp; + rtk_uint32 i, j; + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((ret = rtk_filter_igrAcl_cfg_delAll()) != RT_ERR_OK) + return ret; + + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + for(j = 0; j < RTL8367C_ACLRULEFIELDNO;j++) + aclTemp.field[j] = filter_templateField[i][j]; + + if ((ret = rtl8367c_setAsicAclTemplate(i, &aclTemp)) != RT_ERR_OK) + return ret; + } + + for(i = 0; i < RTL8367C_FIELDSEL_FORMAT_NUMBER; i++) + { + if ((ret = rtl8367c_setAsicFieldSelector(i, field_selector[i][0], field_selector[i][1])) != RT_ERR_OK) + return ret; + } + + RTK_SCAN_ALL_PHY_PORTMASK(i) + { + if ((ret = rtl8367c_setAsicAcl(i, TRUE)) != RT_ERR_OK) + return ret; + + if ((ret = rtl8367c_setAsicAclUnmatchedPermit(i, TRUE)) != RT_ERR_OK) + return ret; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_field_add + * Description: + * Add comparison rule to an ACL configuration + * Input: + * pFilter_cfg - The ACL configuration that this function will add comparison rule + * pFilter_field - The comparison rule that will be added. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg). + * Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL + * comparison rules by means of linked list. Pointer pFilter_field will be added to linked + * list kept by structure that pFilter_cfg points to. + */ +rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t* pFilter_cfg, rtk_filter_field_t* pFilter_field) +{ + rtk_uint32 i; + rtk_filter_field_t *tailPtr; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pFilter_cfg || NULL == pFilter_field) + return RT_ERR_NULL_POINTER; + + if(pFilter_field->fieldType >= FILTER_FIELD_END) + return RT_ERR_ENTRY_INDEX; + + + if(0 == pFilter_field->fieldTemplateNo) + { + pFilter_field->fieldTemplateNo = filter_fieldSize[pFilter_field->fieldType]; + + for(i = 0; i < pFilter_field->fieldTemplateNo; i++) + { + pFilter_field->fieldTemplateIdx[i] = filter_fieldTemplateIndex[pFilter_field->fieldType][i]; + } + } + + if(NULL == pFilter_cfg->fieldHead) + { + pFilter_cfg->fieldHead = pFilter_field; + } + else + { + if (pFilter_cfg->fieldHead->next == NULL) + { + pFilter_cfg->fieldHead->next = pFilter_field; + } + else + { + tailPtr = pFilter_cfg->fieldHead->next; + while( tailPtr->next != NULL) + { + tailPtr = tailPtr->next; + } + tailPtr->next = pFilter_field; + } + } + + return RT_ERR_OK; +} + +static rtk_api_ret_t _rtk_filter_igrAcl_writeDataField(rtl8367c_aclrule *aclRule, rtk_filter_field_t *fieldPtr) +{ + rtk_uint32 i, tempIdx,fieldIdx, ipValue, ipMask; + rtk_uint32 ip6addr[RTK_IPV6_ADDR_WORD_LENGTH]; + rtk_uint32 ip6mask[RTK_IPV6_ADDR_WORD_LENGTH]; + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + + aclRule[tempIdx].valid = TRUE; + } + + switch (fieldPtr->fieldType) + { + /* use DMAC structure as representative for mac structure */ + case FILTER_FIELD_DMAC: + case FILTER_FIELD_SMAC: + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.value.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.value.octet[5 - (i*2 + 1)] << 8); + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.mac.mask.octet[5 - i*2] | (fieldPtr->filter_pattern_union.mac.mask.octet[5 - (i*2 + 1)] << 8); + } + break; + case FILTER_FIELD_ETHERTYPE: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.etherType.mask; + } + break; + case FILTER_FIELD_IPV4_SIP: + case FILTER_FIELD_IPV4_DIP: + + ipValue = fieldPtr->filter_pattern_union.sip.value; + ipMask = fieldPtr->filter_pattern_union.sip.mask; + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = (0xFFFF & (ipValue >> (i*16))); + aclRule[tempIdx].care_bits.field[fieldIdx] = (0xFFFF & (ipMask >> (i*16))); + } + break; + case FILTER_FIELD_IPV4_TOS: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.value & 0xFF; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.ipTos.mask & 0xFF; + } + break; + case FILTER_FIELD_IPV4_PROTOCOL: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.value & 0xFF; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.protocol.mask & 0xFF; + } + break; + case FILTER_FIELD_IPV6_SIPV6: + case FILTER_FIELD_IPV6_DIPV6: + for(i = 0; i < RTK_IPV6_ADDR_WORD_LENGTH; i++) + { + ip6addr[i] = fieldPtr->filter_pattern_union.sipv6.value.addr[i]; + ip6mask[i] = fieldPtr->filter_pattern_union.sipv6.mask.addr[i]; + } + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + if(i < 2) + { + aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[0] & (0xFFFF << (i * 16))) >> (i * 16)); + aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[0] & (0xFFFF << (i * 16))) >> (i * 16)); + } + else + { + /*default ACL template for ipv6 address supports MSB 32-bits and LSB 32-bits only*/ + aclRule[tempIdx].data_bits.field[fieldIdx] = ((ip6addr[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16)); + aclRule[tempIdx].care_bits.field[fieldIdx] = ((ip6mask[3] & (0xFFFF << ((i&1) * 16))) >> ((i&1) * 16)); + } + } + + break; + case FILTER_FIELD_CTAG: + case FILTER_FIELD_STAG: + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.value << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.value << 12) | fieldPtr->filter_pattern_union.l2tag.vid.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.l2tag.pri.mask << 13) | (fieldPtr->filter_pattern_union.l2tag.cfi.mask << 12) | fieldPtr->filter_pattern_union.l2tag.vid.mask; + } + break; + case FILTER_FIELD_IPV4_FLAG: + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x1FFF; + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.value << 15); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.value << 14); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.value << 13); + + aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x1FFF; + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.xf.mask << 15); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.df.mask << 14); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.ipFlag.mf.mask << 13); + } + + break; + case FILTER_FIELD_IPV4_OFFSET: + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xE000; + aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.value; + + aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xE000; + aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.inData.mask; + } + + break; + + case FILTER_FIELD_IPV6_TRAFFIC_CLASS: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + + aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.value << 4)&0x0FF0; + aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.inData.mask << 4)&0x0FF0; + } + break; + case FILTER_FIELD_IPV6_NEXT_HEADER: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value << 8; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask << 8; + } + break; + case FILTER_FIELD_TCP_SPORT: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpSrcPort.mask; + } + break; + case FILTER_FIELD_TCP_DPORT: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.tcpDstPort.mask; + } + break; + case FILTER_FIELD_TCP_FLAG: + + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.value << 7); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.value << 6); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.value << 5); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.value << 4); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.value << 3); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.value << 2); + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.value << 1); + aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.value; + + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.cwr.mask << 7); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ece.mask << 6); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.urg.mask << 5); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.ack.mask << 4); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.psh.mask << 3); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.rst.mask << 2); + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.tcpFlag.syn.mask << 1); + aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.tcpFlag.fin.mask; + } + break; + case FILTER_FIELD_UDP_SPORT: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpSrcPort.mask; + } + break; + case FILTER_FIELD_UDP_DPORT: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.udpDstPort.mask; + } + break; + case FILTER_FIELD_ICMP_CODE: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] &= 0xFF00; + aclRule[tempIdx].data_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.value; + aclRule[tempIdx].care_bits.field[fieldIdx] &= 0xFF00; + aclRule[tempIdx].care_bits.field[fieldIdx] |= fieldPtr->filter_pattern_union.icmpCode.mask; + } + break; + case FILTER_FIELD_ICMP_TYPE: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] &= 0x00FF; + aclRule[tempIdx].data_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.value << 8); + aclRule[tempIdx].care_bits.field[fieldIdx] &= 0x00FF; + aclRule[tempIdx].care_bits.field[fieldIdx] |= (fieldPtr->filter_pattern_union.icmpType.mask << 8); + } + break; + case FILTER_FIELD_IGMP_TYPE: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.value << 8); + aclRule[tempIdx].care_bits.field[fieldIdx] = (fieldPtr->filter_pattern_union.igmpType.mask << 8); + } + break; + case FILTER_FIELD_PATTERN_MATCH: + for(i = 0; i < fieldPtr->fieldTemplateNo; i++) + { + tempIdx = (fieldPtr->fieldTemplateIdx[i] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[i] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.value[i/2] >> (16 * (i%2))) & 0x0000FFFF ); + aclRule[tempIdx].care_bits.field[fieldIdx] = ((fieldPtr->filter_pattern_union.pattern.mask[i/2] >> (16 * (i%2))) & 0x0000FFFF ); + } + break; + case FILTER_FIELD_VID_RANGE: + case FILTER_FIELD_IP_RANGE: + case FILTER_FIELD_PORT_RANGE: + default: + tempIdx = (fieldPtr->fieldTemplateIdx[0] & 0xF0) >> 4; + fieldIdx = fieldPtr->fieldTemplateIdx[0] & 0x0F; + + aclRule[tempIdx].data_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.value; + aclRule[tempIdx].care_bits.field[fieldIdx] = fieldPtr->filter_pattern_union.inData.mask; + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_cfg_add + * Description: + * Add an ACL configuration to ASIC + * Input: + * filter_id - Start index of ACL configuration. + * pFilter_cfg - The ACL configuration that this function will add comparison rule + * pFilter_action - Action(s) of ACL configuration. + * Output: + * ruleNum - number of rules written in ACL table + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENTRY_INDEX - Invalid filter_id . + * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. + * RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT - Action is not supported in this chip. + * RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT - Rule is not supported. + * Note: + * This function store pFilter_cfg, pFilter_action into ASIC. The starting + * index(es) is filter_id. + */ +rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t* pFilter_cfg, rtk_filter_action_t* pFilter_action, rtk_filter_number_t *ruleNum) +{ + rtk_api_ret_t retVal; + rtk_uint32 careTagData, careTagMask; + rtk_uint32 i,vidx, svidx, actType, ruleId; + rtk_uint32 aclActCtrl; + rtk_uint32 cpuPort; + rtk_filter_field_t* fieldPtr; + rtl8367c_aclrule aclRule[RTL8367C_ACLTEMPLATENO]; + rtl8367c_aclrule tempRule; + rtl8367c_acl_act_t aclAct; + rtk_uint32 noRulesAdd; + rtk_uint32 portmask; + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(filter_id > RTL8367C_ACLRULEMAX ) + return RT_ERR_ENTRY_INDEX; + + if((NULL == pFilter_cfg) || (NULL == pFilter_action) || (NULL == ruleNum)) + return RT_ERR_NULL_POINTER; + + fieldPtr = pFilter_cfg->fieldHead; + + /* init RULE */ + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + memset(&aclRule[i], 0, sizeof(rtl8367c_aclrule)); + + aclRule[i].data_bits.type= i; + aclRule[i].care_bits.type= 0x7; + } + + while(NULL != fieldPtr) + { + _rtk_filter_igrAcl_writeDataField(aclRule, fieldPtr); + + fieldPtr = fieldPtr->next; + } + + /*set care tag mask in User Defined Field 15*/ + /*Follow care tag should not be used while ACL template and User defined fields are fully control by system designer*/ + /*those advanced packet type care tag is used in default template design structure only*/ + careTagData = 0; + careTagMask = 0; + + for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++) + { + if(pFilter_cfg->careTag.tagType[i].mask) + careTagMask = careTagMask | (1 << (i-CARE_TAG_TCP)); + + if(pFilter_cfg->careTag.tagType[i].value) + careTagData = careTagData | (1 << (i-CARE_TAG_TCP)); + } + + if(careTagData || careTagMask) + { + i = 0; + while(i < RTL8367C_ACLTEMPLATENO) + { + if(aclRule[i].valid == 1 && filter_advanceCaretagField[i][0] == TRUE) + { + + aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF; + aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF; + break; + } + i++; + } + /*none of previous used template containing field 15*/ + if(i == RTL8367C_ACLTEMPLATENO) + { + i = 0; + while(i < RTL8367C_ACLTEMPLATENO) + { + if(filter_advanceCaretagField[i][0] == TRUE) + { + aclRule[i].data_bits.field[filter_advanceCaretagField[i][1]] = careTagData & 0xFFFF; + aclRule[i].care_bits.field[filter_advanceCaretagField[i][1]] = careTagMask & 0xFFFF; + aclRule[i].valid = 1; + break; + } + i++; + } + } + } + + /*Check rule number*/ + noRulesAdd = 0; + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + if(1 == aclRule[i].valid) + { + noRulesAdd ++; + } + } + + *ruleNum = noRulesAdd; + + if((filter_id + noRulesAdd - 1) > RTL8367C_ACLRULEMAX) + { + return RT_ERR_ENTRY_INDEX; + } + + /*set care tag mask in TAG Indicator*/ + careTagData = 0; + careTagMask = 0; + + for(i = 0; i <= CARE_TAG_IPV6;i++) + { + if(0 == pFilter_cfg->careTag.tagType[i].mask ) + { + careTagMask &= ~(1 << i); + } + else + { + careTagMask |= (1 << i); + if(0 == pFilter_cfg->careTag.tagType[i].value ) + careTagData &= ~(1 << i); + else + careTagData |= (1 << i); + } + } + + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + aclRule[i].data_bits.tag_exist = (careTagData) & ACL_RULE_CARETAG_MASK; + aclRule[i].care_bits.tag_exist = (careTagMask) & ACL_RULE_CARETAG_MASK; + } + + RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.value); + RTK_CHK_PORTMASK_VALID(&pFilter_cfg->activeport.mask); + + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + if(TRUE == aclRule[i].valid) + { + if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.value, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + + aclRule[i].data_bits.active_portmsk = portmask; + + if(rtk_switch_portmask_L2P_get(&pFilter_cfg->activeport.mask, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + + aclRule[i].care_bits.active_portmsk = portmask; + } + } + + if(pFilter_cfg->invert >= FILTER_INVERT_END ) + return RT_ERR_INPUT; + + + /*Last action gets high priority if actions are the same*/ + memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t)); + aclActCtrl = 0; + for(actType = 0; actType < FILTER_ENACT_END; actType ++) + { + if(pFilter_action->actEnable[actType]) + { + switch (actType) + { + case FILTER_ENACT_CVLAN_INGRESS: + if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX) + return RT_ERR_INPUT; + + if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK) + { + return retVal; + } + aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); + aclAct.cvidx_cact = vidx; + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; + } + + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_CVLAN_EGRESS: + if(pFilter_action->filterCvlanVid > RTL8367C_EVIDMAX) + return RT_ERR_INPUT; + + if((retVal = rtk_vlan_checkAndCreateMbr(pFilter_action->filterCvlanVid, &vidx)) != RT_ERR_OK) + return retVal; + + aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); + aclAct.cvidx_cact = vidx; + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; + } + + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_CVLAN_SVID: + + aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; + } + + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_POLICING_1: + if(pFilter_action->filterPolicingIdx[1] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) + return RT_ERR_INPUT; + + aclAct.cact = FILTER_ENACT_CVLAN_TYPE(actType); + aclAct.cvidx_cact = pFilter_action->filterPolicingIdx[1]; + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_TAGONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_VLANONLY; + } + + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + + case FILTER_ENACT_SVLAN_INGRESS: + case FILTER_ENACT_SVLAN_EGRESS: + + if((retVal = rtk_svlan_checkAndCreateMbr(pFilter_action->filterSvlanVid, &svidx)) != RT_ERR_OK) + return retVal; + + aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); + aclAct.svidx_sact = svidx; + aclActCtrl |= FILTER_ENACT_SVLAN_MASK; + break; + case FILTER_ENACT_SVLAN_CVID: + + aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); + aclActCtrl |= FILTER_ENACT_SVLAN_MASK; + break; + case FILTER_ENACT_POLICING_2: + if(pFilter_action->filterPolicingIdx[2] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) + return RT_ERR_INPUT; + + aclAct.sact = FILTER_ENACT_SVLAN_TYPE(actType); + aclAct.svidx_sact = pFilter_action->filterPolicingIdx[2]; + aclActCtrl |= FILTER_ENACT_SVLAN_MASK; + break; + case FILTER_ENACT_POLICING_0: + if(pFilter_action->filterPolicingIdx[0] >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) + return RT_ERR_INPUT; + + aclAct.aclmeteridx = pFilter_action->filterPolicingIdx[0]; + aclActCtrl |= FILTER_ENACT_POLICING_MASK; + break; + case FILTER_ENACT_PRIORITY: + case FILTER_ENACT_1P_REMARK: + if(pFilter_action->filterPriority > RTL8367C_PRIMAX) + return RT_ERR_INPUT; + + aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); + aclAct.pridx = pFilter_action->filterPriority; + aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; + break; + case FILTER_ENACT_DSCP_REMARK: + if(pFilter_action->filterPriority > RTL8367C_DSCPMAX) + return RT_ERR_INPUT; + + aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); + aclAct.pridx = pFilter_action->filterPriority; + aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; + break; + case FILTER_ENACT_POLICING_3: + if(pFilter_action->filterPriority >= (RTK_METER_NUM + RTL8367C_MAX_LOG_CNT_NUM)) + return RT_ERR_INPUT; + + aclAct.priact = FILTER_ENACT_PRI_TYPE(actType); + aclAct.pridx = pFilter_action->filterPolicingIdx[3]; + aclActCtrl |= FILTER_ENACT_PRIORITY_MASK; + break; + case FILTER_ENACT_DROP: + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_REDIRECT); + aclAct.fwdact_ext = FALSE; + + aclAct.fwdpmask = 0; + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + case FILTER_ENACT_REDIRECT: + RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); + aclAct.fwdact_ext = FALSE; + + if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + aclAct.fwdpmask = portmask; + + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + + case FILTER_ENACT_ADD_DSTPORT: + RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); + aclAct.fwdact_ext = FALSE; + + if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + aclAct.fwdpmask = portmask; + + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + case FILTER_ENACT_MIRROR: + RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); + aclAct.cact_ext = FALSE; + + if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + aclAct.fwdpmask = portmask; + + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + case FILTER_ENACT_TRAP_CPU: + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(actType); + aclAct.fwdact_ext = FALSE; + + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + case FILTER_ENACT_COPY_CPU: + if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK) + return retVal; + + aclAct.fwdact = FILTER_ENACT_FWD_TYPE(FILTER_ENACT_MIRROR); + aclAct.fwdact_ext = FALSE; + + aclAct.fwdpmask = 1 << cpuPort; + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + case FILTER_ENACT_ISOLATION: + RTK_CHK_PORTMASK_VALID(&pFilter_action->filterPortmask); + + aclAct.fwdact_ext = TRUE; + + if(rtk_switch_portmask_L2P_get(&pFilter_action->filterPortmask, &portmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + aclAct.fwdpmask = portmask; + + aclActCtrl |= FILTER_ENACT_FWD_MASK; + break; + + case FILTER_ENACT_INTERRUPT: + + aclAct.aclint = TRUE; + aclActCtrl |= FILTER_ENACT_INTGPIO_MASK; + break; + case FILTER_ENACT_GPO: + + aclAct.gpio_en = TRUE; + aclAct.gpio_pin = pFilter_action->filterPin; + aclActCtrl |= FILTER_ENACT_INTGPIO_MASK; + break; + case FILTER_ENACT_EGRESSCTAG_TAG: + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; + } + aclAct.tag_fmt = FILTER_CTAGFMT_TAG; + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_EGRESSCTAG_UNTAG: + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; + } + aclAct.tag_fmt = FILTER_CTAGFMT_UNTAG; + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_EGRESSCTAG_KEEP: + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; + } + aclAct.tag_fmt = FILTER_CTAGFMT_KEEP; + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + case FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK: + + if(aclActCtrl &(FILTER_ENACT_CVLAN_MASK)) + { + if(aclAct.cact_ext == FILTER_ENACT_CACTEXT_VLANONLY) + aclAct.cact_ext = FILTER_ENACT_CACTEXT_BOTHVLANTAG; + } + else + { + aclAct.cact_ext = FILTER_ENACT_CACTEXT_TAGONLY; + } + aclAct.tag_fmt = FILTER_CTAGFMT_KEEP1PRMK; + aclActCtrl |= FILTER_ENACT_CVLAN_MASK; + break; + default: + return RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT; + } + } + } + + + /*check if free ACL rules are enough*/ + for(i = filter_id; i < (filter_id + noRulesAdd); i++) + { + if((retVal = rtl8367c_getAsicAclRule(i, &tempRule)) != RT_ERR_OK ) + return retVal; + + if(tempRule.valid == TRUE) + { + return RT_ERR_TBL_FULL; + } + } + + ruleId = 0; + for(i = 0; i < RTL8367C_ACLTEMPLATENO; i++) + { + if(aclRule[i].valid == TRUE) + { + /* write ACL action control */ + if((retVal = rtl8367c_setAsicAclActCtrl(filter_id + ruleId, aclActCtrl)) != RT_ERR_OK ) + return retVal; + /* write ACL action */ + if((retVal = rtl8367c_setAsicAclAct(filter_id + ruleId, &aclAct)) != RT_ERR_OK ) + return retVal; + + /* write ACL not */ + if((retVal = rtl8367c_setAsicAclNot(filter_id + ruleId, pFilter_cfg->invert)) != RT_ERR_OK ) + return retVal; + /* write ACL rule */ + if((retVal = rtl8367c_setAsicAclRule(filter_id + ruleId, &aclRule[i])) != RT_ERR_OK ) + return retVal; + + /* only the first rule will be written with input action control, aclActCtrl of other rules will be zero */ + aclActCtrl = 0; + memset(&aclAct, 0, sizeof(rtl8367c_acl_act_t)); + + ruleId ++; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_cfg_del + * Description: + * Delete an ACL configuration from ASIC + * Input: + * filter_id - Start index of ACL configuration. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_ENTRYIDX - Invalid filter_id. + * Note: + * This function delete a group of ACL rules starting from filter_id. + */ +rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id) +{ + rtl8367c_aclrule initRule; + rtl8367c_acl_act_t initAct; + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(filter_id > RTL8367C_ACLRULEMAX ) + return RT_ERR_FILTER_ENTRYIDX; + + memset(&initRule, 0, sizeof(rtl8367c_aclrule)); + memset(&initAct, 0, sizeof(rtl8367c_acl_act_t)); + + if((ret = rtl8367c_setAsicAclRule(filter_id, &initRule)) != RT_ERR_OK) + return ret; + if((ret = rtl8367c_setAsicAclActCtrl(filter_id, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK) + return ret; + if((ret = rtl8367c_setAsicAclAct(filter_id, &initAct)) != RT_ERR_OK) + return ret; + if((ret = rtl8367c_setAsicAclNot(filter_id, DISABLED)) != RT_ERR_OK ) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_cfg_delAll + * Description: + * Delete all ACL entries from ASIC + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This function delete all ACL configuration from ASIC. + */ +rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void) +{ + rtk_uint32 i; + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + for(i = 0; i < RTL8367C_ACLRULENO; i++) + { + if((ret = rtl8367c_setAsicAclActCtrl(i, FILTER_ENACT_INIT_MASK))!= RT_ERR_OK) + return ret; + if((ret = rtl8367c_setAsicAclNot(i, DISABLED)) != RT_ERR_OK ) + return ret; + } + + return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_RESET_CFG, RTL8367C_ACL_RESET_CFG_OFFSET, TRUE);; +} + +/* Function Name: + * rtk_filter_igrAcl_cfg_get + * Description: + * Get one ingress ACL configuration from ASIC. + * Input: + * filter_id - Start index of ACL configuration. + * Output: + * pFilter_cfg - buffer pointer of ingress ACL data + * pFilter_action - buffer pointer of ingress ACL action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. + * RT_ERR_FILTER_ENTRYIDX - Invalid entry index. + * Note: + * This function get configuration from ASIC. + */ +rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction) +{ + rtk_api_ret_t retVal; + rtk_uint32 i, tmp; + rtl8367c_aclrule aclRule; + rtl8367c_acl_act_t aclAct; + rtk_uint32 cpuPort; + rtl8367c_acltemplate_t type; + rtl8367c_svlan_memconf_t svlan_cfg; + rtl8367c_vlanconfiguser vlanMC; + rtk_uint32 phyPmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pFilter_cfg || NULL == pAction) + return RT_ERR_NULL_POINTER; + + if(filter_id > RTL8367C_ACLRULEMAX) + return RT_ERR_ENTRY_INDEX; + + if ((retVal = rtl8367c_getAsicAclRule(filter_id, &aclRule)) != RT_ERR_OK) + return retVal; + + /* Check valid */ + if(aclRule.valid == 0) + { + pFilter_cfg->valid = DISABLED; + return RT_ERR_OK; + } + + phyPmask = aclRule.data_bits.active_portmsk; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.value)) != RT_ERR_OK) + return RT_ERR_FAILED; + + phyPmask = aclRule.care_bits.active_portmsk; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pFilter_cfg->activeport.mask)) != RT_ERR_OK) + return RT_ERR_FAILED; + + for(i = 0; i <= CARE_TAG_IPV6; i++) + { + if(aclRule.data_bits.tag_exist & (1 << i)) + pFilter_cfg->careTag.tagType[i].value = 1; + else + pFilter_cfg->careTag.tagType[i].value = 0; + + if (aclRule.care_bits.tag_exist & (1 << i)) + pFilter_cfg->careTag.tagType[i].mask = 1; + else + pFilter_cfg->careTag.tagType[i].mask = 0; + } + + if(filter_advanceCaretagField[aclRule.data_bits.type][0] == TRUE) + { + /* Advanced Care tag setting */ + for(i = CARE_TAG_TCP; i < CARE_TAG_END; i++) + { + if(aclRule.data_bits.field[filter_advanceCaretagField[aclRule.data_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) ) + pFilter_cfg->careTag.tagType[i].value = 1; + else + pFilter_cfg->careTag.tagType[i].value = 0; + + if(aclRule.care_bits.field[filter_advanceCaretagField[aclRule.care_bits.type][1]] & (0x0001 << (i-CARE_TAG_TCP)) ) + pFilter_cfg->careTag.tagType[i].mask = 1; + else + pFilter_cfg->careTag.tagType[i].mask = 0; + } + } + + for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) + { + pFilter_cfg->careFieldRaw[i] = aclRule.care_bits.field[i]; + pFilter_cfg->dataFieldRaw[i] = aclRule.data_bits.field[i]; + } + + if ((retVal = rtl8367c_getAsicAclNot(filter_id, &tmp))!= RT_ERR_OK) + return retVal; + + pFilter_cfg->invert = tmp; + + pFilter_cfg->valid = aclRule.valid; + + memset(pAction, 0, sizeof(rtk_filter_action_t)); + + if ((retVal = rtl8367c_getAsicAclActCtrl(filter_id, &tmp))!= RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicAclAct(filter_id, &aclAct)) != RT_ERR_OK) + return retVal; + + if(tmp & FILTER_ENACT_FWD_MASK) + { + if(TRUE == aclAct.fwdact_ext) + { + pAction->actEnable[FILTER_ENACT_ISOLATION] = TRUE; + + phyPmask = aclAct.fwdpmask; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) + return RT_ERR_FAILED; + } + else if(aclAct.fwdact == RTL8367C_ACL_FWD_TRAP) + { + pAction->actEnable[FILTER_ENACT_TRAP_CPU] = TRUE; + } + else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRRORFUNTION ) + { + pAction->actEnable[FILTER_ENACT_MIRROR] = TRUE; + + phyPmask = aclAct.fwdpmask; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) + return RT_ERR_FAILED; + } + else if (aclAct.fwdact == RTL8367C_ACL_FWD_REDIRECT) + { + if(aclAct.fwdpmask == 0 ) + pAction->actEnable[FILTER_ENACT_DROP] = TRUE; + else + { + pAction->actEnable[FILTER_ENACT_REDIRECT] = TRUE; + + phyPmask = aclAct.fwdpmask; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) + return RT_ERR_FAILED; + } + } + else if (aclAct.fwdact == RTL8367C_ACL_FWD_MIRROR) + { + if((retVal = rtl8367c_getAsicCputagTrapPort(&cpuPort)) != RT_ERR_OK) + return retVal; + if (aclAct.fwdpmask == (1 << cpuPort)) + { + pAction->actEnable[FILTER_ENACT_COPY_CPU] = TRUE; + } + else + { + pAction->actEnable[FILTER_ENACT_ADD_DSTPORT] = TRUE; + + phyPmask = aclAct.fwdpmask; + if(rtk_switch_portmask_P2L_get(phyPmask,&(pAction->filterPortmask)) != RT_ERR_OK) + return RT_ERR_FAILED; + } + } + else + { + return RT_ERR_FAILED; + } + } + + if(tmp & FILTER_ENACT_POLICING_MASK) + { + pAction->actEnable[FILTER_ENACT_POLICING_0] = TRUE; + pAction->filterPolicingIdx[0] = aclAct.aclmeteridx; + } + + if(tmp & FILTER_ENACT_PRIORITY_MASK) + { + if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_PRIORITY)) + { + pAction->actEnable[FILTER_ENACT_PRIORITY] = TRUE; + pAction->filterPriority = aclAct.pridx; + } + else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_1P_REMARK)) + { + pAction->actEnable[FILTER_ENACT_1P_REMARK] = TRUE; + pAction->filterPriority = aclAct.pridx; + } + else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_DSCP_REMARK)) + { + pAction->actEnable[FILTER_ENACT_DSCP_REMARK] = TRUE; + pAction->filterPriority = aclAct.pridx; + } + else if(aclAct.priact == FILTER_ENACT_PRI_TYPE(FILTER_ENACT_POLICING_3)) + { + pAction->actEnable[FILTER_ENACT_POLICING_3] = TRUE; + pAction->filterPolicingIdx[3] = aclAct.pridx; + } + } + + if(tmp & FILTER_ENACT_SVLAN_MASK) + { + if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_INGRESS)) + { + if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK) + return retVal; + + pAction->actEnable[FILTER_ENACT_SVLAN_INGRESS] = TRUE; + pAction->filterSvlanIdx = aclAct.svidx_sact; + pAction->filterSvlanVid = svlan_cfg.vs_svid; + } + else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_EGRESS)) + { + if((retVal = rtl8367c_getAsicSvlanMemberConfiguration(aclAct.svidx_sact, &svlan_cfg)) != RT_ERR_OK) + return retVal; + + pAction->actEnable[FILTER_ENACT_SVLAN_EGRESS] = TRUE; + pAction->filterSvlanIdx = aclAct.svidx_sact; + pAction->filterSvlanVid = svlan_cfg.vs_svid; + } + else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_SVLAN_CVID)) + pAction->actEnable[FILTER_ENACT_SVLAN_CVID] = TRUE; + else if(aclAct.sact == FILTER_ENACT_SVLAN_TYPE(FILTER_ENACT_POLICING_2)) + { + pAction->actEnable[FILTER_ENACT_POLICING_2] = TRUE; + pAction->filterPolicingIdx[2] = aclAct.svidx_sact; + } + } + + + if(tmp & FILTER_ENACT_CVLAN_MASK) + { + if(FILTER_ENACT_CACTEXT_TAGONLY == aclAct.cact_ext || + FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext ) + { + if(FILTER_CTAGFMT_UNTAG == aclAct.tag_fmt) + { + pAction->actEnable[FILTER_ENACT_EGRESSCTAG_UNTAG] = TRUE; + } + else if(FILTER_CTAGFMT_TAG == aclAct.tag_fmt) + { + pAction->actEnable[FILTER_ENACT_EGRESSCTAG_TAG] = TRUE; + } + else if(FILTER_CTAGFMT_KEEP == aclAct.tag_fmt) + { + pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEP] = TRUE; + } + else if(FILTER_CTAGFMT_KEEP1PRMK== aclAct.tag_fmt) + { + pAction->actEnable[FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK] = TRUE; + } + + } + + if(FILTER_ENACT_CACTEXT_VLANONLY == aclAct.cact_ext || + FILTER_ENACT_CACTEXT_BOTHVLANTAG == aclAct.cact_ext ) + { + if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_INGRESS)) + { + if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK) + return retVal; + + pAction->actEnable[FILTER_ENACT_CVLAN_INGRESS] = TRUE; + pAction->filterCvlanIdx = aclAct.cvidx_cact; + pAction->filterCvlanVid = vlanMC.evid; + } + else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_EGRESS)) + { + if((retVal = rtl8367c_getAsicVlanMemberConfig(aclAct.cvidx_cact, &vlanMC)) != RT_ERR_OK) + return retVal; + + pAction->actEnable[FILTER_ENACT_CVLAN_EGRESS] = TRUE; + pAction->filterCvlanIdx = aclAct.cvidx_cact; + pAction->filterCvlanVid = vlanMC.evid; + } + else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_CVLAN_SVID)) + { + pAction->actEnable[FILTER_ENACT_CVLAN_SVID] = TRUE; + } + else if(aclAct.cact == FILTER_ENACT_CVLAN_TYPE(FILTER_ENACT_POLICING_1)) + { + pAction->actEnable[FILTER_ENACT_POLICING_1] = TRUE; + pAction->filterPolicingIdx[1] = aclAct.cvidx_cact; + } + } + } + + if(tmp & FILTER_ENACT_INTGPIO_MASK) + { + if(TRUE == aclAct.aclint) + { + pAction->actEnable[FILTER_ENACT_INTERRUPT] = TRUE; + } + + if(TRUE == aclAct.gpio_en) + { + pAction->actEnable[FILTER_ENACT_GPO] = TRUE; + pAction->filterPin = aclAct.gpio_pin; + } + } + + /* Get field type of RAW data */ + if ((retVal = rtl8367c_getAsicAclTemplate(aclRule.data_bits.type, &type))!= RT_ERR_OK) + return retVal; + + for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) + { + pFilter_cfg->fieldRawType[i] = type.field[i]; + }/* end of for(i...) */ + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_unmatchAction_set + * Description: + * Set action to packets when no ACL configuration match + * Input: + * port - Port id. + * action - Action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function sets action of packets when no ACL configuration matches. + */ +rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(action >= FILTER_UNMATCH_END) + return RT_ERR_INPUT; + + if((ret = rtl8367c_setAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), action)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_unmatchAction_get + * Description: + * Get action to packets when no ACL configuration match + * Input: + * port - Port id. + * Output: + * pAction - Action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configruation matches. + */ +rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* pAction) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if((ret = rtl8367c_getAsicAclUnmatchedPermit(rtk_switch_port_L2P_get(port), pAction)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_state_set + * Description: + * Set state of ingress ACL. + * Input: + * port - Port id. + * state - Ingress ACL state. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configuration matches. + */ +rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(state >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if((ret = rtl8367c_setAsicAcl(rtk_switch_port_L2P_get(port), state)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_state_get + * Description: + * Get state of ingress ACL. + * Input: + * port - Port id. + * Output: + * pState - Ingress ACL state. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configuration matches. + */ +rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* pState) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pState) + return RT_ERR_NULL_POINTER; + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if((ret = rtl8367c_getAsicAcl(rtk_switch_port_L2P_get(port), pState)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} +/* Function Name: + * rtk_filter_igrAcl_template_set + * Description: + * Set template of ingress ACL. + * Input: + * template - Ingress ACL template + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function set ACL template. + */ +rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate) +{ + rtk_api_ret_t retVal; + rtk_uint32 idxField; + rtl8367c_acltemplate_t aclType; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE) + return RT_ERR_INPUT; + + for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++) + { + if(aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_DMAC_15_0 || + (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_CTAG && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV4_SIP_15_0 ) || + (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV4_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_IPV6_SIP_15_0 ) || + (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_IPV6_DIP_31_16 && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_VIDRANGE ) || + (aclTemplate->fieldType[idxField] > FILTER_FIELD_RAW_FIELD_VALID && aclTemplate->fieldType[idxField] < FILTER_FIELD_RAW_FIELD_SELECT00 ) || + aclTemplate->fieldType[idxField] >= FILTER_FIELD_RAW_END) + { + return RT_ERR_INPUT; + } + } + + for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField++) + { + aclType.field[idxField] = aclTemplate->fieldType[idxField]; + } + + if((retVal = rtl8367c_setAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_template_get + * Description: + * Get template of ingress ACL. + * Input: + * template - Ingress ACL template + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This function gets template of ACL. + */ +rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate) +{ + rtk_api_ret_t ret; + rtk_uint32 idxField; + rtl8367c_acltemplate_t aclType; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == aclTemplate) + return RT_ERR_NULL_POINTER; + + if(aclTemplate->index >= RTK_MAX_NUM_OF_FILTER_TYPE) + return RT_ERR_INPUT; + + if((ret = rtl8367c_getAsicAclTemplate(aclTemplate->index, &aclType)) != RT_ERR_OK) + return ret; + + for(idxField = 0; idxField < RTK_MAX_NUM_OF_FILTER_FIELD; idxField ++) + { + aclTemplate->fieldType[idxField] = aclType.field[idxField]; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_field_sel_set + * Description: + * Set user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * format - Format of field selector + * offset - Retrieving data offset + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * System support 16 user defined field selectors. + * Each selector can be enabled or disable. + * User can defined retrieving 16-bits in many predefiend + * standard l2/l3/l4 payload. + */ +rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + if(format >= FORMAT_END) + return RT_ERR_OUT_OF_RANGE; + + if(offset > RTL8367C_FIELDSEL_MAX_OFFSET) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_setAsicFieldSelector(index, (rtk_uint32)format, offset)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAcl_field_sel_get + * Description: + * Get user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * Output: + * pFormat - Format of field selector + * pOffset - Retrieving data offset + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pFormat || NULL == pOffset) + return RT_ERR_NULL_POINTER; + + if(index >= RTL8367C_FIELDSEL_FORMAT_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_getAsicFieldSelector(index, pFormat, pOffset)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_iprange_set + * Description: + * Set IP Range check + * Input: + * index - index of IP Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP + * upperIp - The upper bound of IP range + * lowerIp - The lower Bound of IP range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperIp must be larger or equal than lowerIp. + */ +rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(type >= IPRANGE_END) + return RT_ERR_OUT_OF_RANGE; + + if(lowerIp > upperIp) + return RT_ERR_INPUT; + + if((ret = rtl8367c_setAsicAclIpRange(index, type, upperIp, lowerIp)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_iprange_get + * Description: + * Set IP Range check + * Input: + * index - index of IP Range 0-15 + * Output: + * pType - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP + * pUpperIp - The upper bound of IP range + * pLowerIp - The lower Bound of IP range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * Note: + * None. + */ +rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if((NULL == pType) || (NULL == pUpperIp) || (NULL == pLowerIp)) + return RT_ERR_NULL_POINTER; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_getAsicAclIpRange(index, pType, pUpperIp, pLowerIp)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_vidrange_set + * Description: + * Set VID Range check + * Input: + * index - index of VID Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID + * upperVid - The upper bound of VID range + * lowerVid - The lower Bound of VID range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperVid must be larger or equal than lowerVid. + */ +rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(type >= VIDRANGE_END) + return RT_ERR_OUT_OF_RANGE; + + if(lowerVid > upperVid) + return RT_ERR_INPUT; + + if( (upperVid > RTL8367C_VIDMAX) || (lowerVid > RTL8367C_VIDMAX)) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_setAsicAclVidRange(index, type, upperVid, lowerVid)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_vidrange_get + * Description: + * Get VID Range check + * Input: + * index - index of VID Range 0-15 + * Output: + * pType - IP Range check type, 0:Unused, 1: CVID, 2: SVID + * pUpperVid - The upper bound of VID range + * pLowerVid - The lower Bound of VID range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * Note: + * None. + */ +rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if((NULL == pType) || (NULL == pUpperVid) || (NULL == pLowerVid)) + return RT_ERR_NULL_POINTER; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_getAsicAclVidRange(index, pType, pUpperVid, pLowerVid)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_portrange_set + * Description: + * Set Port Range check + * Input: + * index - index of Port Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port + * upperPort - The upper bound of Port range + * lowerPort - The lower Bound of Port range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperPort must be larger or equal than lowerPort. + */ +rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(type >= PORTRANGE_END) + return RT_ERR_OUT_OF_RANGE; + + if(lowerPort > upperPort) + return RT_ERR_INPUT; + + if(upperPort > RTL8367C_ACL_PORTRANGEMAX) + return RT_ERR_INPUT; + + if(lowerPort > RTL8367C_ACL_PORTRANGEMAX) + return RT_ERR_INPUT; + + if((ret = rtl8367c_setAsicAclPortRange(index, type, upperPort, lowerPort)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_portrange_get + * Description: + * Set Port Range check + * Input: + * index - index of Port Range 0-15 + * Output: + * pType - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port + * pUpperPort - The upper bound of Port range + * pLowerPort - The lower Bound of Port range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * None. + */ +rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort) +{ + rtk_api_ret_t ret; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if((NULL == pType) || (NULL == pUpperPort) || (NULL == pLowerPort)) + return RT_ERR_NULL_POINTER; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + if((ret = rtl8367c_getAsicAclPortRange(index, pType, pUpperPort, pLowerPort)) != RT_ERR_OK) + return ret; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_filter_igrAclPolarity_set + * Description: + * Set ACL Goip control polarity + * Input: + * polarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity) +{ + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(polarity > 1) + return RT_ERR_OUT_OF_RANGE; + return rtl8367c_setAsicAclGpioPolarity(polarity); +} +/* Function Name: + * rtk_filter_igrAclPolarity_get + * Description: + * Get ACL Goip control polarity + * Input: + * pPolarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity) +{ + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPolarity) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicAclGpioPolarity(pPolarity); +} + + + + diff --git a/drivers/net/phy/rtk/rtl8367c/cpu.c b/drivers/net/phy/rtk/rtl8367c/cpu.c new file mode 100644 index 000000000000..b031cbe920eb --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/cpu.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in CPU module. + * + */ + +#include +#include +#include +#include + +#include +#include + +/* Function Name: + * rtk_cpu_enable_set + * Description: + * Set CPU port function enable/disable. + * Input: + * enable - CPU port function enable + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can set CPU port function enable/disable. + */ +rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicCputagEnable(enable)) != RT_ERR_OK) + return retVal; + + if (DISABLED == enable) + { + if ((retVal = rtl8367c_setAsicCputagPortmask(0)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_enable_get + * Description: + * Get CPU port and its setting. + * Input: + * None + * Output: + * pEnable - CPU port function enable + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist + * Note: + * The API can get CPU port function enable/disable. + */ +rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicCputagEnable(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_tagPort_set + * Description: + * Set CPU port and CPU tag insert mode. + * Input: + * port - Port id. + * mode - CPU tag insert for packets egress from CPU port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899) + * to the frame that transmitting to CPU port. + * The insert CPU tag mode is as following: + * - CPU_INSERT_TO_ALL + * - CPU_INSERT_TO_TRAPPING + * - CPU_INSERT_TO_NONE + */ +rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (mode >= CPU_INSERT_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicCputagPortmask(1<= CPU_POS_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicCputagPosition(position)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_tagPosition_get + * Description: + * Get CPU tag position. + * Input: + * None + * Output: + * pPosition - CPU tag position. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU tag position. + */ +rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPosition) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicCputagPosition(pPosition)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_tagLength_set + * Description: + * Set CPU tag length. + * Input: + * length - CPU tag length. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can set CPU tag length. + */ +rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (length >= CPU_LEN_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicCputagMode(length)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_tagLength_get + * Description: + * Get CPU tag length. + * Input: + * None + * Output: + * pLength - CPU tag length. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU tag length. + */ +rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pLength) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicCputagMode(pLength)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_priRemap_set + * Description: + * Configure CPU priorities mapping to internal absolute priority. + * Input: + * int_pri - internal priority value. + * new_pri - new internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (new_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if ((retVal = rtl8367c_setAsicCputagPriorityRemapping(int_pri, new_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_priRemap_get + * Description: + * Configure CPU priorities mapping to internal absolute priority. + * Input: + * int_pri - internal priority value. + * Output: + * pNew_pri - new internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pNew_pri) + return RT_ERR_NULL_POINTER; + + if (int_pri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_getAsicCputagPriorityRemapping(int_pri, pNew_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_acceptLength_set + * Description: + * Set CPU accept length. + * Input: + * length - CPU tag length. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can set CPU accept length. + */ +rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (length >= CPU_RX_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicCputagRxMinLength(length)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_cpu_acceptLength_get + * Description: + * Get CPU accept length. + * Input: + * None + * Output: + * pLength - CPU tag length. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU accept length. + */ +rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pLength) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicCputagRxMinLength(pLength)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/dot1x.c b/drivers/net/phy/rtk/rtl8367c/dot1x.c new file mode 100644 index 000000000000..c9b146a6d887 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/dot1x.c @@ -0,0 +1,843 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 75783 $ + * $Date: 2017-02-13 14:54:53 +0800 (週一, 13 二月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in 1X module. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function Name: + * rtk_dot1x_unauthPacketOper_set + * Description: + * Set 802.1x unauth action configuration. + * Input: + * port - Port id. + * unauth_action - 802.1X unauth action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * This API can set 802.1x unauth action configuration. + * The unauth action is as following: + * - DOT1X_ACTION_DROP + * - DOT1X_ACTION_TRAP2CPU + * - DOT1X_ACTION_GUESTVLAN + */ +rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (unauth_action >= DOT1X_ACTION_END) + return RT_ERR_DOT1X_PROC; + + if ((retVal = rtl8367c_setAsic1xProcConfig(rtk_switch_port_L2P_get(port), unauth_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_unauthPacketOper_get + * Description: + * Get 802.1x unauth action configuration. + * Input: + * port - Port id. + * Output: + * pUnauth_action - 802.1X unauth action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get 802.1x unauth action configuration. + * The unauth action is as following: + * - DOT1X_ACTION_DROP + * - DOT1X_ACTION_TRAP2CPU + * - DOT1X_ACTION_GUESTVLAN + */ +rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pUnauth_action) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsic1xProcConfig(rtk_switch_port_L2P_get(port), pUnauth_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_eapolFrame2CpuEnable_set + * Description: + * Set 802.1x EAPOL packet trap to CPU configuration + * Input: + * enable - The status of 802.1x EAPOL packet. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to + * be trapped to CPU. + * The status of EAPOL frame trap to CPU is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK) + return retVal; + + if (ENABLED == enable) + rmacfg.operation = RMAOP_TRAP_TO_CPU; + else if (DISABLED == enable) + rmacfg.operation = RMAOP_FORWARD; + + if ((retVal = rtl8367c_setAsicRma(3, &rmacfg)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_eapolFrame2CpuEnable_get + * Description: + * Get 802.1x EAPOL packet trap to CPU configuration + * Input: + * None + * Output: + * pEnable - The status of 802.1x EAPOL packet. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to + * be trapped to CPU. + * The status of EAPOL frame trap to CPU is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicRma(3, &rmacfg)) != RT_ERR_OK) + return retVal; + + if (RMAOP_TRAP_TO_CPU == rmacfg.operation) + *pEnable = ENABLED; + else + *pEnable = DISABLED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedEnable_set + * Description: + * Set 802.1x port-based enable configuration + * Input: + * port - Port id. + * enable - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_PORTBASEDPNEN - 802.1X port-based enable error + * Note: + * The API can update the port-based port enable register content. If a port is 802.1x + * port based network access control "enabled", it should be authenticated so packets + * from that port won't be dropped or trapped to CPU. + * The status of 802.1x port-based network access control is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsic1xPBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedEnable_get + * Description: + * Get 802.1x port-based enable configuration + * Input: + * port - Port id. + * Output: + * pEnable - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get the 802.1x port-based port status. + */ +rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsic1xPBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedAuthStatus_set + * Description: + * Set 802.1x port-based auth. port configuration + * Input: + * port - Port id. + * port_auth - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_DOT1X_PORTBASEDAUTH - 802.1X port-based auth error + * Note: + * The authenticated status of 802.1x port-based network access control is as following: + * - UNAUTH + * - AUTH + */ +rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (port_auth >= AUTH_STATUS_END) + return RT_ERR_DOT1X_PORTBASEDAUTH; + + if ((retVal = rtl8367c_setAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), port_auth)) != RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedAuthStatus_get + * Description: + * Get 802.1x port-based auth. port configuration + * Input: + * port - Port id. + * Output: + * pPort_auth - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1x port-based port auth.information. + */ +rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPort_auth) + return RT_ERR_NULL_POINTER; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsic1xPBAuthConfig(rtk_switch_port_L2P_get(port), pPort_auth)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedDirection_set + * Description: + * Set 802.1x port-based operational direction configuration + * Input: + * port - Port id. + * port_direction - Operation direction + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error + * Note: + * The operate controlled direction of 802.1x port-based network access control is as following: + * - BOTH + * - IN + */ +rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (port_direction >= DIRECTION_END) + return RT_ERR_DOT1X_PORTBASEDOPDIR; + + if ((retVal = rtl8367c_setAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), port_direction)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_portBasedDirection_get + * Description: + * Get 802.1X port-based operational direction configuration + * Input: + * port - Port id. + * Output: + * pPort_direction - Operation direction + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1x port-based operational direction information. + */ +rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPort_direction) + return RT_ERR_NULL_POINTER; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsic1xPBOpdirConfig(rtk_switch_port_L2P_get(port), pPort_direction)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_macBasedEnable_set + * Description: + * Set 802.1x mac-based port enable configuration + * Input: + * port - Port id. + * enable - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error + * Note: + * If a port is 802.1x MAC based network access control "enabled", the incoming packets should + * be authenticated so packets from that port won't be dropped or trapped to CPU. + * The status of 802.1x MAC-based network access control is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsic1xMBEnConfig(rtk_switch_port_L2P_get(port),enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_macBasedEnable_get + * Description: + * Get 802.1x mac-based port enable configuration + * Input: + * port - Port id. + * Output: + * pEnable - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * If a port is 802.1x MAC based network access control "enabled", the incoming packets should + * be authenticated so packets from that port wont be dropped or trapped to CPU. + * The status of 802.1x MAC-based network access control is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsic1xMBEnConfig(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_macBasedAuthMac_add + * Description: + * Add an authenticated MAC to ASIC + * Input: + * port - Port id. + * pAuth_mac - The authenticated MAC. + * fid - filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error + * Note: + * The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, + * user can't add this MAC to auth status. + */ +rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* must be unicast address */ + if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1)) + return RT_ERR_MAC; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); + l2Table.fid = fid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if ( RT_ERR_OK == retVal) + { + if (l2Table.spa != rtk_switch_port_L2P_get(port)) + return RT_ERR_DOT1X_MAC_PORT_MISMATCH; + + memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); + l2Table.fid = fid; + l2Table.efid = 0; + l2Table.auth = 1; + retVal = rtl8367c_setAsicL2LookupTb(&l2Table); + return retVal; + } + else + return retVal; + +} + +/* Function Name: + * rtk_dot1x_macBasedAuthMac_del + * Description: + * Delete an authenticated MAC to ASIC + * Input: + * port - Port id. + * pAuth_mac - The authenticated MAC. + * fid - filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of + * the MAC and won't delete it from LUT. + */ +rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* must be unicast address */ + if ((pAuth_mac == NULL) || (pAuth_mac->octet[0] & 0x1)) + return RT_ERR_MAC; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); + l2Table.fid = fid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + if (l2Table.spa != rtk_switch_port_L2P_get(port)) + return RT_ERR_DOT1X_MAC_PORT_MISMATCH; + + memcpy(l2Table.mac.octet, pAuth_mac->octet, ETHER_ADDR_LEN); + l2Table.fid = fid; + l2Table.auth = 0; + retVal = rtl8367c_setAsicL2LookupTb(&l2Table); + return retVal; + } + else + return retVal; + +} + +/* Function Name: + * rtk_dot1x_macBasedDirection_set + * Description: + * Set 802.1x mac-based operational direction configuration + * Input: + * mac_direction - Operation direction + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_DOT1X_MACBASEDOPDIR - 802.1X mac-based operation direction error + * Note: + * The operate controlled direction of 802.1x mac-based network access control is as following: + * - BOTH + * - IN + */ +rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (mac_direction >= DIRECTION_END) + return RT_ERR_DOT1X_MACBASEDOPDIR; + + if ((retVal = rtl8367c_setAsic1xMBOpdirConfig(mac_direction)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_macBasedDirection_get + * Description: + * Get 802.1x mac-based operational direction configuration + * Input: + * port - Port id. + * Output: + * pMac_direction - Operation direction + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x mac-based operational direction information. + */ +rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMac_direction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsic1xMBOpdirConfig(pMac_direction)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * Set 802.1x guest VLAN configuration + * Description: + * Set 802.1x mac-based operational direction configuration + * Input: + * vid - 802.1x guest VLAN ID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The operate controlled 802.1x guest VLAN + */ +rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid) +{ + rtk_api_ret_t retVal; + rtk_uint32 index; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~4095 */ + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if((retVal = rtk_vlan_checkAndCreateMbr(vid, &index)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsic1xGuestVidx(index)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_guestVlan_get + * Description: + * Get 802.1x guest VLAN configuration + * Input: + * None + * Output: + * pVid - 802.1x guest VLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x guest VLAN information. + */ +rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid) +{ + rtk_api_ret_t retVal; + rtk_uint32 gvidx; + rtl8367c_vlanconfiguser vlanMC; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pVid) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsic1xGuestVidx(&gvidx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicVlanMemberConfig(gvidx, &vlanMC)) != RT_ERR_OK) + return retVal; + + *pVid = vlanMC.evid; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_guestVlan2Auth_set + * Description: + * Set 802.1x guest VLAN to auth host configuration + * Input: + * enable - The status of guest VLAN to auth host. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The operational direction of 802.1x guest VLAN to auth host control is as following: + * - ENABLED + * - DISABLED + */ +rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsic1xGVOpdir(enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_dot1x_guestVlan2Auth_get + * Description: + * Get 802.1x guest VLAN to auth host configuration + * Input: + * None + * Output: + * pEnable - The status of guest VLAN to auth host. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x guest VLAN to auth host information. + */ +rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsic1xGVOpdir(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/eee.c b/drivers/net/phy/rtk/rtl8367c/eee.c new file mode 100644 index 000000000000..cd14c2ce1325 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/eee.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 48156 $ + * $Date: 2014-05-29 16:39:06 +0800 (週四, 29 五月 2014) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in EEE module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* Function Name: + * rtk_eee_init + * Description: + * EEE function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API is used to initialize EEE status. + */ +rtk_api_ret_t rtk_eee_init(void) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if((retVal = rtl8367c_setAsicRegBit(0x0018, 10, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x0018, 11, 1)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_eee_portEnable_set + * Description: + * Set enable status of EEE function. + * Input: + * port - port id. + * enable - enable EEE status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set EEE function to the specific port. + * The configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + rtk_uint32 phy_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port is UTP port */ + RTK_CHK_PORT_IS_UTP(port); + + if (enable>=RTK_ENABLE_END) + return RT_ERR_INPUT; + + phy_port = rtk_switch_port_L2P_get(port); + + if ((retVal = rtl8367c_setAsicEee100M(phy_port,enable))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicEeeGiga(phy_port,enable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPHYReg(phy_port, RTL8367C_PHY_PAGE_ADDRESS, 0))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicPHYReg(phy_port, 0, ®Data))!=RT_ERR_OK) + return retVal; + regData |= 0x0200; + if ((retVal = rtl8367c_setAsicPHYReg(phy_port, 0, regData))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_eee_portEnable_get + * Description: + * Get enable status of EEE function + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get EEE function to the specific port. + * The configuration of the port is as following: + * - DISABLE + * - ENABLE + */ + +rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData1, regData2; + rtk_uint32 phy_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port is UTP port */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + phy_port = rtk_switch_port_L2P_get(port); + + if ((retVal = rtl8367c_getAsicEee100M(phy_port,®Data1))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicEeeGiga(phy_port,®Data2))!=RT_ERR_OK) + return retVal; + + if (regData1==1&®Data2==1) + *pEnable = ENABLED; + else + *pEnable = DISABLED; + + return RT_ERR_OK; +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/i2c.c b/drivers/net/phy/rtk/rtl8367c/i2c.c new file mode 100644 index 000000000000..17a5f3785bd4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/i2c.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 63932 $ + * $Date: 2015-12-08 14:06:29 +0800 (周二, 08 十二月 2015) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in i2c module. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +static rtk_I2C_16bit_mode_t rtk_i2c_mode = I2C_LSB_16BIT_MODE; + + +/* Function Name: + * rtk_i2c_init + * Description: + * I2C smart function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * Note: + * This API is used to initialize EEE status. + * need used GPIO pins + * OpenDrain and clock + */ +rtk_api_ret_t rtk_i2c_init(void) +{ + rtk_uint32 retVal; + switch_chip_t ChipID; + /* probe switch */ + if((retVal = rtk_switch_probe(&ChipID)) != RT_ERR_OK) + return retVal; + + if( ChipID == CHIP_RTL8370B ) + { + /*set GPIO8, GPIO9, OpenDrain as I2C, clock = 252KHZ */ + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, 0x5c3f)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_FAILED; + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_i2c_mode_set + * Description: + * Set I2C data byte-order. + * Input: + * i2cmode - byte-order mode + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * This API can set I2c traffic's byte-order . + */ +rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode ) +{ + if(i2cmode >= I2C_Mode_END) + { + return RT_ERR_INPUT; + } + else if(i2cmode == I2C_70B_LSB_16BIT_MODE) + { + rtk_i2c_mode = I2C_70B_LSB_16BIT_MODE; + + return RT_ERR_OK; + } + else if( i2cmode == I2C_LSB_16BIT_MODE) + { + rtk_i2c_mode = I2C_LSB_16BIT_MODE; + return RT_ERR_OK; + } + else + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_i2c_mode_get + * Description: + * Get i2c traffic byte-order setting. + * Input: + * None + * Output: + * pI2cMode - i2c byte-order + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can get i2c traffic byte-order setting. + */ +rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode) +{ + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + if(NULL == pI2cMode) + return RT_ERR_NULL_POINTER; + if(rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) + *pI2cMode = 1; + else if ((rtk_i2c_mode == I2C_LSB_16BIT_MODE)) + *pI2cMode = 0; + else + return RT_ERR_FAILED; + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_i2c_gpioPinGroup_set + * Description: + * Set i2c SDA & SCL used GPIO pins group. + * Input: + * pins_group - GPIO pins group + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The API can set i2c used gpio pins group. + * There are three group pins could be used + */ +rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group ) +{ + rtk_uint32 retVal; + + + if( ( pins_group > I2C_GPIO_PIN_END )|| ( pins_group < I2C_GPIO_PIN_8_9) ) + return RT_ERR_INPUT; + + if( (retVal = rtl8367c_setAsicI2CGpioPinGroup(pins_group) ) != RT_ERR_OK ) + return retVal ; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_i2c_gpioPinGroup_get + * Description: + * Get i2c SDA & SCL used GPIO pins group. + * Input: + * None + * Output: + * pPins_group - GPIO pins group + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can get i2c used gpio pins group. + * There are three group pins could be used + */ +rtk_api_ret_t rtk_i2c_gpioPinGroup_get( rtk_I2C_gpio_pin_t * pPins_group ) +{ + rtk_uint32 retVal; + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPins_group) + return RT_ERR_NULL_POINTER; + if( (retVal = rtl8367c_getAsicI2CGpioPinGroup(pPins_group) ) != RT_ERR_OK ) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_i2c_data_read + * Description: + * read i2c slave device register. + * Input: + * deviceAddr - access Slave device address + * slaveRegAddr - access Slave register address + * Output: + * pRegData - read data + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can access i2c slave and read i2c slave device register. + */ +rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData) +{ + rtk_uint32 retVal, counter=0; + rtk_uint8 controlByte_W, controlByte_R; + rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp; + rtk_uint8 regData_L, regData_H; + + /* control byte :deviceAddress + W, deviceAddress + R */ + controlByte_W = (rtk_uint8)(deviceAddr << 1) ; + controlByte_R = (rtk_uint8)(controlByte_W | 0x1); + + slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ; + slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ; + + if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) + { + temp = slaveRegAddr_L ; + slaveRegAddr_L = slaveRegAddr_H; + slaveRegAddr_H = temp; + } + + + /*check bus state: idle*/ + for(counter = 3000; counter>0; counter--) + { + if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK) + break; + } + if( counter ==0 ) + return retVal; /*i2c is busy*/ + + /*tx Start cmd*/ + if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) + return retVal ; + + + /*tx control _W*/ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK ) + return retVal ; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + /* tx slave buffer address low 8 bits */ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK ) + return retVal ; + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + + /* tx slave buffer address high 8 bits */ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK ) + return retVal ; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /*tx Start cmd*/ + if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) + return retVal ; + + /*tx control _R*/ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_R))!= RT_ERR_OK ) + return retVal ; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /* rx low 8bit data*/ + if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( ®Data_L) ) != RT_ERR_OK ) + return retVal; + + + + /* tx ack to slave, keep receive */ + if( (retVal = rtl8367c_setAsicI2CTxAckCmd()) != RT_ERR_OK ) + return retVal; + + /* rx high 8bit data*/ + if( ( retVal = rtl8367c_setAsicI2CRxOneCharCmd( ®Data_H) ) != RT_ERR_OK ) + return retVal; + + + + /* tx Noack to slave, Stop receive */ + if( (retVal = rtl8367c_setAsicI2CTxNoAckCmd()) != RT_ERR_OK ) + return retVal; + + + /*tx Stop cmd */ + if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK ) + return retVal; + + *pRegData = (regData_H << 8) | regData_L; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_i2c_data_write + * Description: + * write data to i2c slave device register + * Input: + * deviceAddr - access Slave device address + * slaveRegAddr - access Slave register address + * regData - data to set + * Output: + * None + * Return: + * RT_ERR_OK - OK + * Note: + * The API can access i2c slave and setting i2c slave device register. + */ +rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData) +{ + rtk_uint32 retVal,counter; + rtk_uint8 controlByte_W; + rtk_uint8 slaveRegAddr_L, slaveRegAddr_H = 0x0, temp; + rtk_uint8 regData_L, regData_H; + + /* control byte :deviceAddress + W */ + controlByte_W = (rtk_uint8)(deviceAddr<< 1) ; + + slaveRegAddr_L = (rtk_uint8) (slaveRegAddr & 0x00FF) ; + slaveRegAddr_H = (rtk_uint8) (slaveRegAddr >>8) ; + + regData_H = (rtk_uint8) (regData>> 8); + regData_L = (rtk_uint8) (regData & 0x00FF); + + if( rtk_i2c_mode == I2C_70B_LSB_16BIT_MODE) + { + temp = slaveRegAddr_L ; + slaveRegAddr_L = slaveRegAddr_H; + slaveRegAddr_H = temp; + } + + + /*check bus state: idle*/ + for(counter = 3000; counter>0; counter--) + { + if ( (retVal = rtl8367c_setAsicI2C_checkBusIdle() ) == RT_ERR_OK) + break; + } + + if( counter ==0 ) + return retVal; /*i2c is busy*/ + + + /*tx Start cmd*/ + if( (retVal = rtl8367c_setAsicI2CStartCmd() ) != RT_ERR_OK ) + return retVal ; + + + /*tx control _W*/ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(controlByte_W))!= RT_ERR_OK ) + return retVal ; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /* tx slave buffer address low 8 bits */ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_L))!= RT_ERR_OK ) + return retVal; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /* tx slave buffer address high 8 bits */ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(slaveRegAddr_H))!= RT_ERR_OK ) + return retVal; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /*tx Datavlue LSB*/ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_L))!= RT_ERR_OK ) + return retVal; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /*tx Datavlue MSB*/ + if( (retVal = rtl8367c_setAsicI2CTxOneCharCmd(regData_H))!= RT_ERR_OK ) + return retVal; + + + /*check if RX ack from slave*/ + if( (retVal = rtl8367c_setAsicI2CcheckRxAck()) != RT_ERR_OK ) + return retVal; + + + /*tx Stop cmd */ + if( (retVal = rtl8367c_setAsicI2CStopCmd()) != RT_ERR_OK ) + return retVal; + + return RT_ERR_OK; +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/igmp.c b/drivers/net/phy/rtk/rtl8367c/igmp.c new file mode 100644 index 000000000000..18e145a21c8c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/igmp.c @@ -0,0 +1,1555 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in IGMP module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + + +/* Function Name: + * rtk_igmp_init + * Description: + * This API enables H/W IGMP and set a default initial configuration. + * Input: + * None. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API enables H/W IGMP and set a default initial configuration. + */ +rtk_api_ret_t rtk_igmp_init(void) +{ + rtk_api_ret_t retVal; + rtk_port_t port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) + return retVal; + + RTK_SCAN_ALL_PHY_PORTMASK(port) + { + if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicMLDv1Opeartion(port, PROTOCOL_OP_ASIC))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicMLDv2Opeartion(port, PROTOCOL_OP_FLOOD))!=RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_switch_phyPortMask_get()))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn(ENABLED))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(1))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIgmp(ENABLED))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_state_set + * Description: + * This API set H/W IGMP state. + * Input: + * enabled - H/W IGMP state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set H/W IGMP state. + */ +rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enabled >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIgmp(enabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_state_get + * Description: + * This API get H/W IGMP state. + * Input: + * None. + * Output: + * pEnabled - H/W IGMP state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current H/W IGMP state. + */ +rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pEnabled == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIgmp(pEnabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_static_router_port_set + * Description: + * Configure static router port + * Input: + * pPortmask - Static Port mask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set static router port + */ +rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Valid port mask */ + if(pPortmask == NULL) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pPortmask); + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPStaticRouterPort(pmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_static_router_port_get + * Description: + * Get static router port + * Input: + * None. + * Output: + * pPortmask - Static port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API get static router port + */ +rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pPortmask == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPStaticRouterPort(&pmask))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_protocol_set + * Description: + * set IGMP/MLD protocol action + * Input: + * port - Port ID + * protocol - IGMP/MLD protocol + * action - Per-port and per-protocol IGMP action setting + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set IGMP/MLD protocol action + */ +rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action) +{ + rtk_uint32 operation; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(protocol >= PROTOCOL_END) + return RT_ERR_INPUT; + + if(action >= IGMP_ACTION_END) + return RT_ERR_INPUT; + + switch(action) + { + case IGMP_ACTION_FORWARD: + operation = PROTOCOL_OP_FLOOD; + break; + case IGMP_ACTION_TRAP2CPU: + operation = PROTOCOL_OP_TRAP; + break; + case IGMP_ACTION_DROP: + operation = PROTOCOL_OP_DROP; + break; + case IGMP_ACTION_ASIC: + operation = PROTOCOL_OP_ASIC; + break; + default: + return RT_ERR_INPUT; + } + + switch(protocol) + { + case PROTOCOL_IGMPv1: + if ((retVal = rtl8367c_setAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_IGMPv2: + if ((retVal = rtl8367c_setAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_IGMPv3: + if ((retVal = rtl8367c_setAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_MLDv1: + if ((retVal = rtl8367c_setAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_MLDv2: + if ((retVal = rtl8367c_setAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), operation))!=RT_ERR_OK) + return retVal; + + break; + default: + return RT_ERR_INPUT; + + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_protocol_get + * Description: + * set IGMP/MLD protocol action + * Input: + * port - Port ID + * protocol - IGMP/MLD protocol + * action - Per-port and per-protocol IGMP action setting + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set IGMP/MLD protocol action + */ +rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction) +{ + rtk_uint32 operation; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(protocol >= PROTOCOL_END) + return RT_ERR_INPUT; + + if(pAction == NULL) + return RT_ERR_NULL_POINTER; + + switch(protocol) + { + case PROTOCOL_IGMPv1: + if ((retVal = rtl8367c_getAsicIGMPv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_IGMPv2: + if ((retVal = rtl8367c_getAsicIGMPv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_IGMPv3: + if ((retVal = rtl8367c_getAsicIGMPv3Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_MLDv1: + if ((retVal = rtl8367c_getAsicMLDv1Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) + return retVal; + + break; + case PROTOCOL_MLDv2: + if ((retVal = rtl8367c_getAsicMLDv2Opeartion(rtk_switch_port_L2P_get(port), &operation))!=RT_ERR_OK) + return retVal; + + break; + default: + return RT_ERR_INPUT; + + } + + switch(operation) + { + case PROTOCOL_OP_FLOOD: + *pAction = IGMP_ACTION_FORWARD; + break; + case PROTOCOL_OP_TRAP: + *pAction = IGMP_ACTION_TRAP2CPU; + break; + case PROTOCOL_OP_DROP: + *pAction = IGMP_ACTION_DROP; + break; + case PROTOCOL_OP_ASIC: + *pAction = IGMP_ACTION_ASIC; + break; + default: + return RT_ERR_FAILED; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_fastLeave_set + * Description: + * set IGMP/MLD FastLeave state + * Input: + * state - ENABLED: Enable FastLeave, DISABLED: disable FastLeave + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API set IGMP/MLD FastLeave state + */ +rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(state >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPFastLeaveEn((rtk_uint32)state))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_fastLeave_get + * Description: + * get IGMP/MLD FastLeave state + * Input: + * None + * Output: + * pState - ENABLED: Enable FastLeave, DISABLED: disable FastLeave + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - NULL pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get IGMP/MLD FastLeave state + */ +rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState) +{ + rtk_uint32 fast_leave; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pState == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPFastLeaveEn(&fast_leave))!=RT_ERR_OK) + return retVal; + + *pState = ((fast_leave == 1) ? ENABLED : DISABLED); + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_maxGroup_set + * Description: + * Set per port multicast group learning limit. + * Input: + * port - Port ID + * group - The number of multicast group learning limit. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_OUT_OF_RANGE - parameter out of range + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API set per port multicast group learning limit. + */ +rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(group > RTL8367C_IGMP_MAX_GOUP) + return RT_ERR_OUT_OF_RANGE; + + if ((retVal = rtl8367c_setAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), group))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_maxGroup_get + * Description: + * Get per port multicast group learning limit. + * Input: + * port - Port ID + * Output: + * pGroup - The number of multicast group learning limit. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get per port multicast group learning limit. + */ +rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(pGroup == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPPortMAXGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_currentGroup_get + * Description: + * Get per port multicast group learning count. + * Input: + * port - Port ID + * Output: + * pGroup - The number of multicast group learning count. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get per port multicast group learning count. + */ +rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(pGroup == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPPortCurrentGroup(rtk_switch_port_L2P_get(port), pGroup))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_tableFullAction_set + * Description: + * set IGMP/MLD Table Full Action + * Input: + * action - Table Full Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(action >= IGMP_TABLE_FULL_OP_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPTableFullOP((rtk_uint32)action))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_tableFullAction_get + * Description: + * get IGMP/MLD Table Full Action + * Input: + * None + * Output: + * pAction - Table Full Action + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPTableFullOP((rtk_uint32 *)pAction))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_checksumErrorAction_set + * Description: + * set IGMP/MLD Checksum Error Action + * Input: + * action - Checksum error Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(action >= IGMP_CRC_ERR_OP_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPCRCErrOP((rtk_uint32)action))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_igmp_checksumErrorAction_get + * Description: + * get IGMP/MLD Checksum Error Action + * Input: + * None + * Output: + * pAction - Checksum error Action + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPCRCErrOP((rtk_uint32 *)pAction))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_leaveTimer_set + * Description: + * set IGMP/MLD Leave timer + * Input: + * timer - Leave timer + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(timer > RTL8367C_MAX_LEAVE_TIMER) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPLeaveTimer(timer))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_leaveTimer_get + * Description: + * get IGMP/MLD Leave timer + * Input: + * None + * Output: + * pTimer - Leave Timer. + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pTimer) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPLeaveTimer(pTimer))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_queryInterval_set + * Description: + * set IGMP/MLD Query Interval + * Input: + * interval - Query Interval + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(interval > RTL8367C_MAX_QUERY_INT) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPQueryInterval(interval))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_queryInterval_get + * Description: + * get IGMP/MLD Query Interval + * Input: + * None. + * Output: + * pInterval - Query Interval + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pInterval) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPQueryInterval(pInterval))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_robustness_set + * Description: + * set IGMP/MLD Robustness value + * Input: + * robustness - Robustness value + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(robustness > RTL8367C_MAX_ROB_VAR) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPRobVar(robustness))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_robustness_get + * Description: + * get IGMP/MLD Robustness value + * Input: + * None + * Output: + * pRobustness - Robustness value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pRobustness) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPRobVar(pRobustness))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_dynamicRouterRortAllow_set + * Description: + * Configure dynamic router port allow option + * Input: + * pPortmask - Dynamic Port allow mask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pPortmask); + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPAllowDynamicRouterPort(pmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_dynamicRouterRortAllow_get + * Description: + * Get dynamic router port allow option + * Input: + * None. + * Output: + * pPortmask - Dynamic Port allow mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPAllowDynamicRouterPort(&pmask))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_dynamicRouterPort_get + * Description: + * Get dynamic router port + * Input: + * None. + * Output: + * pDynamicRouterPort - Dynamic Router Port + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + rtk_uint32 timer; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pDynamicRouterPort) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort1(&port, &timer))!= RT_ERR_OK) + return retVal; + + if (port == RTL8367C_ROUTER_PORT_INVALID) + { + pDynamicRouterPort->dynamicRouterPort0Valid = DISABLED; + pDynamicRouterPort->dynamicRouterPort0 = 0; + pDynamicRouterPort->dynamicRouterPort0Timer = 0; + } + else + { + pDynamicRouterPort->dynamicRouterPort0Valid = ENABLED; + pDynamicRouterPort->dynamicRouterPort0 = rtk_switch_port_P2L_get(port); + pDynamicRouterPort->dynamicRouterPort0Timer = timer; + } + + if ((retVal = rtl8367c_getAsicIGMPdynamicRouterPort2(&port, &timer))!= RT_ERR_OK) + return retVal; + + if (port == RTL8367C_ROUTER_PORT_INVALID) + { + pDynamicRouterPort->dynamicRouterPort1Valid = DISABLED; + pDynamicRouterPort->dynamicRouterPort1 = 0; + pDynamicRouterPort->dynamicRouterPort1Timer = 0; + } + else + { + pDynamicRouterPort->dynamicRouterPort1Valid = ENABLED; + pDynamicRouterPort->dynamicRouterPort1 = rtk_switch_port_P2L_get(port); + pDynamicRouterPort->dynamicRouterPort1Timer = timer; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_suppressionEnable_set + * Description: + * Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression + * Input: + * reportSuppression - Report suppression + * leaveSuppression - Leave suppression + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(reportSuppression >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(leaveSuppression >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPSuppression((rtk_uint32)reportSuppression, (rtk_uint32)leaveSuppression))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_suppressionEnable_get + * Description: + * Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression + * Input: + * None + * Output: + * pReportSuppression - Report suppression + * pLeaveSuppression - Leave suppression + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pReportSuppression) + return RT_ERR_NULL_POINTER; + + if(NULL == pLeaveSuppression) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPSuppression((rtk_uint32 *)pReportSuppression, (rtk_uint32 *)pLeaveSuppression))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_portRxPktEnable_set + * Description: + * Configure IGMP/MLD RX Packet configuration + * Input: + * port - Port ID + * pRxCfg - RX Packet Configuration + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pRxCfg) + return RT_ERR_NULL_POINTER; + + if(pRxCfg->rxQuery >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(pRxCfg->rxReport >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(pRxCfg->rxLeave >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(pRxCfg->rxMRP >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(pRxCfg->rxMcast >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxQuery))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxReport))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxLeave))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMRP))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32)pRxCfg->rxMcast))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_portRxPktEnable_get + * Description: + * Get IGMP/MLD RX Packet configuration + * Input: + * port - Port ID + * pRxCfg - RX Packet Configuration + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pRxCfg) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPQueryRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxQuery)))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicIGMPReportRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxReport)))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicIGMPLeaveRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxLeave)))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicIGMPMRPRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMRP)))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicIGMPMcDataRX(rtk_switch_port_L2P_get(port), (rtk_uint32 *)&(pRxCfg->rxMcast)))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_groupInfo_get + * Description: + * Get IGMP/MLD Group database + * Input: + * index - Index (0~255) + * Output: + * pGroup - Group database information. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup) +{ + rtk_api_ret_t retVal; + rtk_uint32 valid; + rtl8367c_igmpgroup grp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check index */ + if(index > RTL8367C_IGMP_MAX_GOUP) + return RT_ERR_INPUT; + + if(NULL == pGroup) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPGroup(index, &valid, &grp))!=RT_ERR_OK) + return retVal; + + memset(pGroup, 0x00, sizeof(rtk_igmp_groupInfo_t)); + pGroup->valid = valid; + pGroup->reportSuppFlag = grp.report_supp_flag; + + if(grp.p0_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(0)); + pGroup->timer[rtk_switch_port_P2L_get(0)] = grp.p0_timer; + } + + if(grp.p1_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(1)); + pGroup->timer[rtk_switch_port_P2L_get(1)] = grp.p1_timer; + } + + if(grp.p2_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(2)); + pGroup->timer[rtk_switch_port_P2L_get(2)] = grp.p2_timer; + } + + if(grp.p3_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(3)); + pGroup->timer[rtk_switch_port_P2L_get(3)] = grp.p3_timer; + } + + if(grp.p4_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(4)); + pGroup->timer[rtk_switch_port_P2L_get(4)] = grp.p4_timer; + } + + if(grp.p5_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(5)); + pGroup->timer[rtk_switch_port_P2L_get(5)] = grp.p5_timer; + } + + if(grp.p6_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(6)); + pGroup->timer[rtk_switch_port_P2L_get(6)] = grp.p6_timer; + } + + if(grp.p7_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(7)); + pGroup->timer[rtk_switch_port_P2L_get(7)] = grp.p7_timer; + } + + if(grp.p8_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(8)); + pGroup->timer[rtk_switch_port_P2L_get(8)] = grp.p8_timer; + } + + if(grp.p9_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(9)); + pGroup->timer[rtk_switch_port_P2L_get(9)] = grp.p9_timer; + } + + if(grp.p10_timer != 0) + { + RTK_PORTMASK_PORT_SET((pGroup->member), rtk_switch_port_P2L_get(10)); + pGroup->timer[rtk_switch_port_P2L_get(10)] = grp.p10_timer; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_ReportLeaveFwdAction_set + * Description: + * Set Report Leave packet forwarding action + * Input: + * action - Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + switch(action) + { + case IGMP_REPORT_LEAVE_TO_ROUTER: + regData = 1; + break; + case IGMP_REPORT_LEAVE_TO_ALLPORT: + regData = 2; + break; + case IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV: + regData = 3; + break; + default: + return RT_ERR_INPUT; + } + + if ((retVal = rtl8367c_setAsicIGMPReportLeaveFlood(regData))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_ReportLeaveFwdAction_get + * Description: + * Get Report Leave packet forwarding action + * Input: + * action - Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPReportLeaveFlood(®Data))!=RT_ERR_OK) + return retVal; + + switch(regData) + { + case 1: + *pAction = IGMP_REPORT_LEAVE_TO_ROUTER; + break; + case 2: + *pAction = IGMP_REPORT_LEAVE_TO_ALLPORT; + break; + case 3: + *pAction = IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV; + break; + default: + return RT_ERR_FAILED; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_dropLeaveZeroEnable_set + * Description: + * Set the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * enabled - Action 1: drop, 0:pass + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(enabled >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPDropLeaveZero(enabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_igmp_dropLeaveZeroEnable_get + * Description: + * Get the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * None + * Output: + * pEnabled. - Action 1: drop, 0:pass + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPDropLeaveZero((rtk_uint32 *)pEnabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_igmp_bypassGroupRange_set + * Description: + * Set Bypass group + * Input: + * group - bypassed group + * enabled - enabled 1: Bypassed, 0: not bypass + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(group >= IGMP_BYPASS_GROUP_END) + return RT_ERR_INPUT; + + if(enabled >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicIGMPBypassGroup(group, enabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_igmp_bypassGroupRange_get + * Description: + * get Bypass group + * Input: + * group - bypassed group + * Output: + * pEnable - enabled 1: Bypassed, 0: not bypass + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(group >= IGMP_BYPASS_GROUP_END) + return RT_ERR_INPUT; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicIGMPBypassGroup(group, pEnable))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/include/acl.h b/drivers/net/phy/rtk/rtl8367c/include/acl.h new file mode 100644 index 000000000000..634e7325d696 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/acl.h @@ -0,0 +1,990 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes ACL module high-layer API definition + * + */ + +#ifndef __RTK_API_ACL_H__ +#define __RTK_API_ACL_H__ + +/* + * Data Type Declaration + */ +#define RTK_FILTER_RAW_FIELD_NUMBER 8 + +#define ACL_DEFAULT_ABILITY 0 +#define ACL_DEFAULT_UNMATCH_PERMIT 1 + +#define ACL_RULE_FREE 0 +#define ACL_RULE_INAVAILABLE 1 +#define ACL_RULE_CARETAG_MASK 0x1F +#define FILTER_POLICING_MAX 4 +#define FILTER_LOGGING_MAX 8 +#define FILTER_PATTERN_MAX 4 + +#define FILTER_ENACT_CVLAN_MASK 0x01 +#define FILTER_ENACT_SVLAN_MASK 0x02 +#define FILTER_ENACT_PRIORITY_MASK 0x04 +#define FILTER_ENACT_POLICING_MASK 0x08 +#define FILTER_ENACT_FWD_MASK 0x10 +#define FILTER_ENACT_INTGPIO_MASK 0x20 +#define FILTER_ENACT_INIT_MASK 0x3F + +typedef enum rtk_filter_act_cactext_e +{ + FILTER_ENACT_CACTEXT_VLANONLY=0, + FILTER_ENACT_CACTEXT_BOTHVLANTAG, + FILTER_ENACT_CACTEXT_TAGONLY, + FILTER_ENACT_CACTEXT_END, + + +}rtk_filter_act_cactext_t; + +typedef enum rtk_filter_act_ctagfmt_e +{ + FILTER_CTAGFMT_UNTAG=0, + FILTER_CTAGFMT_TAG, + FILTER_CTAGFMT_KEEP, + FILTER_CTAGFMT_KEEP1PRMK, + + +}rtk_filter_act_ctag_t; + + + + + +#define RTK_MAX_NUM_OF_FILTER_TYPE 5 +#define RTK_MAX_NUM_OF_FILTER_FIELD 8 + +#define RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH 3UL +#define RTK_IPV6_ADDR_WORD_LENGTH 4UL + +#define FILTER_ENACT_CVLAN_TYPE(type) (type - FILTER_ENACT_CVLAN_INGRESS) +#define FILTER_ENACT_SVLAN_TYPE(type) (type - FILTER_ENACT_SVLAN_INGRESS) +#define FILTER_ENACT_FWD_TYPE(type) (type - FILTER_ENACT_ADD_DSTPORT) +#define FILTER_ENACT_PRI_TYPE(type) (type - FILTER_ENACT_PRIORITY) + +#define RTK_FILTER_FIELD_USED_MAX 8 +#define RTK_FILTER_FIELD_INDEX(template, index) ((template << 4) + index) + + +typedef enum rtk_filter_act_enable_e +{ + /* CVLAN */ + FILTER_ENACT_CVLAN_INGRESS = 0, + FILTER_ENACT_CVLAN_EGRESS, + FILTER_ENACT_CVLAN_SVID, + FILTER_ENACT_POLICING_1, + + /* SVLAN */ + FILTER_ENACT_SVLAN_INGRESS, + FILTER_ENACT_SVLAN_EGRESS, + FILTER_ENACT_SVLAN_CVID, + FILTER_ENACT_POLICING_2, + + /* Policing and Logging */ + FILTER_ENACT_POLICING_0, + + /* Forward */ + FILTER_ENACT_COPY_CPU, + FILTER_ENACT_DROP, + FILTER_ENACT_ADD_DSTPORT, + FILTER_ENACT_REDIRECT, + FILTER_ENACT_MIRROR, + FILTER_ENACT_TRAP_CPU, + FILTER_ENACT_ISOLATION, + + /* QoS */ + FILTER_ENACT_PRIORITY, + FILTER_ENACT_DSCP_REMARK, + FILTER_ENACT_1P_REMARK, + FILTER_ENACT_POLICING_3, + + /* Interrutp and GPO */ + FILTER_ENACT_INTERRUPT, + FILTER_ENACT_GPO, + + /*VLAN tag*/ + FILTER_ENACT_EGRESSCTAG_UNTAG, + FILTER_ENACT_EGRESSCTAG_TAG, + FILTER_ENACT_EGRESSCTAG_KEEP, + FILTER_ENACT_EGRESSCTAG_KEEPAND1PRMK, + + FILTER_ENACT_END, +} rtk_filter_act_enable_t; + + +typedef struct +{ + rtk_filter_act_enable_t actEnable[FILTER_ENACT_END]; + + /* CVLAN acton */ + rtk_uint32 filterCvlanVid; + rtk_uint32 filterCvlanIdx; + /* SVLAN action */ + rtk_uint32 filterSvlanVid; + rtk_uint32 filterSvlanIdx; + + /* Policing action */ + rtk_uint32 filterPolicingIdx[FILTER_POLICING_MAX]; + + /* Forwarding action */ + rtk_portmask_t filterPortmask; + + /* QOS action */ + rtk_uint32 filterPriority; + + /*GPO*/ + rtk_uint32 filterPin; + +} rtk_filter_action_t; + +typedef struct rtk_filter_flag_s +{ + rtk_uint32 value; + rtk_uint32 mask; +} rtk_filter_flag_t; + +typedef enum rtk_filter_care_tag_index_e +{ + CARE_TAG_CTAG = 0, + CARE_TAG_STAG, + CARE_TAG_PPPOE, + CARE_TAG_IPV4, + CARE_TAG_IPV6, + CARE_TAG_TCP, + CARE_TAG_UDP, + CARE_TAG_ARP, + CARE_TAG_RSV1, + CARE_TAG_RSV2, + CARE_TAG_ICMP, + CARE_TAG_IGMP, + CARE_TAG_LLC, + CARE_TAG_RSV3, + CARE_TAG_HTTP, + CARE_TAG_RSV4, + CARE_TAG_RSV5, + CARE_TAG_DHCP, + CARE_TAG_DHCPV6, + CARE_TAG_SNMP, + CARE_TAG_OAM, + CARE_TAG_END, +} rtk_filter_care_tag_index_t; + +typedef struct rtk_filter_care_tag_s +{ + rtk_filter_flag_t tagType[CARE_TAG_END]; +} rtk_filter_care_tag_t; + +typedef struct rtk_filter_field rtk_filter_field_t; + +typedef struct +{ + rtk_uint32 value[RTK_DOT_1AS_TIMESTAMP_UNIT_IN_WORD_LENGTH]; +} rtk_filter_dot1as_timestamp_t; + +typedef enum rtk_filter_field_data_type_e +{ + FILTER_FIELD_DATA_MASK = 0, + FILTER_FIELD_DATA_RANGE, + FILTER_FIELD_DATA_END , +} rtk_filter_field_data_type_t; + +typedef struct rtk_filter_ip_s +{ + rtk_uint32 dataType; + rtk_uint32 rangeStart; + rtk_uint32 rangeEnd; + rtk_uint32 value; + rtk_uint32 mask; +} rtk_filter_ip_t; + +typedef struct rtk_filter_mac_s +{ + rtk_uint32 dataType; + rtk_mac_t value; + rtk_mac_t mask; + rtk_mac_t rangeStart; + rtk_mac_t rangeEnd; +} rtk_filter_mac_t; + +typedef rtk_uint32 rtk_filter_op_t; + +typedef struct rtk_filter_value_s +{ + rtk_uint32 dataType; + rtk_uint32 value; + rtk_uint32 mask; + rtk_uint32 rangeStart; + rtk_uint32 rangeEnd; + +} rtk_filter_value_t; + +typedef struct rtk_filter_activeport_s +{ + rtk_portmask_t value; + rtk_portmask_t mask; + +} rtk_filter_activeport_t; + + + +typedef struct rtk_filter_tag_s +{ + rtk_filter_value_t pri; + rtk_filter_flag_t cfi; + rtk_filter_value_t vid; +} rtk_filter_tag_t; + +typedef struct rtk_filter_ipFlag_s +{ + rtk_filter_flag_t xf; + rtk_filter_flag_t mf; + rtk_filter_flag_t df; +} rtk_filter_ipFlag_t; + +typedef struct +{ + rtk_uint32 addr[RTK_IPV6_ADDR_WORD_LENGTH]; +} rtk_filter_ip6_addr_t; + +typedef struct +{ + rtk_uint32 dataType; + rtk_filter_ip6_addr_t value; + rtk_filter_ip6_addr_t mask; + rtk_filter_ip6_addr_t rangeStart; + rtk_filter_ip6_addr_t rangeEnd; +} rtk_filter_ip6_t; + +typedef rtk_uint32 rtk_filter_number_t; + +typedef struct rtk_filter_pattern_s +{ + rtk_uint32 value[FILTER_PATTERN_MAX]; + rtk_uint32 mask[FILTER_PATTERN_MAX]; +} rtk_filter_pattern_t; + +typedef struct rtk_filter_tcpFlag_s +{ + rtk_filter_flag_t urg; + rtk_filter_flag_t ack; + rtk_filter_flag_t psh; + rtk_filter_flag_t rst; + rtk_filter_flag_t syn; + rtk_filter_flag_t fin; + rtk_filter_flag_t ns; + rtk_filter_flag_t cwr; + rtk_filter_flag_t ece; +} rtk_filter_tcpFlag_t; + +typedef rtk_uint32 rtk_filter_field_raw_t; + +typedef enum rtk_filter_field_temple_input_e +{ + FILTER_FIELD_TEMPLE_INPUT_TYPE = 0, + FILTER_FIELD_TEMPLE_INPUT_INDEX, + FILTER_FIELD_TEMPLE_INPUT_MAX , +} rtk_filter_field_temple_input_t; + +struct rtk_filter_field +{ + rtk_uint32 fieldType; + + union + { + /* L2 struct */ + rtk_filter_mac_t dmac; + rtk_filter_mac_t smac; + rtk_filter_value_t etherType; + rtk_filter_tag_t ctag; + rtk_filter_tag_t relayCtag; + rtk_filter_tag_t stag; + rtk_filter_tag_t l2tag; + rtk_filter_dot1as_timestamp_t dot1asTimeStamp; + rtk_filter_mac_t mac; + + /* L3 struct */ + rtk_filter_ip_t sip; + rtk_filter_ip_t dip; + rtk_filter_ip_t ip; + rtk_filter_value_t protocol; + rtk_filter_value_t ipTos; + rtk_filter_ipFlag_t ipFlag; + rtk_filter_value_t ipOffset; + rtk_filter_ip6_t sipv6; + rtk_filter_ip6_t dipv6; + rtk_filter_ip6_t ipv6; + rtk_filter_value_t ipv6TrafficClass; + rtk_filter_value_t ipv6NextHeader; + rtk_filter_value_t flowLabel; + + /* L4 struct */ + rtk_filter_value_t tcpSrcPort; + rtk_filter_value_t tcpDstPort; + rtk_filter_tcpFlag_t tcpFlag; + rtk_filter_value_t tcpSeqNumber; + rtk_filter_value_t tcpAckNumber; + rtk_filter_value_t udpSrcPort; + rtk_filter_value_t udpDstPort; + rtk_filter_value_t icmpCode; + rtk_filter_value_t icmpType; + rtk_filter_value_t igmpType; + + /* pattern match */ + rtk_filter_pattern_t pattern; + + rtk_filter_value_t inData; + + } filter_pattern_union; + + rtk_uint32 fieldTemplateNo; + rtk_uint32 fieldTemplateIdx[RTK_FILTER_FIELD_USED_MAX]; + + struct rtk_filter_field *next; +}; + +typedef enum rtk_filter_field_type_e +{ + FILTER_FIELD_DMAC = 0, + FILTER_FIELD_SMAC, + FILTER_FIELD_ETHERTYPE, + FILTER_FIELD_CTAG, + FILTER_FIELD_STAG, + + FILTER_FIELD_IPV4_SIP, + FILTER_FIELD_IPV4_DIP, + FILTER_FIELD_IPV4_TOS, + FILTER_FIELD_IPV4_PROTOCOL, + FILTER_FIELD_IPV4_FLAG, + FILTER_FIELD_IPV4_OFFSET, + FILTER_FIELD_IPV6_SIPV6, + FILTER_FIELD_IPV6_DIPV6, + FILTER_FIELD_IPV6_TRAFFIC_CLASS, + FILTER_FIELD_IPV6_NEXT_HEADER, + + FILTER_FIELD_TCP_SPORT, + FILTER_FIELD_TCP_DPORT, + FILTER_FIELD_TCP_FLAG, + FILTER_FIELD_UDP_SPORT, + FILTER_FIELD_UDP_DPORT, + FILTER_FIELD_ICMP_CODE, + FILTER_FIELD_ICMP_TYPE, + FILTER_FIELD_IGMP_TYPE, + + FILTER_FIELD_VID_RANGE, + FILTER_FIELD_IP_RANGE, + FILTER_FIELD_PORT_RANGE, + + FILTER_FIELD_USER_DEFINED00, + FILTER_FIELD_USER_DEFINED01, + FILTER_FIELD_USER_DEFINED02, + FILTER_FIELD_USER_DEFINED03, + FILTER_FIELD_USER_DEFINED04, + FILTER_FIELD_USER_DEFINED05, + FILTER_FIELD_USER_DEFINED06, + FILTER_FIELD_USER_DEFINED07, + FILTER_FIELD_USER_DEFINED08, + FILTER_FIELD_USER_DEFINED09, + FILTER_FIELD_USER_DEFINED10, + FILTER_FIELD_USER_DEFINED11, + FILTER_FIELD_USER_DEFINED12, + FILTER_FIELD_USER_DEFINED13, + FILTER_FIELD_USER_DEFINED14, + FILTER_FIELD_USER_DEFINED15, + + FILTER_FIELD_PATTERN_MATCH, + + FILTER_FIELD_END, +} rtk_filter_field_type_t; + + +typedef enum rtk_filter_field_type_raw_e +{ + FILTER_FIELD_RAW_UNUSED = 0, + FILTER_FIELD_RAW_DMAC_15_0, + FILTER_FIELD_RAW_DMAC_31_16, + FILTER_FIELD_RAW_DMAC_47_32, + FILTER_FIELD_RAW_SMAC_15_0, + FILTER_FIELD_RAW_SMAC_31_16, + FILTER_FIELD_RAW_SMAC_47_32, + FILTER_FIELD_RAW_ETHERTYPE, + FILTER_FIELD_RAW_STAG, + FILTER_FIELD_RAW_CTAG, + + FILTER_FIELD_RAW_IPV4_SIP_15_0 = 0x10, + FILTER_FIELD_RAW_IPV4_SIP_31_16, + FILTER_FIELD_RAW_IPV4_DIP_15_0, + FILTER_FIELD_RAW_IPV4_DIP_31_16, + + + FILTER_FIELD_RAW_IPV6_SIP_15_0 = 0x20, + FILTER_FIELD_RAW_IPV6_SIP_31_16, + FILTER_FIELD_RAW_IPV6_DIP_15_0 = 0x28, + FILTER_FIELD_RAW_IPV6_DIP_31_16, + + FILTER_FIELD_RAW_VIDRANGE = 0x30, + FILTER_FIELD_RAW_IPRANGE, + FILTER_FIELD_RAW_PORTRANGE, + FILTER_FIELD_RAW_FIELD_VALID, + + FILTER_FIELD_RAW_FIELD_SELECT00 = 0x40, + FILTER_FIELD_RAW_FIELD_SELECT01, + FILTER_FIELD_RAW_FIELD_SELECT02, + FILTER_FIELD_RAW_FIELD_SELECT03, + FILTER_FIELD_RAW_FIELD_SELECT04, + FILTER_FIELD_RAW_FIELD_SELECT05, + FILTER_FIELD_RAW_FIELD_SELECT06, + FILTER_FIELD_RAW_FIELD_SELECT07, + FILTER_FIELD_RAW_FIELD_SELECT08, + FILTER_FIELD_RAW_FIELD_SELECT09, + FILTER_FIELD_RAW_FIELD_SELECT10, + FILTER_FIELD_RAW_FIELD_SELECT11, + FILTER_FIELD_RAW_FIELD_SELECT12, + FILTER_FIELD_RAW_FIELD_SELECT13, + FILTER_FIELD_RAW_FIELD_SELECT14, + FILTER_FIELD_RAW_FIELD_SELECT15, + + FILTER_FIELD_RAW_END, +} rtk_filter_field_type_raw_t; + +typedef enum rtk_filter_flag_care_type_e +{ + FILTER_FLAG_CARE_DONT_CARE = 0, + FILTER_FLAG_CARE_1, + FILTER_FLAG_CARE_0, + FILTER_FLAG_END +} rtk_filter_flag_care_type_t; + +typedef rtk_uint32 rtk_filter_id_t; /* filter id type */ + +typedef enum rtk_filter_invert_e +{ + FILTER_INVERT_DISABLE = 0, + FILTER_INVERT_ENABLE, + FILTER_INVERT_END, +} rtk_filter_invert_t; + +typedef rtk_uint32 rtk_filter_state_t; + +typedef rtk_uint32 rtk_filter_unmatch_action_t; + +typedef enum rtk_filter_unmatch_action_e +{ + FILTER_UNMATCH_DROP = 0, + FILTER_UNMATCH_PERMIT, + FILTER_UNMATCH_END, +} rtk_filter_unmatch_action_type_t; + +typedef struct +{ + rtk_filter_field_t *fieldHead; + rtk_filter_care_tag_t careTag; + rtk_filter_activeport_t activeport; + + rtk_filter_invert_t invert; +} rtk_filter_cfg_t; + +typedef struct +{ + rtk_filter_field_raw_t dataFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER]; + rtk_filter_field_raw_t careFieldRaw[RTK_FILTER_RAW_FIELD_NUMBER]; + rtk_filter_field_type_raw_t fieldRawType[RTK_FILTER_RAW_FIELD_NUMBER]; + rtk_filter_care_tag_t careTag; + rtk_filter_activeport_t activeport; + + rtk_filter_invert_t invert; + rtk_enable_t valid; +} rtk_filter_cfg_raw_t; + +typedef struct +{ + rtk_uint32 index; + rtk_filter_field_type_raw_t fieldType[RTK_FILTER_RAW_FIELD_NUMBER]; +} rtk_filter_template_t; + +typedef enum rtk_field_sel_e +{ + FORMAT_DEFAULT = 0, + FORMAT_RAW, + FORMAT_LLC, + FORMAT_IPV4, + FORMAT_ARP, + FORMAT_IPV6, + FORMAT_IPPAYLOAD, + FORMAT_L4PAYLOAD, + FORMAT_END +}rtk_field_sel_t; + +typedef enum rtk_filter_iprange_e +{ + IPRANGE_UNUSED = 0, + IPRANGE_IPV4_SIP, + IPRANGE_IPV4_DIP, + IPRANGE_IPV6_SIP, + IPRANGE_IPV6_DIP, + IPRANGE_END +}rtk_filter_iprange_t; + +typedef enum rtk_filter_vidrange_e +{ + VIDRANGE_UNUSED = 0, + VIDRANGE_CVID, + VIDRANGE_SVID, + VIDRANGE_END +}rtk_filter_vidrange_t; + +typedef enum rtk_filter_portrange_e +{ + PORTRANGE_UNUSED = 0, + PORTRANGE_SPORT, + PORTRANGE_DPORT, + PORTRANGE_END +}rtk_filter_portrange_t; + +/* Function Name: + * rtk_filter_igrAcl_init + * Description: + * ACL initialization function + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * Note: + * This function enable and initialize ACL function + */ +extern rtk_api_ret_t rtk_filter_igrAcl_init(void); + +/* Function Name: + * rtk_filter_igrAcl_field_add + * Description: + * Add comparison rule to an ACL configuration + * Input: + * pFilter_cfg - The ACL configuration that this function will add comparison rule + * pFilter_field - The comparison rule that will be added. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function add a comparison rule (*pFilter_field) to an ACL configuration (*pFilter_cfg). + * Pointer pFilter_cfg points to an ACL configuration structure, this structure keeps multiple ACL + * comparison rules by means of linked list. Pointer pFilter_field will be added to linked + * list kept by structure that pFilter_cfg points to. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_field_add(rtk_filter_cfg_t *pFilter_cfg, rtk_filter_field_t *pFilter_field); + +/* Function Name: + * rtk_filter_igrAcl_cfg_add + * Description: + * Add an ACL configuration to ASIC + * Input: + * filter_id - Start index of ACL configuration. + * pFilter_cfg - The ACL configuration that this function will add comparison rule + * pFilter_action - Action(s) of ACL configuration. + * Output: + * ruleNum - number of rules written in ACL table + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_field or pFilter_cfg point to NULL. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENTRY_INDEX - Invalid filter_id . + * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. + * RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT - Action is not supported in this chip. + * RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT - Rule is not supported. + * Note: + * This function store pFilter_cfg, pFilter_action into ASIC. The starting + * index(es) is filter_id. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_cfg_add(rtk_filter_id_t filter_id, rtk_filter_cfg_t *pFilter_cfg, rtk_filter_action_t *pAction, rtk_filter_number_t *ruleNum); + +/* Function Name: + * rtk_filter_igrAcl_cfg_del + * Description: + * Delete an ACL configuration from ASIC + * Input: + * filter_id - Start index of ACL configuration. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_ENTRYIDX - Invalid filter_id. + * Note: + * This function delete a group of ACL rules starting from filter_id. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_cfg_del(rtk_filter_id_t filter_id); + +/* Function Name: + * rtk_filter_igrAcl_cfg_delAll + * Description: + * Delete all ACL entries from ASIC + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This function delete all ACL configuration from ASIC. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_cfg_delAll(void); + +/* Function Name: + * rtk_filter_igrAcl_cfg_get + * Description: + * Get one ingress ACL configuration from ASIC. + * Input: + * filter_id - Start index of ACL configuration. + * Output: + * pFilter_cfg - buffer pointer of ingress ACL data + * pFilter_action - buffer pointer of ingress ACL action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Pointer pFilter_action or pFilter_cfg point to NULL. + * RT_ERR_FILTER_ENTRYIDX - Invalid entry index. + * Note: + * This function delete all ACL configuration from ASIC. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_cfg_get(rtk_filter_id_t filter_id, rtk_filter_cfg_raw_t *pFilter_cfg, rtk_filter_action_t *pAction); + +/* Function Name: + * rtk_filter_igrAcl_unmatchAction_set + * Description: + * Set action to packets when no ACL configuration match + * Input: + * port - Port id. + * action - Action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function sets action of packets when no ACL configuration matches. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_set(rtk_port_t port, rtk_filter_unmatch_action_t action); + +/* Function Name: + * rtk_filter_igrAcl_unmatchAction_get + * Description: + * Get action to packets when no ACL configuration match + * Input: + * port - Port id. + * Output: + * pAction - Action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configuration matches. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_unmatchAction_get(rtk_port_t port, rtk_filter_unmatch_action_t* action); + +/* Function Name: + * rtk_filter_igrAcl_state_set + * Description: + * Set state of ingress ACL. + * Input: + * port - Port id. + * state - Ingress ACL state. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configuration matches. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_state_set(rtk_port_t port, rtk_filter_state_t state); + +/* Function Name: + * rtk_filter_igrAcl_state_get + * Description: + * Get state of ingress ACL. + * Input: + * port - Port id. + * Output: + * pState - Ingress ACL state. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port id. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function gets action of packets when no ACL configuration matches. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_state_get(rtk_port_t port, rtk_filter_state_t* state); + +/* Function Name: + * rtk_filter_igrAcl_template_set + * Description: + * Set template of ingress ACL. + * Input: + * template - Ingress ACL template + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This function set ACL template. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_template_set(rtk_filter_template_t *aclTemplate); + +/* Function Name: + * rtk_filter_igrAcl_template_get + * Description: + * Get template of ingress ACL. + * Input: + * template - Ingress ACL template + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This function gets template of ACL. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_template_get(rtk_filter_template_t *aclTemplate); + +/* Function Name: + * rtk_filter_igrAcl_field_sel_set + * Description: + * Set user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * format - Format of field selector + * offset - Retrieving data offset + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * System support 16 user defined field selectors. + * Each selector can be enabled or disable. + * User can defined retrieving 16-bits in many predefiend + * standard l2/l3/l4 payload. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_set(rtk_uint32 index, rtk_field_sel_t format, rtk_uint32 offset); + +/* Function Name: + * rtk_filter_igrAcl_field_sel_get + * Description: + * Get user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * Output: + * pFormat - Format of field selector + * pOffset - Retrieving data offset + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +extern rtk_api_ret_t rtk_filter_igrAcl_field_sel_get(rtk_uint32 index, rtk_field_sel_t *pFormat, rtk_uint32 *pOffset); + +/* Function Name: + * rtk_filter_iprange_set + * Description: + * Set IP Range check + * Input: + * index - index of IP Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP + * upperIp - The upper bound of IP range + * lowerIp - The lower Bound of IP range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperIp must be larger or equal than lowerIp. + */ +extern rtk_api_ret_t rtk_filter_iprange_set(rtk_uint32 index, rtk_filter_iprange_t type, ipaddr_t upperIp, ipaddr_t lowerIp); + +/* Function Name: + * rtk_filter_iprange_get + * Description: + * Set IP Range check + * Input: + * index - index of IP Range 0-15 + * Output: + * pType - IP Range check type, 0:Delete a entry, 1: IPv4_SIP, 2: IPv4_DIP, 3:IPv6_SIP, 4:IPv6_DIP + * pUpperIp - The upper bound of IP range + * pLowerIp - The lower Bound of IP range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * Note: + * upperIp must be larger or equal than lowerIp. + */ +extern rtk_api_ret_t rtk_filter_iprange_get(rtk_uint32 index, rtk_filter_iprange_t *pType, ipaddr_t *pUpperIp, ipaddr_t *pLowerIp); + +/* Function Name: + * rtk_filter_vidrange_set + * Description: + * Set VID Range check + * Input: + * index - index of VID Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: CVID, 2: SVID + * upperVid - The upper bound of VID range + * lowerVid - The lower Bound of VID range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperVid must be larger or equal than lowerVid. + */ +extern rtk_api_ret_t rtk_filter_vidrange_set(rtk_uint32 index, rtk_filter_vidrange_t type, rtk_uint32 upperVid, rtk_uint32 lowerVid); + +/* Function Name: + * rtk_filter_vidrange_get + * Description: + * Get VID Range check + * Input: + * index - index of VID Range 0-15 + * Output: + * pType - IP Range check type, 0:Unused, 1: CVID, 2: SVID + * pUpperVid - The upper bound of VID range + * pLowerVid - The lower Bound of VID range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * Note: + * None. + */ +extern rtk_api_ret_t rtk_filter_vidrange_get(rtk_uint32 index, rtk_filter_vidrange_t *pType, rtk_uint32 *pUpperVid, rtk_uint32 *pLowerVid); + +/* Function Name: + * rtk_filter_portrange_set + * Description: + * Set Port Range check + * Input: + * index - index of Port Range 0-15 + * type - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port + * upperPort - The upper bound of Port range + * lowerPort - The lower Bound of Port range + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * upperPort must be larger or equal than lowerPort. + */ +extern rtk_api_ret_t rtk_filter_portrange_set(rtk_uint32 index, rtk_filter_portrange_t type, rtk_uint32 upperPort, rtk_uint32 lowerPort); + +/* Function Name: + * rtk_filter_portrange_get + * Description: + * Set Port Range check + * Input: + * index - index of Port Range 0-15 + * Output: + * pType - IP Range check type, 0:Delete a entry, 1: Source Port, 2: Destination Port + * pUpperPort - The upper bound of Port range + * pLowerPort - The lower Bound of Port range + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - The parameter is out of range + * RT_ERR_INPUT - Input error + * Note: + * None. + */ +extern rtk_api_ret_t rtk_filter_portrange_get(rtk_uint32 index, rtk_filter_portrange_t *pType, rtk_uint32 *pUpperPort, rtk_uint32 *pLowerPort); + +/* Function Name: + * rtk_filter_igrAclPolarity_set + * Description: + * Set ACL Goip control polarity + * Input: + * polarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +extern rtk_api_ret_t rtk_filter_igrAclPolarity_set(rtk_uint32 polarity); + +/* Function Name: + * rtk_filter_igrAclPolarity_get + * Description: + * Get ACL Goip control polarity + * Input: + * pPolarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +extern rtk_api_ret_t rtk_filter_igrAclPolarity_get(rtk_uint32* pPolarity); + + +#endif /* __RTK_API_ACL_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/cpu.h b/drivers/net/phy/rtk/rtl8367c/include/cpu.h new file mode 100644 index 000000000000..67aa1e3d88ea --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/cpu.h @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes CPU module high-layer API definition + * + */ + +#ifndef __RTK_API_CPU_H__ +#define __RTK_API_CPU_H__ + + +/* + * Data Type Declaration + */ +typedef enum rtk_cpu_insert_e +{ + CPU_INSERT_TO_ALL = 0, + CPU_INSERT_TO_TRAPPING, + CPU_INSERT_TO_NONE, + CPU_INSERT_END +}rtk_cpu_insert_t; + +typedef enum rtk_cpu_position_e +{ + CPU_POS_AFTER_SA = 0, + CPU_POS_BEFORE_CRC, + CPU_POS_END +}rtk_cpu_position_t; + +typedef enum rtk_cpu_tag_length_e +{ + CPU_LEN_8BYTES = 0, + CPU_LEN_4BYTES, + CPU_LEN_END +}rtk_cpu_tag_length_t; + + +typedef enum rtk_cpu_rx_length_e +{ + CPU_RX_72BYTES = 0, + CPU_RX_64BYTES, + CPU_RX_END +}rtk_cpu_rx_length_t; + + +/* Function Name: + * rtk_cpu_enable_set + * Description: + * Set CPU port function enable/disable. + * Input: + * enable - CPU port function enable + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can set CPU port function enable/disable. + */ +extern rtk_api_ret_t rtk_cpu_enable_set(rtk_enable_t enable); + +/* Function Name: + * rtk_cpu_enable_get + * Description: + * Get CPU port and its setting. + * Input: + * None + * Output: + * pEnable - CPU port function enable + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist + * Note: + * The API can get CPU port function enable/disable. + */ +extern rtk_api_ret_t rtk_cpu_enable_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_cpu_tagPort_set + * Description: + * Set CPU port and CPU tag insert mode. + * Input: + * port - Port id. + * mode - CPU tag insert for packets egress from CPU port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can set CPU port and inserting proprietary CPU tag mode (Length/Type 0x8899) + * to the frame that transmitting to CPU port. + * The insert CPU tag mode is as following: + * - CPU_INSERT_TO_ALL + * - CPU_INSERT_TO_TRAPPING + * - CPU_INSERT_TO_NONE + */ +extern rtk_api_ret_t rtk_cpu_tagPort_set(rtk_port_t port, rtk_cpu_insert_t mode); + +/* Function Name: + * rtk_cpu_tagPort_get + * Description: + * Get CPU port and CPU tag insert mode. + * Input: + * None + * Output: + * pPort - Port id. + * pMode - CPU tag insert for packets egress from CPU port, 0:all insert 1:Only for trapped packets 2:no insert. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_L2_NO_CPU_PORT - CPU port is not exist + * Note: + * The API can get configured CPU port and its setting. + * The insert CPU tag mode is as following: + * - CPU_INSERT_TO_ALL + * - CPU_INSERT_TO_TRAPPING + * - CPU_INSERT_TO_NONE + */ +extern rtk_api_ret_t rtk_cpu_tagPort_get(rtk_port_t *pPort, rtk_cpu_insert_t *pMode); + +/* Function Name: + * rtk_cpu_awarePort_set + * Description: + * Set CPU aware port mask. + * Input: + * portmask - Port mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * The API can set configured CPU aware port mask. + */ +extern rtk_api_ret_t rtk_cpu_awarePort_set(rtk_portmask_t *pPortmask); + + +/* Function Name: + * rtk_cpu_awarePort_get + * Description: + * Get CPU aware port mask. + * Input: + * None + * Output: + * pPortmask - Port mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can get configured CPU aware port mask. + */ +extern rtk_api_ret_t rtk_cpu_awarePort_get(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_cpu_tagPosition_set + * Description: + * Set CPU tag position. + * Input: + * position - CPU tag position. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can set CPU tag position. + */ +extern rtk_api_ret_t rtk_cpu_tagPosition_set(rtk_cpu_position_t position); + +/* Function Name: + * rtk_cpu_tagPosition_get + * Description: + * Get CPU tag position. + * Input: + * None + * Output: + * pPosition - CPU tag position. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU tag position. + */ +extern rtk_api_ret_t rtk_cpu_tagPosition_get(rtk_cpu_position_t *pPosition); + +/* Function Name: + * rtk_cpu_tagLength_set + * Description: + * Set CPU tag length. + * Input: + * length - CPU tag length. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can set CPU tag length. + */ +extern rtk_api_ret_t rtk_cpu_tagLength_set(rtk_cpu_tag_length_t length); + +/* Function Name: + * rtk_cpu_tagLength_get + * Description: + * Get CPU tag length. + * Input: + * None + * Output: + * pLength - CPU tag length. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU tag length. + */ +extern rtk_api_ret_t rtk_cpu_tagLength_get(rtk_cpu_tag_length_t *pLength); + +/* Function Name: + * rtk_cpu_acceptLength_set + * Description: + * Set CPU accept length. + * Input: + * length - CPU tag length. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can set CPU accept length. + */ +extern rtk_api_ret_t rtk_cpu_acceptLength_set(rtk_cpu_rx_length_t length); + +/* Function Name: + * rtk_cpu_acceptLength_get + * Description: + * Get CPU accept length. + * Input: + * None + * Output: + * pLength - CPU tag length. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input. + * Note: + * The API can get CPU accept length. + */ +extern rtk_api_ret_t rtk_cpu_acceptLength_get(rtk_cpu_rx_length_t *pLength); + +/* Function Name: + * rtk_cpu_priRemap_set + * Description: + * Configure CPU priorities mapping to internal absolute priority. + * Input: + * int_pri - internal priority value. + * new_pri - new internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_cpu_priRemap_set(rtk_pri_t int_pri, rtk_pri_t new_pri); + +/* Function Name: + * rtk_cpu_priRemap_get + * Description: + * Configure CPU priorities mapping to internal absolute priority. + * Input: + * int_pri - internal priority value. + * Output: + * pNew_pri - new internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of CPU tag assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_cpu_priRemap_get(rtk_pri_t int_pri, rtk_pri_t *pNew_pri); + + +#endif /* __RTK_API_CPU_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/dot1x.h b/drivers/net/phy/rtk/rtl8367c/include/dot1x.h new file mode 100644 index 000000000000..082ee2569e2a --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/dot1x.h @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes 1X module high-layer API definition + * + */ + +#ifndef __RTK_API_DOT1X_H__ +#define __RTK_API_DOT1X_H__ + + +/* Type of port-based dot1x auth/unauth*/ +typedef enum rtk_dot1x_auth_status_e +{ + UNAUTH = 0, + AUTH, + AUTH_STATUS_END +} rtk_dot1x_auth_status_t; + +typedef enum rtk_dot1x_direction_e +{ + DIR_BOTH = 0, + DIR_IN, + DIRECTION_END +} rtk_dot1x_direction_t; + +/* unauth pkt action */ +typedef enum rtk_dot1x_unauth_action_e +{ + DOT1X_ACTION_DROP = 0, + DOT1X_ACTION_TRAP2CPU, + DOT1X_ACTION_GUESTVLAN, + DOT1X_ACTION_END +} rtk_dot1x_unauth_action_t; + +/* Function Name: + * rtk_dot1x_unauthPacketOper_set + * Description: + * Set 802.1x unauth action configuration. + * Input: + * port - Port id. + * unauth_action - 802.1X unauth action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * This API can set 802.1x unauth action configuration. + * The unauth action is as following: + * - DOT1X_ACTION_DROP + * - DOT1X_ACTION_TRAP2CPU + * - DOT1X_ACTION_GUESTVLAN + */ +extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_set(rtk_port_t port, rtk_dot1x_unauth_action_t unauth_action); + +/* Function Name: + * rtk_dot1x_unauthPacketOper_get + * Description: + * Get 802.1x unauth action configuration. + * Input: + * port - Port id. + * Output: + * pUnauth_action - 802.1X unauth action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get 802.1x unauth action configuration. + * The unauth action is as following: + * - DOT1X_ACTION_DROP + * - DOT1X_ACTION_TRAP2CPU + * - DOT1X_ACTION_GUESTVLAN + */ +extern rtk_api_ret_t rtk_dot1x_unauthPacketOper_get(rtk_port_t port, rtk_dot1x_unauth_action_t *pUnauth_action); + +/* Function Name: + * rtk_dot1x_eapolFrame2CpuEnable_set + * Description: + * Set 802.1x EAPOL packet trap to CPU configuration + * Input: + * enable - The status of 802.1x EAPOL packet. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to + * be trapped to CPU. + * The status of EAPOL frame trap to CPU is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_set(rtk_enable_t enable); + +/* Function Name: + * rtk_dot1x_eapolFrame2CpuEnable_get + * Description: + * Get 802.1x EAPOL packet trap to CPU configuration + * Input: + * None + * Output: + * pEnable - The status of 802.1x EAPOL packet. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * To support 802.1x authentication functionality, EAPOL frame (ether type = 0x888E) has to + * be trapped to CPU. + * The status of EAPOL frame trap to CPU is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_dot1x_eapolFrame2CpuEnable_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_dot1x_portBasedEnable_set + * Description: + * Set 802.1x port-based enable configuration + * Input: + * port - Port id. + * enable - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_PORTBASEDPNEN - 802.1X port-based enable error + * Note: + * The API can update the port-based port enable register content. If a port is 802.1x + * port based network access control "enabled", it should be authenticated so packets + * from that port won't be dropped or trapped to CPU. + * The status of 802.1x port-based network access control is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_dot1x_portBasedEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_dot1x_portBasedEnable_get + * Description: + * Get 802.1x port-based enable configuration + * Input: + * port - Port id. + * Output: + * pEnable - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get the 802.1x port-based port status. + */ +extern rtk_api_ret_t rtk_dot1x_portBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_dot1x_portBasedAuthStatus_set + * Description: + * Set 802.1x port-based auth. port configuration + * Input: + * port - Port id. + * port_auth - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_DOT1X_PORTBASEDAUTH - 802.1X port-based auth error + * Note: + * The authenticated status of 802.1x port-based network access control is as following: + * - UNAUTH + * - AUTH + */ +extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_set(rtk_port_t port, rtk_dot1x_auth_status_t port_auth); + +/* Function Name: + * rtk_dot1x_portBasedAuthStatus_get + * Description: + * Get 802.1x port-based auth. port configuration + * Input: + * port - Port id. + * Output: + * pPort_auth - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1x port-based port auth.information. + */ +extern rtk_api_ret_t rtk_dot1x_portBasedAuthStatus_get(rtk_port_t port, rtk_dot1x_auth_status_t *pPort_auth); + +/* Function Name: + * rtk_dot1x_portBasedDirection_set + * Description: + * Set 802.1x port-based operational direction configuration + * Input: + * port - Port id. + * port_direction - Operation direction + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_DOT1X_PORTBASEDOPDIR - 802.1X port-based operation direction error + * Note: + * The operate controlled direction of 802.1x port-based network access control is as following: + * - BOTH + * - IN + */ +extern rtk_api_ret_t rtk_dot1x_portBasedDirection_set(rtk_port_t port, rtk_dot1x_direction_t port_direction); + +/* Function Name: + * rtk_dot1x_portBasedDirection_get + * Description: + * Get 802.1X port-based operational direction configuration + * Input: + * port - Port id. + * Output: + * pPort_direction - Operation direction + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1x port-based operational direction information. + */ +extern rtk_api_ret_t rtk_dot1x_portBasedDirection_get(rtk_port_t port, rtk_dot1x_direction_t *pPort_direction); + +/* Function Name: + * rtk_dot1x_macBasedEnable_set + * Description: + * Set 802.1x mac-based port enable configuration + * Input: + * port - Port id. + * enable - The status of 802.1x port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error + * Note: + * If a port is 802.1x MAC based network access control "enabled", the incoming packets should + * be authenticated so packets from that port won't be dropped or trapped to CPU. + * The status of 802.1x MAC-based network access control is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_dot1x_macBasedEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_dot1x_macBasedEnable_get + * Description: + * Get 802.1x mac-based port enable configuration + * Input: + * port - Port id. + * Output: + * pEnable - The status of 802.1x port. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * If a port is 802.1x MAC based network access control "enabled", the incoming packets should + * be authenticated so packets from that port wont be dropped or trapped to CPU. + * The status of 802.1x MAC-based network access control is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_dot1x_macBasedEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_dot1x_macBasedAuthMac_add + * Description: + * Add an authenticated MAC to ASIC + * Input: + * port - Port id. + * pAuth_mac - The authenticated MAC. + * fid - filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * RT_ERR_DOT1X_MACBASEDPNEN - 802.1X mac-based enable error + * Note: + * The API can add a 802.1x authenticated MAC address to port. If the MAC does not exist in LUT, + * user can't add this MAC to auth status. + */ +extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_add(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid); + +/* Function Name: + * rtk_dot1x_macBasedAuthMac_del + * Description: + * Delete an authenticated MAC to ASIC + * Input: + * port - Port id. + * pAuth_mac - The authenticated MAC. + * fid - filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can delete a 802.1x authenticated MAC address to port. It only change the auth status of + * the MAC and won't delete it from LUT. + */ +extern rtk_api_ret_t rtk_dot1x_macBasedAuthMac_del(rtk_port_t port, rtk_mac_t *pAuth_mac, rtk_fid_t fid); + +/* Function Name: + * rtk_dot1x_macBasedDirection_set + * Description: + * Set 802.1x mac-based operational direction configuration + * Input: + * mac_direction - Operation direction + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_DOT1X_MACBASEDOPDIR - 802.1X mac-based operation direction error + * Note: + * The operate controlled direction of 802.1x mac-based network access control is as following: + * - BOTH + * - IN + */ +extern rtk_api_ret_t rtk_dot1x_macBasedDirection_set(rtk_dot1x_direction_t mac_direction); + +/* Function Name: + * rtk_dot1x_macBasedDirection_get + * Description: + * Get 802.1x mac-based operational direction configuration + * Input: + * port - Port id. + * Output: + * pMac_direction - Operation direction + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x mac-based operational direction information. + */ +extern rtk_api_ret_t rtk_dot1x_macBasedDirection_get(rtk_dot1x_direction_t *pMac_direction); + +/* Function Name: + * Set 802.1x guest VLAN configuration + * Description: + * Set 802.1x mac-based operational direction configuration + * Input: + * vid - 802.1x guest VLAN ID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The operate controlled 802.1x guest VLAN + */ +extern rtk_api_ret_t rtk_dot1x_guestVlan_set(rtk_vlan_t vid); + +/* Function Name: + * rtk_dot1x_guestVlan_get + * Description: + * Get 802.1x guest VLAN configuration + * Input: + * None + * Output: + * pVid - 802.1x guest VLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x guest VLAN information. + */ +extern rtk_api_ret_t rtk_dot1x_guestVlan_get(rtk_vlan_t *pVid); + +/* Function Name: + * rtk_dot1x_guestVlan2Auth_set + * Description: + * Set 802.1x guest VLAN to auth host configuration + * Input: + * enable - The status of guest VLAN to auth host. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The operational direction of 802.1x guest VLAN to auth host control is as following: + * - ENABLED + * - DISABLED + */ +extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_set(rtk_enable_t enable); + +/* Function Name: + * rtk_dot1x_guestVlan2Auth_get + * Description: + * Get 802.1x guest VLAN to auth host configuration + * Input: + * None + * Output: + * pEnable - The status of guest VLAN to auth host. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get 802.1x guest VLAN to auth host information. + */ +extern rtk_api_ret_t rtk_dot1x_guestVlan2Auth_get(rtk_enable_t *pEnable); + + +#endif /* __RTK_API_DOT1X_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/eee.h b/drivers/net/phy/rtk/rtl8367c/include/eee.h new file mode 100644 index 000000000000..e3920363d15c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/eee.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes EEE module high-layer API definition + * + */ + +#ifndef __RTK_API_EEE_H__ +#define __RTK_API_EEE_H__ + +/* Function Name: + * rtk_eee_init + * Description: + * EEE function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API is used to initialize EEE status. + */ +extern rtk_api_ret_t rtk_eee_init(void); + +/* Function Name: + * rtk_eee_portEnable_set + * Description: + * Set enable status of EEE function. + * Input: + * port - port id. + * enable - enable EEE status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set EEE function to the specific port. + * The configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_eee_portEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_eee_portEnable_get + * Description: + * Get port admin configuration of the specific port. + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can set EEE function to the specific port. + * The configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_eee_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + + +#endif /* __RTK_API_EEE_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/i2c.h b/drivers/net/phy/rtk/rtl8367c/include/i2c.h new file mode 100644 index 000000000000..110f41e818ee --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/i2c.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes I2C module high-layer API definition + * + */ + + +#ifndef __RTK_API_I2C_H__ +#define __RTK_API_I2C_H__ +#include + +#define I2C_GPIO_MAX_GROUP (3) + +typedef enum rtk_I2C_16bit_mode_e{ + I2C_LSB_16BIT_MODE = 0, + I2C_70B_LSB_16BIT_MODE, + I2C_Mode_END +}rtk_I2C_16bit_mode_t; + + +typedef enum rtk_I2C_gpio_pin_e{ + I2C_GPIO_PIN_8_9 = 0, + I2C_GPIO_PIN_15_16 , + I2C_GPIO_PIN_35_36 , + I2C_GPIO_PIN_END +}rtk_I2C_gpio_pin_t; + + +/* Function Name: + * rtk_i2c_data_read + * Description: + * read i2c slave device register. + * Input: + * deviceAddr - access Slave device address + * slaveRegAddr - access Slave register address + * Output: + * pRegData - read data + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can access i2c slave and read i2c slave device register. + */ +extern rtk_api_ret_t rtk_i2c_data_read(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 *pRegData); + +/* Function Name: + * rtk_i2c_data_write + * Description: + * write data to i2c slave device register + * Input: + * deviceAddr - access Slave device address + * slaveRegAddr - access Slave register address + * regData - data to set + * Output: + * None + * Return: + * RT_ERR_OK - OK + * Note: + * The API can access i2c slave and setting i2c slave device register. + */ +extern rtk_api_ret_t rtk_i2c_data_write(rtk_uint8 deviceAddr, rtk_uint32 slaveRegAddr, rtk_uint32 regData); + + +/* Function Name: + * rtk_i2c_init + * Description: + * I2C smart function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * Note: + * This API is used to initialize EEE status. + * need used GPIO pins + * OpenDrain and clock + */ +extern rtk_api_ret_t rtk_i2c_init(void); + +/* Function Name: + * rtk_i2c_mode_set + * Description: + * Set I2C data byte-order. + * Input: + * i2cmode - byte-order mode + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * This API can set I2c traffic's byte-order . + */ +extern rtk_api_ret_t rtk_i2c_mode_set( rtk_I2C_16bit_mode_t i2cmode); + +/* Function Name: + * rtk_i2c_mode_get + * Description: + * Get i2c traffic byte-order setting. + * Input: + * None + * Output: + * pI2cMode - i2c byte-order + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can get i2c traffic byte-order setting. + */ +extern rtk_api_ret_t rtk_i2c_mode_get( rtk_I2C_16bit_mode_t * pI2cMode); + + +/* Function Name: + * rtk_i2c_gpioPinGroup_set + * Description: + * Set i2c SDA & SCL used GPIO pins group. + * Input: + * pins_group - GPIO pins group + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The API can set i2c used gpio pins group. + * There are three group pins could be used + */ +extern rtk_api_ret_t rtk_i2c_gpioPinGroup_set( rtk_I2C_gpio_pin_t pins_group); + +/* Function Name: + * rtk_i2c_gpioPinGroup_get + * Description: + * Get i2c SDA & SCL used GPIO pins group. + * Input: + * None + * Output: + * pPins_group - GPIO pins group + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - input parameter is null pointer + * Note: + * The API can get i2c used gpio pins group. + * There are three group pins could be used + */ +extern rtk_api_ret_t rtk_i2c_gpioPinGroup_get(rtk_I2C_gpio_pin_t * pPins_group); + + + + + + + +#endif + diff --git a/drivers/net/phy/rtk/rtl8367c/include/igmp.h b/drivers/net/phy/rtk/rtl8367c/include/igmp.h new file mode 100644 index 000000000000..b36db43d830c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/igmp.h @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes IGMP module high-layer API definition + * + */ + +#ifndef __RTK_API_IGMP_H__ +#define __RTK_API_IGMP_H__ + +/* + * Data Type Declaration + */ +typedef enum rtk_igmp_type_e +{ + IGMP_IPV4 = 0, + IGMP_PPPOE_IPV4, + IGMP_MLD, + IGMP_PPPOE_MLD, + IGMP_TYPE_END +} rtk_igmp_type_t; + +typedef enum rtk_trap_igmp_action_e +{ + IGMP_ACTION_FORWARD = 0, + IGMP_ACTION_TRAP2CPU, + IGMP_ACTION_DROP, + IGMP_ACTION_ASIC, + IGMP_ACTION_END +} rtk_igmp_action_t; + +typedef enum rtk_igmp_protocol_e +{ + PROTOCOL_IGMPv1 = 0, + PROTOCOL_IGMPv2, + PROTOCOL_IGMPv3, + PROTOCOL_MLDv1, + PROTOCOL_MLDv2, + PROTOCOL_END +} rtk_igmp_protocol_t; + +typedef enum rtk_igmp_tableFullAction_e +{ + IGMP_TABLE_FULL_FORWARD = 0, + IGMP_TABLE_FULL_DROP, + IGMP_TABLE_FULL_TRAP, + IGMP_TABLE_FULL_OP_END +}rtk_igmp_tableFullAction_t; + +typedef enum rtk_igmp_checksumErrorAction_e +{ + IGMP_CRC_ERR_DROP = 0, + IGMP_CRC_ERR_TRAP, + IGMP_CRC_ERR_FORWARD, + IGMP_CRC_ERR_OP_END +}rtk_igmp_checksumErrorAction_t; + +typedef enum rtk_igmp_bypassGroup_e +{ + IGMP_BYPASS_224_0_0_X = 0, + IGMP_BYPASS_224_0_1_X, + IGMP_BYPASS_239_255_255_X, + IGMP_BYPASS_IPV6_00XX, + IGMP_BYPASS_GROUP_END +}rtk_igmp_bypassGroup_t; + + +typedef struct rtk_igmp_dynamicRouterPort_s +{ + rtk_enable_t dynamicRouterPort0Valid; + rtk_port_t dynamicRouterPort0; + rtk_uint32 dynamicRouterPort0Timer; + rtk_enable_t dynamicRouterPort1Valid; + rtk_port_t dynamicRouterPort1; + rtk_uint32 dynamicRouterPort1Timer; + +}rtk_igmp_dynamicRouterPort_t; + +typedef struct rtk_igmp_rxPktEnable_s +{ + rtk_enable_t rxQuery; + rtk_enable_t rxReport; + rtk_enable_t rxLeave; + rtk_enable_t rxMRP; + rtk_enable_t rxMcast; +}rtk_igmp_rxPktEnable_t; + +typedef struct rtk_igmp_groupInfo_s +{ + rtk_enable_t valid; + rtk_portmask_t member; + rtk_uint32 timer[RTK_PORT_MAX]; + rtk_uint32 reportSuppFlag; +}rtk_igmp_groupInfo_t; + +typedef enum rtk_igmp_ReportLeaveFwdAct_e +{ + IGMP_REPORT_LEAVE_TO_ROUTER = 0, + IGMP_REPORT_LEAVE_TO_ALLPORT, + IGMP_REPORT_LEAVE_TO_ROUTER_PORT_ADV, + IGMP_REPORT_LEAVE_ACT_END +}rtk_igmp_ReportLeaveFwdAct_t; + +/* Function Name: + * rtk_igmp_init + * Description: + * This API enables H/W IGMP and set a default initial configuration. + * Input: + * None. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API enables H/W IGMP and set a default initial configuration. + */ +extern rtk_api_ret_t rtk_igmp_init(void); + +/* Function Name: + * rtk_igmp_state_set + * Description: + * This API set H/W IGMP state. + * Input: + * enabled - H/W IGMP state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set H/W IGMP state. + */ +extern rtk_api_ret_t rtk_igmp_state_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_igmp_state_get + * Description: + * This API get H/W IGMP state. + * Input: + * None. + * Output: + * pEnabled - H/W IGMP state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current H/W IGMP state. + */ +extern rtk_api_ret_t rtk_igmp_state_get(rtk_enable_t *pEnabled); + +/* Function Name: + * rtk_igmp_static_router_port_set + * Description: + * Configure static router port + * Input: + * pPortmask - Static Port mask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set static router port + */ +extern rtk_api_ret_t rtk_igmp_static_router_port_set(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_igmp_static_router_port_get + * Description: + * Get static router port + * Input: + * None. + * Output: + * pPortmask - Static port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API get static router port + */ +extern rtk_api_ret_t rtk_igmp_static_router_port_get(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_igmp_protocol_set + * Description: + * set IGMP/MLD protocol action + * Input: + * port - Port ID + * protocol - IGMP/MLD protocol + * action - Per-port and per-protocol IGMP action setting + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set IGMP/MLD protocol action + */ +extern rtk_api_ret_t rtk_igmp_protocol_set(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t action); + +/* Function Name: + * rtk_igmp_protocol_get + * Description: + * set IGMP/MLD protocol action + * Input: + * port - Port ID + * protocol - IGMP/MLD protocol + * action - Per-port and per-protocol IGMP action setting + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * This API set IGMP/MLD protocol action + */ +extern rtk_api_ret_t rtk_igmp_protocol_get(rtk_port_t port, rtk_igmp_protocol_t protocol, rtk_igmp_action_t *pAction); + +/* Function Name: + * rtk_igmp_fastLeave_set + * Description: + * set IGMP/MLD FastLeave state + * Input: + * state - ENABLED: Enable FastLeave, DISABLED: disable FastLeave + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API set IGMP/MLD FastLeave state + */ +extern rtk_api_ret_t rtk_igmp_fastLeave_set(rtk_enable_t state); + +/* Function Name: + * rtk_igmp_fastLeave_get + * Description: + * get IGMP/MLD FastLeave state + * Input: + * None + * Output: + * pState - ENABLED: Enable FastLeave, DISABLED: disable FastLeave + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - NULL pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get IGMP/MLD FastLeave state + */ +extern rtk_api_ret_t rtk_igmp_fastLeave_get(rtk_enable_t *pState); + +/* Function Name: + * rtk_igmp_maxGroup_set + * Description: + * Set per port multicast group learning limit. + * Input: + * port - Port ID + * group - The number of multicast group learning limit. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_OUT_OF_RANGE - parameter out of range + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API set per port multicast group learning limit. + */ +extern rtk_api_ret_t rtk_igmp_maxGroup_set(rtk_port_t port, rtk_uint32 group); + +/* Function Name: + * rtk_igmp_maxGroup_get + * Description: + * Get per port multicast group learning limit. + * Input: + * port - Port ID + * Output: + * pGroup - The number of multicast group learning limit. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get per port multicast group learning limit. + */ +extern rtk_api_ret_t rtk_igmp_maxGroup_get(rtk_port_t port, rtk_uint32 *pGroup); + +/* Function Name: + * rtk_igmp_currentGroup_get + * Description: + * Get per port multicast group learning count. + * Input: + * port - Port ID + * Output: + * pGroup - The number of multicast group learning count. + * Return: + * RT_ERR_OK - OK + * RT_ERR_PORT_ID - Error Port ID + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API get per port multicast group learning count. + */ +extern rtk_api_ret_t rtk_igmp_currentGroup_get(rtk_port_t port, rtk_uint32 *pGroup); + +/* Function Name: + * rtk_igmp_tableFullAction_set + * Description: + * set IGMP/MLD Table Full Action + * Input: + * action - Table Full Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_tableFullAction_set(rtk_igmp_tableFullAction_t action); + +/* Function Name: + * rtk_igmp_tableFullAction_get + * Description: + * get IGMP/MLD Table Full Action + * Input: + * None + * Output: + * pAction - Table Full Action + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_tableFullAction_get(rtk_igmp_tableFullAction_t *pAction); + +/* Function Name: + * rtk_igmp_checksumErrorAction_set + * Description: + * set IGMP/MLD Checksum Error Action + * Input: + * action - Checksum error Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_checksumErrorAction_set(rtk_igmp_checksumErrorAction_t action); + +/* Function Name: + * rtk_igmp_checksumErrorAction_get + * Description: + * get IGMP/MLD Checksum Error Action + * Input: + * None + * Output: + * pAction - Checksum error Action + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_checksumErrorAction_get(rtk_igmp_checksumErrorAction_t *pAction); + +/* Function Name: + * rtk_igmp_leaveTimer_set + * Description: + * set IGMP/MLD Leave timer + * Input: + * timer - Leave timer + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_leaveTimer_set(rtk_uint32 timer); + +/* Function Name: + * rtk_igmp_leaveTimer_get + * Description: + * get IGMP/MLD Leave timer + * Input: + * None + * Output: + * pTimer - Leave Timer. + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_leaveTimer_get(rtk_uint32 *pTimer); + +/* Function Name: + * rtk_igmp_queryInterval_set + * Description: + * set IGMP/MLD Query Interval + * Input: + * interval - Query Interval + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_queryInterval_set(rtk_uint32 interval); + +/* Function Name: + * rtk_igmp_queryInterval_get + * Description: + * get IGMP/MLD Query Interval + * Input: + * None. + * Output: + * pInterval - Query Interval + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_queryInterval_get(rtk_uint32 *pInterval); + +/* Function Name: + * rtk_igmp_robustness_set + * Description: + * set IGMP/MLD Robustness value + * Input: + * robustness - Robustness value + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Error Input + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_robustness_set(rtk_uint32 robustness); + +/* Function Name: + * rtk_igmp_robustness_get + * Description: + * get IGMP/MLD Robustness value + * Input: + * None + * Output: + * pRobustness - Robustness value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +extern rtk_api_ret_t rtk_igmp_robustness_get(rtk_uint32 *pRobustness); + +/* Function Name: + * rtk_igmp_dynamicRouterRortAllow_set + * Description: + * Configure dynamic router port allow option + * Input: + * pPortmask - Dynamic Port allow mask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_set(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_igmp_dynamicRouterRortAllow_get + * Description: + * Get dynamic router port allow option + * Input: + * None. + * Output: + * pPortmask - Dynamic Port allow mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_dynamicRouterPortAllow_get(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_igmp_dynamicRouterPort_get + * Description: + * Get dynamic router port + * Input: + * None. + * Output: + * pDynamicRouterPort - Dynamic Router Port + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error parameter + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_dynamicRouterPort_get(rtk_igmp_dynamicRouterPort_t *pDynamicRouterPort); + +/* Function Name: + * rtk_igmp_suppressionEnable_set + * Description: + * Configure IGMPv1/v2 & MLDv1 Report/Leave/Done suppression + * Input: + * reportSuppression - Report suppression + * leaveSuppression - Leave suppression + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_suppressionEnable_set(rtk_enable_t reportSuppression, rtk_enable_t leaveSuppression); + +/* Function Name: + * rtk_igmp_suppressionEnable_get + * Description: + * Get IGMPv1/v2 & MLDv1 Report/Leave/Done suppression + * Input: + * None + * Output: + * pReportSuppression - Report suppression + * pLeaveSuppression - Leave suppression + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_suppressionEnable_get(rtk_enable_t *pReportSuppression, rtk_enable_t *pLeaveSuppression); + +/* Function Name: + * rtk_igmp_portRxPktEnable_set + * Description: + * Configure IGMP/MLD RX Packet configuration + * Input: + * port - Port ID + * pRxCfg - RX Packet Configuration + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_portRxPktEnable_set(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg); + +/* Function Name: + * rtk_igmp_portRxPktEnable_get + * Description: + * Get IGMP/MLD RX Packet configuration + * Input: + * port - Port ID + * pRxCfg - RX Packet Configuration + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_portRxPktEnable_get(rtk_port_t port, rtk_igmp_rxPktEnable_t *pRxCfg); + +/* Function Name: + * rtk_igmp_groupInfo_get + * Description: + * Get IGMP/MLD Group database + * Input: + * index - Index (0~255) + * Output: + * pGroup - Group database information. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_groupInfo_get(rtk_uint32 index, rtk_igmp_groupInfo_t *pGroup); + +/* Function Name: + * rtk_igmp_ReportLeaveFwdAction_set + * Description: + * Set Report Leave packet forwarding action + * Input: + * action - Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_set(rtk_igmp_ReportLeaveFwdAct_t action); + +/* Function Name: + * rtk_igmp_ReportLeaveFwdAction_get + * Description: + * Get Report Leave packet forwarding action + * Input: + * action - Action + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_ReportLeaveFwdAction_get(rtk_igmp_ReportLeaveFwdAct_t *pAction); + +/* Function Name: + * rtk_igmp_dropLeaveZeroEnable_set + * Description: + * Set the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * enabled - Action 1: drop, 0:pass + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_igmp_dropLeaveZeroEnable_get + * Description: + * Get the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * None + * Output: + * pEnabled. - Action 1: drop, 0:pass + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_dropLeaveZeroEnable_get(rtk_enable_t *pEnabled); + +/* Function Name: + * rtk_igmp_bypassGroupRange_set + * Description: + * Set Bypass group + * Input: + * group - bypassed group + * enabled - enabled 1: Bypassed, 0: not bypass + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_bypassGroupRange_set(rtk_igmp_bypassGroup_t group, rtk_enable_t enabled); + +/* Function Name: + * rtk_igmp_bypassGroupRange_get + * Description: + * get Bypass group + * Input: + * group - bypassed group + * Output: + * pEnable - enabled 1: Bypassed, 0: not bypass + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_igmp_bypassGroupRange_get(rtk_igmp_bypassGroup_t group, rtk_enable_t *pEnable); + +#endif /* __RTK_API_IGMP_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/interrupt.h b/drivers/net/phy/rtk/rtl8367c/include/interrupt.h new file mode 100644 index 000000000000..20625fff52c2 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/interrupt.h @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Interrupt module high-layer API definition + * + */ + +#ifndef __RTK_API_INTERRUPT_H__ +#define __RTK_API_INTERRUPT_H__ + + +/* + * Data Type Declaration + */ +#define RTK_MAX_NUM_OF_INTERRUPT_TYPE 1 + + +typedef struct rtk_int_status_s +{ + rtk_uint16 value[RTK_MAX_NUM_OF_INTERRUPT_TYPE]; +} rtk_int_status_t; + +typedef struct rtk_int_info_s +{ + rtk_portmask_t portMask; + rtk_uint32 meterMask; + rtk_uint32 systemLearnOver; +}rtk_int_info_t; + +typedef enum rtk_int_type_e +{ + INT_TYPE_LINK_STATUS = 0, + INT_TYPE_METER_EXCEED, + INT_TYPE_LEARN_LIMIT, + INT_TYPE_LINK_SPEED, + INT_TYPE_CONGEST, + INT_TYPE_GREEN_FEATURE, + INT_TYPE_LOOP_DETECT, + INT_TYPE_8051, + INT_TYPE_CABLE_DIAG, + INT_TYPE_ACL, + INT_TYPE_RESERVED, /* Unused */ + INT_TYPE_SLIENT, + INT_TYPE_END +}rtk_int_type_t; + +typedef enum rtk_int_advType_e +{ + ADV_L2_LEARN_PORT_MASK = 0, + ADV_SPEED_CHANGE_PORT_MASK, + ADV_SPECIAL_CONGESTION_PORT_MASK, + ADV_PORT_LINKDOWN_PORT_MASK, + ADV_PORT_LINKUP_PORT_MASK, + ADV_METER_EXCEED_MASK, + ADV_RLDP_LOOPED, + ADV_RLDP_RELEASED, + ADV_END, +} rtk_int_advType_t; + +typedef enum rtk_int_polarity_e +{ + INT_POLAR_HIGH = 0, + INT_POLAR_LOW, + INT_POLAR_END +} rtk_int_polarity_t; + +/* Function Name: + * rtk_int_polarity_set + * Description: + * Set interrupt polarity configuration. + * Input: + * type - Interruptpolarity type. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set interrupt polarity configuration. + */ +extern rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type); + +/* Function Name: + * rtk_int_polarity_get + * Description: + * Get interrupt polarity configuration. + * Input: + * None + * Output: + * pType - Interruptpolarity type. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can get interrupt polarity configuration. + */ +extern rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType); + +/* Function Name: + * rtk_int_control_set + * Description: + * Set interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * enable - Interrupt status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set interrupt status configuration. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS + * - INT_TYPE_METER_EXCEED + * - INT_TYPE_LEARN_LIMIT + * - INT_TYPE_LINK_SPEED + * - INT_TYPE_CONGEST + * - INT_TYPE_GREEN_FEATURE + * - INT_TYPE_LOOP_DETECT + * - INT_TYPE_8051, + * - INT_TYPE_CABLE_DIAG, + * - INT_TYPE_ACL, + * - INT_TYPE_SLIENT + */ +extern rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable); + +/* Function Name: + * rtk_int_control_get + * Description: + * Get interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * Output: + * pEnable - Interrupt status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt status configuration. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS + * - INT_TYPE_METER_EXCEED + * - INT_TYPE_LEARN_LIMIT + * - INT_TYPE_LINK_SPEED + * - INT_TYPE_CONGEST + * - INT_TYPE_GREEN_FEATURE + * - INT_TYPE_LOOP_DETECT + * - INT_TYPE_8051, + * - INT_TYPE_CABLE_DIAG, + * - INT_TYPE_ACL, + * - INT_TYPE_SLIENT + */ +extern rtk_api_ret_t rtk_int_control_get(rtk_int_type_t type, rtk_enable_t* pEnable); + +/* Function Name: + * rtk_int_status_set + * Description: + * Set interrupt trigger status to clean. + * Input: + * None + * Output: + * pStatusMask - Interrupt status bit mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can clean interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) + * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) + * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) + * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) + * - INT_TYPE_CONGEST (value[0] (Bit4)) + * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) + * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) + * - INT_TYPE_8051 (value[0] (Bit7)) + * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) + * - INT_TYPE_ACL (value[0] (Bit9)) + * - INT_TYPE_SLIENT (value[0] (Bit11)) + * The status will be cleared after execute this API. + */ +extern rtk_api_ret_t rtk_int_status_set(rtk_int_status_t *pStatusMask); + +/* Function Name: + * rtk_int_status_get + * Description: + * Get interrupt trigger status. + * Input: + * None + * Output: + * pStatusMask - Interrupt status bit mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) + * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) + * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) + * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) + * - INT_TYPE_CONGEST (value[0] (Bit4)) + * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) + * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) + * - INT_TYPE_8051 (value[0] (Bit7)) + * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) + * - INT_TYPE_ACL (value[0] (Bit9)) + * - INT_TYPE_SLIENT (value[0] (Bit11)) + * + */ +extern rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask); + +/* Function Name: + * rtk_int_advanceInfo_get + * Description: + * Get interrupt advanced information. + * Input: + * adv_type - Advanced interrupt type. + * Output: + * info - Information per type. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get advanced information when interrupt happened. + * The status will be cleared after execute this API. + */ +extern rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t* info); + + +#endif /* __RTK_API_INTERRUPT_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/l2.h b/drivers/net/phy/rtk/rtl8367c/include/l2.h new file mode 100644 index 000000000000..ec5aad2e30b9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/l2.h @@ -0,0 +1,1181 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes L2 module high-layer API definition + * + */ + +#ifndef __RTK_API_L2_H__ +#define __RTK_API_L2_H__ + + +/* + * Data Type Declaration + */ +#define RTK_MAX_NUM_OF_LEARN_LIMIT (rtk_switch_maxLutAddrNumber_get()) + +#define RTK_MAC_ADDR_LEN 6 +#define RTK_MAX_LUT_ADDRESS (RTK_MAX_NUM_OF_LEARN_LIMIT) +#define RTK_MAX_LUT_ADDR_ID (RTK_MAX_LUT_ADDRESS - 1) + +typedef rtk_uint32 rtk_l2_age_time_t; + +typedef enum rtk_l2_flood_type_e +{ + FLOOD_UNKNOWNDA = 0, + FLOOD_UNKNOWNMC, + FLOOD_BC, + FLOOD_END +} rtk_l2_flood_type_t; + +typedef rtk_uint32 rtk_l2_flushItem_t; + +typedef enum rtk_l2_flushType_e +{ + FLUSH_TYPE_BY_PORT = 0, /* physical port */ + FLUSH_TYPE_BY_PORT_VID, /* physical port + VID */ + FLUSH_TYPE_BY_PORT_FID, /* physical port + FID */ + FLUSH_TYPE_END +} rtk_l2_flushType_t; + +typedef struct rtk_l2_flushCfg_s +{ + rtk_enable_t flushByVid; + rtk_vlan_t vid; + rtk_enable_t flushByFid; + rtk_uint32 fid; + rtk_enable_t flushByPort; + rtk_port_t port; + rtk_enable_t flushByMac; + rtk_mac_t ucastAddr; + rtk_enable_t flushStaticAddr; + rtk_enable_t flushAddrOnAllPorts; /* this is used when flushByVid */ +} rtk_l2_flushCfg_t; + +typedef enum rtk_l2_read_method_e{ + + READMETHOD_MAC = 0, + READMETHOD_ADDRESS, + READMETHOD_NEXT_ADDRESS, + READMETHOD_NEXT_L2UC, + READMETHOD_NEXT_L2MC, + READMETHOD_NEXT_L3MC, + READMETHOD_NEXT_L2L3MC, + READMETHOD_NEXT_L2UCSPA, + READMETHOD_END +}rtk_l2_read_method_t; + +/* l2 limit learning count action */ +typedef enum rtk_l2_limitLearnCntAction_e +{ + LIMIT_LEARN_CNT_ACTION_DROP = 0, + LIMIT_LEARN_CNT_ACTION_FORWARD, + LIMIT_LEARN_CNT_ACTION_TO_CPU, + LIMIT_LEARN_CNT_ACTION_END +} rtk_l2_limitLearnCntAction_t; + +typedef enum rtk_l2_ipmc_lookup_type_e +{ + LOOKUP_MAC = 0, + LOOKUP_IP, + LOOKUP_IP_VID, + LOOKUP_END +} rtk_l2_ipmc_lookup_type_t; + +/* l2 address table - unicast data structure */ +typedef struct rtk_l2_ucastAddr_s +{ + rtk_mac_t mac; + rtk_uint32 ivl; + rtk_uint32 cvid; + rtk_uint32 fid; + rtk_uint32 efid; + rtk_uint32 port; + rtk_uint32 sa_block; + rtk_uint32 da_block; + rtk_uint32 auth; + rtk_uint32 is_static; + rtk_uint32 priority; + rtk_uint32 sa_pri_en; + rtk_uint32 fwd_pri_en; + rtk_uint32 address; +}rtk_l2_ucastAddr_t; + +/* l2 address table - multicast data structure */ +typedef struct rtk_l2_mcastAddr_s +{ + rtk_uint32 vid; + rtk_mac_t mac; + rtk_uint32 fid; + rtk_portmask_t portmask; + rtk_uint32 ivl; + rtk_uint32 priority; + rtk_uint32 fwd_pri_en; + rtk_uint32 igmp_asic; + rtk_uint32 igmp_index; + rtk_uint32 address; +}rtk_l2_mcastAddr_t; + +/* l2 address table - ip multicast data structure */ +typedef struct rtk_l2_ipMcastAddr_s +{ + ipaddr_t dip; + ipaddr_t sip; + rtk_portmask_t portmask; + rtk_uint32 priority; + rtk_uint32 fwd_pri_en; + rtk_uint32 igmp_asic; + rtk_uint32 igmp_index; + rtk_uint32 address; +}rtk_l2_ipMcastAddr_t; + +/* l2 address table - ip VID multicast data structure */ +typedef struct rtk_l2_ipVidMcastAddr_s +{ + ipaddr_t dip; + ipaddr_t sip; + rtk_uint32 vid; + rtk_portmask_t portmask; + rtk_uint32 address; +}rtk_l2_ipVidMcastAddr_t; + +typedef struct rtk_l2_addr_table_s +{ + rtk_uint32 index; + ipaddr_t sip; + ipaddr_t dip; + rtk_mac_t mac; + rtk_uint32 sa_block; + rtk_uint32 auth; + rtk_portmask_t portmask; + rtk_uint32 age; + rtk_uint32 ivl; + rtk_uint32 cvid; + rtk_uint32 fid; + rtk_uint32 is_ipmul; + rtk_uint32 is_static; + rtk_uint32 is_ipvidmul; + rtk_uint32 l3_vid; +}rtk_l2_addr_table_t; + +typedef enum rtk_l2_clearStatus_e +{ + L2_CLEAR_STATE_FINISH = 0, + L2_CLEAR_STATE_BUSY, + L2_CLEAR_STATE_END +}rtk_l2_clearStatus_t; + +/* Function Name: + * rtk_l2_init + * Description: + * Initialize l2 module of the specified device. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Initialize l2 module before calling any l2 APIs. + */ +extern rtk_api_ret_t rtk_l2_init(void); + +/* Function Name: + * rtk_l2_addr_add + * Description: + * Add LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * pL2_data - Unicast entry parameter + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the unicast mac address already existed in LUT, it will update the status of the entry. + * Otherwise, it will find an empty or asic auto learned entry to write. If all the entries + * with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. + */ +extern rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); + +/* Function Name: + * rtk_l2_addr_get + * Description: + * Get LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * Output: + * pL2_data - Unicast entry parameter + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the unicast mac address existed in LUT, it will return the port and fid where + * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. + */ +extern rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); + +/* Function Name: + * rtk_l2_addr_next_get + * Description: + * Get Next LUT unicast entry. + * Input: + * read_method - The reading method. + * port - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA + * pAddress - The Address ID + * Output: + * pL2_data - Unicast entry parameter + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next unicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all entries is LUT. + */ +extern rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data); + +/* Function Name: + * rtk_l2_addr_del + * Description: + * Delete LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * fid - Filtering database + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. + */ +extern rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data); + +/* Function Name: + * rtk_l2_mcastAddr_add + * Description: + * Add LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the multicast mac address already existed in the LUT, it will update the + * port mask of the entry. Otherwise, it will find an empty or asic auto learned + * entry to write. If all the entries with the same hash value can't be replaced, + * ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. + */ +extern rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr); + +/* Function Name: + * rtk_l2_mcastAddr_get + * Description: + * Get LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * pMcastAddr - L2 multicast entry structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the multicast mac address existed in the LUT, it will return the port where + * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. + */ +extern rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr); + +/* Function Name: + * rtk_l2_mcastAddr_next_get + * Description: + * Get Next L2 Multicast entry. + * Input: + * pAddress - The Address ID + * Output: + * pMcastAddr - L2 multicast entry structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next L2 multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all multicast entries is LUT. + */ +extern rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr); + +/* Function Name: + * rtk_l2_mcastAddr_del + * Description: + * Delete LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. + */ +extern rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr); + +/* Function Name: + * rtk_l2_ipMcastAddr_add + * Description: + * Add LUT IP multicast entry + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user + * desired. If this function is enabled, then system will be looked up L2 IP multicast entry to + * forward IP multicast frame directly without flooding. + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr); + +/* Function Name: + * rtk_l2_ipMcastAddr_get + * Description: + * Get LUT IP multicast entry. + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * pIpMcastAddr - IP Multicast entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LUT table of IP multicast entry. + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr); + +/* Function Name: + * rtk_l2_ipMcastAddr_next_get + * Description: + * Get Next IP Multicast entry. + * Input: + * pAddress - The Address ID + * Output: + * pIpMcastAddr - IP Multicast entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next IP multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all IP multicast entries is LUT. + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr); + +/* Function Name: + * rtk_l2_ipMcastAddr_del + * Description: + * Delete a ip multicast address entry from the specified device. + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can delete a IP multicast address entry from the specified device. + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr); + +/* Function Name: + * rtk_l2_ipVidMcastAddr_add + * Description: + * Add LUT IP multicast+VID entry + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); + +/* Function Name: + * rtk_l2_ipVidMcastAddr_get + * Description: + * Get LUT IP multicast+VID entry. + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * pIpVidMcastAddr - IP & VID multicast Entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); + +/* Function Name: + * rtk_l2_ipVidMcastAddr_next_get + * Description: + * Get Next IP Multicast+VID entry. + * Input: + * pAddress - The Address ID + * Output: + * pIpVidMcastAddr - IP & VID multicast Entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next IP multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all IP multicast entries is LUT. + */ +extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); + +/* Function Name: + * rtk_l2_ipVidMcastAddr_del + * Description: + * Delete a ip multicast+VID address entry from the specified device. + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr); + +/* Function Name: + * rtk_l2_ucastAddr_flush + * Description: + * Flush L2 mac address by type in the specified device (both dynamic and static). + * Input: + * pConfig - flush configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * flushByVid - 1: Flush by VID, 0: Don't flush by VID + * vid - VID (0 ~ 4095) + * flushByFid - 1: Flush by FID, 0: Don't flush by FID + * fid - FID (0 ~ 15) + * flushByPort - 1: Flush by Port, 0: Don't flush by Port + * port - Port ID + * flushByMac - Not Supported + * ucastAddr - Not Supported + * flushStaticAddr - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries + * flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port. + */ +extern rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig); + +/* Function Name: + * rtk_l2_table_clear + * Description: + * Flush all static & dynamic entries in LUT. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_table_clear(void); + +/* Function Name: + * rtk_l2_table_clearStatus_get + * Description: + * Get table clear status + * Input: + * None + * Output: + * pStatus - Clear status, 1:Busy, 0:finish + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus); + +/* Function Name: + * rtk_l2_flushLinkDownPortAddrEnable_set + * Description: + * Set HW flush linkdown port mac configuration of the specified device. + * Input: + * port - Port id. + * enable - link down flush status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The status of flush linkdown port address is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_l2_flushLinkDownPortAddrEnable_get + * Description: + * Get HW flush linkdown port mac configuration of the specified device. + * Input: + * port - Port id. + * Output: + * pEnable - link down flush status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The status of flush linkdown port address is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_l2_agingEnable_set + * Description: + * Set L2 LUT aging status per port setting. + * Input: + * port - Port id. + * enable - Aging status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can be used to set L2 LUT aging status per port. + */ +extern rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_l2_agingEnable_get + * Description: + * Get L2 LUT aging status per port setting. + * Input: + * port - Port id. + * Output: + * pEnable - Aging status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can be used to get L2 LUT aging function per port. + */ +extern rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_l2_limitLearningCnt_set + * Description: + * Set per-Port auto learning limit number + * Input: + * port - Port id. + * mac_cnt - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * The API can set per-port ASIC auto learning limit number from 0(disable learning) + * to 8k. + */ +extern rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt); + +/* Function Name: + * rtk_l2_limitLearningCnt_get + * Description: + * Get per-Port auto learning limit number + * Input: + * port - Port id. + * Output: + * pMac_cnt - Auto learning entries limit number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get per-port ASIC auto learning limit number. + */ +extern rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt); + +/* Function Name: + * rtk_l2_limitSystemLearningCnt_set + * Description: + * Set System auto learning limit number + * Input: + * mac_cnt - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * The API can set system ASIC auto learning limit number from 0(disable learning) + * to 2112. + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt); + +/* Function Name: + * rtk_l2_limitSystemLearningCnt_get + * Description: + * Get System auto learning limit number + * Input: + * None + * Output: + * pMac_cnt - Auto learning entries limit number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get system ASIC auto learning limit number. + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt); + +/* Function Name: + * rtk_l2_limitLearningCntAction_set + * Description: + * Configure auto learn over limit number action. + * Input: + * port - Port id. + * action - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * The API can set SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +extern rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action); + +/* Function Name: + * rtk_l2_limitLearningCntAction_get + * Description: + * Get auto learn over limit number action. + * Input: + * port - Port id. + * Output: + * pAction - Learn over action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +extern rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction); + +/* Function Name: + * rtk_l2_limitSystemLearningCntAction_set + * Description: + * Configure system auto learn over limit number action. + * Input: + * port - Port id. + * action - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * The API can set SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action); + +/* Function Name: + * rtk_l2_limitSystemLearningCntAction_get + * Description: + * Get system auto learn over limit number action. + * Input: + * None. + * Output: + * pAction - Learn over action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction); + +/* Function Name: + * rtk_l2_limitSystemLearningCntPortMask_set + * Description: + * Configure system auto learn portmask + * Input: + * pPortmask - Port Mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_l2_limitSystemLearningCntPortMask_get + * Description: + * get system auto learn portmask + * Input: + * None + * Output: + * pPortmask - Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer. + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_l2_learningCnt_get + * Description: + * Get per-Port current auto learning number + * Input: + * port - Port id. + * Output: + * pMac_cnt - ASIC auto learning entries number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get per-port ASIC auto learning number + */ +extern rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt); + +/* Function Name: + * rtk_l2_floodPortMask_set + * Description: + * Set flooding portmask + * Input: + * type - flooding type. + * pFlood_portmask - flooding portmask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set the flooding mask. + * The flooding type is as following: + * - FLOOD_UNKNOWNDA + * - FLOOD_UNKNOWNMC + * - FLOOD_BC + */ +extern rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask); + +/* Function Name: + * rtk_l2_floodPortMask_get + * Description: + * Get flooding portmask + * Input: + * type - flooding type. + * Output: + * pFlood_portmask - flooding portmask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get the flooding mask. + * The flooding type is as following: + * - FLOOD_UNKNOWNDA + * - FLOOD_UNKNOWNMC + * - FLOOD_BC + */ +extern rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask); + +/* Function Name: + * rtk_l2_localPktPermit_set + * Description: + * Set permission of frames if source port and destination port are the same. + * Input: + * port - Port id. + * permit - permission status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid permit value. + * Note: + * This API is set to permit frame if its source port is equal to destination port. + */ +extern rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit); + +/* Function Name: + * rtk_l2_localPktPermit_get + * Description: + * Get permission of frames if source port and destination port are the same. + * Input: + * port - Port id. + * Output: + * pPermit - permission status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API is to get permission status for frames if its source port is equal to destination port. + */ +extern rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit); + +/* Function Name: + * rtk_l2_aging_set + * Description: + * Set LUT ageing out speed + * Input: + * aging_time - Ageing out time. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can set LUT ageing out period for each entry and the range is from 14s to 800s. + */ +extern rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time); + +/* Function Name: + * rtk_l2_aging_get + * Description: + * Get LUT ageing out time + * Input: + * None + * Output: + * pEnable - Aging status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get LUT ageing out period for each entry. + */ +extern rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time); + +/* Function Name: + * rtk_l2_ipMcastAddrLookup_set + * Description: + * Set LUT IP multicast lookup function + * Input: + * type - Lookup type for IPMC packet. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API can work with rtk_l2_ipMcastAddrLookupException_add. + * If users set the lookup type to DIP, the group in exception table + * will be lookup by DIP+SIP + * If users set the lookup type to DIP+SIP, the group in exception table + * will be lookup by only DIP + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type); + +/* Function Name: + * rtk_l2_ipMcastAddrLookup_get + * Description: + * Get LUT IP multicast lookup function + * Input: + * None. + * Output: + * pType - Lookup type for IPMC packet. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +extern rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType); + +/* Function Name: + * rtk_l2_ipMcastForwardRouterPort_set + * Description: + * Set IPMC packet forward to router port also or not + * Input: + * enabled - 1: Include router port, 0, exclude router port + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_l2_ipMcastForwardRouterPort_get + * Description: + * Get IPMC packet forward to router port also or not + * Input: + * None. + * Output: + * pEnabled - 1: Include router port, 0, exclude router port + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled); + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_add + * Description: + * Add an IP Multicast entry to group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * pPortmask - portmask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Add an entry to IP Multicast Group table. + */ +extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_del + * Description: + * Delete an entry from IP Multicast group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Delete an entry from IP Multicast group table. + */ +extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid); + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_get + * Description: + * get an entry from IP Multicast group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * Output: + * pPortmask - member port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Delete an entry from IP Multicast group table. + */ +extern rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_l2_entry_get + * Description: + * Get LUT unicast entry. + * Input: + * pL2_entry - Index field in the structure. + * Output: + * pL2_entry - other fields such as MAC, port, age... + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_EMPTY_ENTRY - Empty LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API is used to get address by index from 0~2111. + */ +extern rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry); + + +#endif /* __RTK_API_L2_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/leaky.h b/drivers/net/phy/rtk/rtl8367c/include/leaky.h new file mode 100644 index 000000000000..e5b22e2878b4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/leaky.h @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Leaky module high-layer API definition + * + */ + +#ifndef __RTK_API_LEAKY_H__ +#define __RTK_API_LEAKY_H__ + + +typedef enum rtk_leaky_type_e +{ + LEAKY_BRG_GROUP = 0, + LEAKY_FD_PAUSE, + LEAKY_SP_MCAST, + LEAKY_1X_PAE, + LEAKY_UNDEF_BRG_04, + LEAKY_UNDEF_BRG_05, + LEAKY_UNDEF_BRG_06, + LEAKY_UNDEF_BRG_07, + LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + LEAKY_UNDEF_BRG_09, + LEAKY_UNDEF_BRG_0A, + LEAKY_UNDEF_BRG_0B, + LEAKY_UNDEF_BRG_0C, + LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + LEAKY_8021AB, + LEAKY_UNDEF_BRG_0F, + LEAKY_BRG_MNGEMENT, + LEAKY_UNDEFINED_11, + LEAKY_UNDEFINED_12, + LEAKY_UNDEFINED_13, + LEAKY_UNDEFINED_14, + LEAKY_UNDEFINED_15, + LEAKY_UNDEFINED_16, + LEAKY_UNDEFINED_17, + LEAKY_UNDEFINED_18, + LEAKY_UNDEFINED_19, + LEAKY_UNDEFINED_1A, + LEAKY_UNDEFINED_1B, + LEAKY_UNDEFINED_1C, + LEAKY_UNDEFINED_1D, + LEAKY_UNDEFINED_1E, + LEAKY_UNDEFINED_1F, + LEAKY_GMRP, + LEAKY_GVRP, + LEAKY_UNDEF_GARP_22, + LEAKY_UNDEF_GARP_23, + LEAKY_UNDEF_GARP_24, + LEAKY_UNDEF_GARP_25, + LEAKY_UNDEF_GARP_26, + LEAKY_UNDEF_GARP_27, + LEAKY_UNDEF_GARP_28, + LEAKY_UNDEF_GARP_29, + LEAKY_UNDEF_GARP_2A, + LEAKY_UNDEF_GARP_2B, + LEAKY_UNDEF_GARP_2C, + LEAKY_UNDEF_GARP_2D, + LEAKY_UNDEF_GARP_2E, + LEAKY_UNDEF_GARP_2F, + LEAKY_IGMP, + LEAKY_IPMULTICAST, + LEAKY_CDP, + LEAKY_CSSTP, + LEAKY_LLDP, + LEAKY_END, +}rtk_leaky_type_t; + +/* Function Name: + * rtk_leaky_vlan_set + * Description: + * Set VLAN leaky. + * Input: + * type - Packet type for VLAN leaky. + * enable - Leaky status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input + * Note: + * This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +extern rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable); + +/* Function Name: + * rtk_leaky_vlan_get + * Description: + * Get VLAN leaky. + * Input: + * type - Packet type for VLAN leaky. + * Output: + * pEnable - Leaky status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +extern rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_leaky_portIsolation_set + * Description: + * Set port isolation leaky. + * Input: + * type - Packet type for port isolation leaky. + * enable - Leaky status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input + * Note: + * This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +extern rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable); + +/* Function Name: + * rtk_leaky_portIsolation_get + * Description: + * Get port isolation leaky. + * Input: + * type - Packet type for port isolation leaky. + * Output: + * pEnable - Leaky status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +extern rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable); + +#endif /* __RTK_API_LEAKY_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/led.h b/drivers/net/phy/rtk/rtl8367c/include/led.h new file mode 100644 index 000000000000..7706107ef40e --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/led.h @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes LED module high-layer API definition + * + */ + +#ifndef __RTK_API_LED_H__ +#define __RTK_API_LED_H__ + +typedef enum rtk_led_operation_e +{ + LED_OP_SCAN=0, + LED_OP_PARALLEL, + LED_OP_SERIAL, + LED_OP_END, +}rtk_led_operation_t; + + +typedef enum rtk_led_active_e +{ + LED_ACTIVE_HIGH=0, + LED_ACTIVE_LOW, + LED_ACTIVE_END, +}rtk_led_active_t; + +typedef enum rtk_led_config_e +{ + LED_CONFIG_LEDOFF=0, + LED_CONFIG_DUPCOL, + LED_CONFIG_LINK_ACT, + LED_CONFIG_SPD1000, + LED_CONFIG_SPD100, + LED_CONFIG_SPD10, + LED_CONFIG_SPD1000ACT, + LED_CONFIG_SPD100ACT, + LED_CONFIG_SPD10ACT, + LED_CONFIG_SPD10010ACT, + LED_CONFIG_LOOPDETECT, + LED_CONFIG_EEE, + LED_CONFIG_LINKRX, + LED_CONFIG_LINKTX, + LED_CONFIG_MASTER, + LED_CONFIG_ACT, + LED_CONFIG_END, +}rtk_led_congig_t; + +typedef struct rtk_led_ability_s +{ + rtk_enable_t link_10m; + rtk_enable_t link_100m; + rtk_enable_t link_500m; + rtk_enable_t link_1000m; + rtk_enable_t act_rx; + rtk_enable_t act_tx; +}rtk_led_ability_t; + +typedef enum rtk_led_blink_rate_e +{ + LED_BLINKRATE_32MS=0, + LED_BLINKRATE_64MS, + LED_BLINKRATE_128MS, + LED_BLINKRATE_256MS, + LED_BLINKRATE_512MS, + LED_BLINKRATE_1024MS, + LED_BLINKRATE_48MS, + LED_BLINKRATE_96MS, + LED_BLINKRATE_END, +}rtk_led_blink_rate_t; + +typedef enum rtk_led_group_e +{ + LED_GROUP_0 = 0, + LED_GROUP_1, + LED_GROUP_2, + LED_GROUP_END +}rtk_led_group_t; + + +typedef enum rtk_led_force_mode_e +{ + LED_FORCE_NORMAL=0, + LED_FORCE_BLINK, + LED_FORCE_OFF, + LED_FORCE_ON, + LED_FORCE_END +}rtk_led_force_mode_t; + +typedef enum rtk_led_serialOutput_e +{ + SERIAL_LED_NONE = 0, + SERIAL_LED_0, + SERIAL_LED_0_1, + SERIAL_LED_0_2, + SERIAL_LED_END, +}rtk_led_serialOutput_t; + + +/* Function Name: + * rtk_led_enable_set + * Description: + * Set Led enable configuration + * Input: + * group - LED group id. + * pPortmask - LED enable port mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can be used to enable LED per port per group. + */ +extern rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_led_enable_get + * Description: + * Get Led enable configuration + * Input: + * group - LED group id. + * Output: + * pPortmask - LED enable port mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can be used to get LED enable status. + */ +extern rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_led_operation_set + * Description: + * Set Led operation mode + * Input: + * mode - LED operation mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set Led operation mode. + * The modes that can be set are as following: + * - LED_OP_SCAN, + * - LED_OP_PARALLEL, + * - LED_OP_SERIAL, + */ +extern rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode); + +/* Function Name: + * rtk_led_operation_get + * Description: + * Get Led operation mode + * Input: + * None + * Output: + * pMode - Support LED operation mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get Led operation mode. + * The modes that can be set are as following: + * - LED_OP_SCAN, + * - LED_OP_PARALLEL, + * - LED_OP_SERIAL, + */ +extern rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode); + +/* Function Name: + * rtk_led_modeForce_set + * Description: + * Set Led group to configuration force mode + * Input: + * port - port ID + * group - Support LED group id. + * mode - Support LED force mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Error Port ID + * Note: + * The API can force to one force mode. + * The force modes that can be set are as following: + * - LED_FORCE_NORMAL, + * - LED_FORCE_BLINK, + * - LED_FORCE_OFF, + * - LED_FORCE_ON. + */ +extern rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode); + +/* Function Name: + * rtk_led_modeForce_get + * Description: + * Get Led group to configuration force mode + * Input: + * port - port ID + * group - Support LED group id. + * pMode - Support LED force mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Error Port ID + * Note: + * The API can get forced Led group mode. + * The force modes that can be set are as following: + * - LED_FORCE_NORMAL, + * - LED_FORCE_BLINK, + * - LED_FORCE_OFF, + * - LED_FORCE_ON. + */ +extern rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode); + +/* Function Name: + * rtk_led_blinkRate_set + * Description: + * Set LED blinking rate + * Input: + * blinkRate - blinking rate. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. + */ +extern rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate); + +/* Function Name: + * rtk_led_blinkRate_get + * Description: + * Get LED blinking rate at mode 0 to mode 3 + * Input: + * None + * Output: + * pBlinkRate - blinking rate. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. + */ +extern rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate); + +/* Function Name: + * rtk_led_groupConfig_set + * Description: + * Set per group Led to configuration mode + * Input: + * group - LED group. + * config - LED configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. + * - Definition LED Statuses Description + * - 0000 LED_Off LED pin Tri-State. + * - 0001 Dup/Col Collision, Full duplex Indicator. + * - 0010 Link/Act Link, Activity Indicator. + * - 0011 Spd1000 1000Mb/s Speed Indicator. + * - 0100 Spd100 100Mb/s Speed Indicator. + * - 0101 Spd10 10Mb/s Speed Indicator. + * - 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. + * - 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. + * - 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. + * - 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. + * - 1010 LoopDetect LoopDetect Indicator. + * - 1011 EEE EEE Indicator. + * - 1100 Link/Rx Link, Activity Indicator. + * - 1101 Link/Tx Link, Activity Indicator. + * - 1110 Master Link on Master Indicator. + * - 1111 Act Activity Indicator. Low for link established. + */ +extern rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config); + +/* Function Name: + * rtk_led_groupConfig_get + * Description: + * Get Led group configuration mode + * Input: + * group - LED group. + * Output: + * pConfig - LED configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LED indicated information configuration for each LED group. + */ +extern rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig); + +/* Function Name: + * rtk_led_groupAbility_set + * Description: + * Configure per group Led ability + * Input: + * group - LED group. + * pAbility - LED ability + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * None. + */ + +extern rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility); + +/* Function Name: + * rtk_led_groupAbility_get + * Description: + * Get per group Led ability + * Input: + * group - LED group. + * pAbility - LED ability + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * None. + */ + +extern rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility); + +/* Function Name: + * rtk_led_serialMode_set + * Description: + * Set Led serial mode active configuration + * Input: + * active - LED group. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set LED serial mode active configuration. + */ +extern rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active); + +/* Function Name: + * rtk_led_serialMode_get + * Description: + * Get Led group configuration mode + * Input: + * group - LED group. + * Output: + * pConfig - LED configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LED serial mode active configuration. + */ +extern rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive); + +/* Function Name: + * rtk_led_OutputEnable_set + * Description: + * This API set LED I/O state. + * Input: + * enabled - LED I/O state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set LED I/O state. + */ +extern rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state); + + +/* Function Name: + * rtk_led_OutputEnable_get + * Description: + * This API get LED I/O state. + * Input: + * None. + * Output: + * pEnabled - LED I/O state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current LED I/O state. + */ +extern rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState); + +/* Function Name: + * rtk_led_serialModePortmask_set + * Description: + * This API configure Serial LED output Group and portmask + * Input: + * output - output group + * pPortmask - output portmask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * None. + */ +extern rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_led_serialModePortmask_get + * Description: + * This API get Serial LED output Group and portmask + * Input: + * None. + * Output: + * pOutput - output group + * pPortmask - output portmask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * None. + */ +extern rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask); + +#endif /* __RTK_API_LED_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/mirror.h b/drivers/net/phy/rtk/rtl8367c/include/mirror.h new file mode 100644 index 000000000000..8d179ce2df48 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/mirror.h @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Mirror module high-layer API definition + * + */ + +#ifndef __RTK_API_MIRROR_H__ +#define __RTK_API_MIRROR_H__ + +typedef enum rtk_mirror_keep_e +{ + MIRROR_FOLLOW_VLAN = 0, + MIRROR_KEEP_ORIGINAL, + MIRROR_KEEP_END +}rtk_mirror_keep_t; + + +/* Function Name: + * rtk_mirror_portBased_set + * Description: + * Set port mirror function. + * Input: + * mirroring_port - Monitor port. + * pMirrored_rx_portmask - Rx mirror port mask. + * pMirrored_tx_portmask - Tx mirror port mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API is to set mirror function of source port and mirror port. + * The mirror port can only be set to one port and the TX and RX mirror ports + * should be identical. + */ +extern rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask); + +/* Function Name: + * rtk_mirror_portBased_get + * Description: + * Get port mirror function. + * Input: + * None + * Output: + * pMirroring_port - Monitor port. + * pMirrored_rx_portmask - Rx mirror port mask. + * pMirrored_tx_portmask - Tx mirror port mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror function of source port and mirror port. + */ +extern rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t* pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask); + +/* Function Name: + * rtk_mirror_portIso_set + * Description: + * Set mirror port isolation. + * Input: + * enable |Mirror isolation status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set mirror isolation function that prevent normal forwarding packets to mirror port. + */ +extern rtk_api_ret_t rtk_mirror_portIso_set(rtk_enable_t enable); + +/* Function Name: + * rtk_mirror_portIso_get + * Description: + * Get mirror port isolation. + * Input: + * None + * Output: + * pEnable |Mirror isolation status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror isolation status. + */ +extern rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_mirror_vlanLeaky_set + * Description: + * Set mirror VLAN leaky. + * Input: + * txenable -TX leaky enable. + * rxenable - RX leaky enable. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set mirror VLAN leaky function forwarding packets to mirror port. + */ +extern rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable); + + +/* Function Name: + * rtk_mirror_vlanLeaky_get + * Description: + * Get mirror VLAN leaky. + * Input: + * None + * Output: + * pTxenable - TX leaky enable. + * pRxenable - RX leaky enable. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror VLAN leaky status. + */ +extern rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable); + +/* Function Name: + * rtk_mirror_isolationLeaky_set + * Description: + * Set mirror Isolation leaky. + * Input: + * txenable -TX leaky enable. + * rxenable - RX leaky enable. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set mirror VLAN leaky function forwarding packets to mirror port. + */ +extern rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable); + +/* Function Name: + * rtk_mirror_isolationLeaky_get + * Description: + * Get mirror isolation leaky. + * Input: + * None + * Output: + * pTxenable - TX leaky enable. + * pRxenable - RX leaky enable. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror isolation leaky status. + */ +extern rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable); + +/* Function Name: + * rtk_mirror_keep_set + * Description: + * Set mirror packet format keep. + * Input: + * mode - -mirror keep mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set -mirror keep mode. + * The mirror keep mode is as following: + * - MIRROR_FOLLOW_VLAN + * - MIRROR_KEEP_ORIGINAL + * - MIRROR_KEEP_END + */ +extern rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode); + + +/* Function Name: + * rtk_mirror_keep_get + * Description: + * Get mirror packet format keep. + * Input: + * None + * Output: + * pMode -mirror keep mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror keep mode. + * The mirror keep mode is as following: + * - MIRROR_FOLLOW_VLAN + * - MIRROR_KEEP_ORIGINAL + * - MIRROR_KEEP_END + */ +extern rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode); + +/* Function Name: + * rtk_mirror_override_set + * Description: + * Set port mirror override function. + * Input: + * rxMirror - 1: output mirrored packet, 0: output normal forward packet + * txMirror - 1: output mirrored packet, 0: output normal forward packet + * aclMirror - 1: output mirrored packet, 0: output normal forward packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API is to set mirror override function. + * This function control the output format when a port output + * normal forward & mirrored packet at the same time. + */ +extern rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror); + +/* Function Name: + * rtk_mirror_override_get + * Description: + * Get port mirror override function. + * Input: + * None + * Output: + * pRxMirror - 1: output mirrored packet, 0: output normal forward packet + * pTxMirror - 1: output mirrored packet, 0: output normal forward packet + * pAclMirror - 1: output mirrored packet, 0: output normal forward packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * The API is to Get mirror override function. + * This function control the output format when a port output + * normal forward & mirrored packet at the same time. + */ +extern rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror); + +#endif /* __RTK_API_MIRROR_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/oam.h b/drivers/net/phy/rtk/rtl8367c/include/oam.h new file mode 100644 index 000000000000..1fc14bd62fec --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/oam.h @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes the following modules and sub-modules + * (1) OAM (802.3ah) configuration + * + */ + +#ifndef __RTK_OAM_H__ +#define __RTK_OAM_H__ + +/* + * Symbol Definition + */ + + +/* + * Data Declaration + */ + + +/* + * Macro Declaration + */ + +typedef enum rtk_oam_parser_act_e +{ + OAM_PARSER_ACTION_FORWARD = 0, + OAM_PARSER_ACTION_LOOPBACK, + OAM_PARSER_ACTION_DISCARD, + OAM_PARSER_ACTION_END, + +} rtk_oam_parser_act_t; + +typedef enum rtk_oam_multiplexer_act_e +{ + OAM_MULTIPLEXER_ACTION_FORWARD = 0, + OAM_MULTIPLEXER_ACTION_DISCARD, + OAM_MULTIPLEXER_ACTION_CPUONLY, + OAM_MULTIPLEXER_ACTION_END, + +} rtk_oam_multiplexer_act_t; + + +/* + * Function Declaration + */ + +/* Function Name: + * rtk_oam_init + * Description: + * Initialize oam module. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * Must initialize oam module before calling any oam APIs. + */ +extern rtk_api_ret_t rtk_oam_init(void); + +/* Function Name: + * rtk_oam_state_set + * Description: + * This API set OAM state. + * Input: + * enabled -OAMstate + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set OAM state. + */ +extern rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_oam_state_get + * Description: + * This API get OAM state. + * Input: + * None. + * Output: + * pEnabled - H/W IGMP state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current OAM state. + */ +extern rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled); + + +/* Module Name : OAM */ + +/* Function Name: + * rtk_oam_parserAction_set + * Description: + * Set OAM parser action + * Input: + * port - port id + * action - parser action + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +extern rtk_api_ret_t rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action); + +/* Function Name: + * rtk_oam_parserAction_set + * Description: + * Get OAM parser action + * Input: + * port - port id + * Output: + * pAction - parser action + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +extern rtk_api_ret_t rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction); + + +/* Function Name: + * rtk_oam_multiplexerAction_set + * Description: + * Set OAM multiplexer action + * Input: + * port - port id + * action - parser action + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +extern rtk_api_ret_t rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action); + +/* Function Name: + * rtk_oam_multiplexerAction_set + * Description: + * Get OAM multiplexer action + * Input: + * port - port id + * Output: + * pAction - parser action + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +extern rtk_api_ret_t rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction); + + +#endif /* __RTK_OAM_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/port.h b/drivers/net/phy/rtk/rtl8367c/include/port.h new file mode 100644 index 000000000000..458f16bf6d97 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/port.h @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes port module high-layer API definition + * + */ + +#ifndef __RTK_API_PORT_H__ +#define __RTK_API_PORT_H__ + +/* + * Data Type Declaration + */ + +#define PHY_CONTROL_REG 0 +#define PHY_STATUS_REG 1 +#define PHY_AN_ADVERTISEMENT_REG 4 +#define PHY_AN_LINKPARTNER_REG 5 +#define PHY_1000_BASET_CONTROL_REG 9 +#define PHY_1000_BASET_STATUS_REG 10 +#define PHY_RESOLVED_REG 26 + +#define RTK_EFID_MAX 0x7 + +#define RTK_FIBER_FORCE_1000M 3 +#define RTK_FIBER_FORCE_100M 5 +#define RTK_FIBER_FORCE_100M1000M 7 + +#define RTK_INDRECT_ACCESS_CRTL 0x1f00 +#define RTK_INDRECT_ACCESS_STATUS 0x1f01 +#define RTK_INDRECT_ACCESS_ADDRESS 0x1f02 +#define RTK_INDRECT_ACCESS_WRITE_DATA 0x1f03 +#define RTK_INDRECT_ACCESS_READ_DATA 0x1f04 +#define RTK_INDRECT_ACCESS_DELAY 0x1f80 +#define RTK_INDRECT_ACCESS_BURST 0x1f81 +#define RTK_RW_MASK 0x2 +#define RTK_CMD_MASK 0x1 +#define RTK_PHY_BUSY_OFFSET 2 + + +typedef enum rtk_mode_ext_e +{ + MODE_EXT_DISABLE = 0, + MODE_EXT_RGMII, + MODE_EXT_MII_MAC, + MODE_EXT_MII_PHY, + MODE_EXT_TMII_MAC, + MODE_EXT_TMII_PHY, + MODE_EXT_GMII, + MODE_EXT_RMII_MAC, + MODE_EXT_RMII_PHY, + MODE_EXT_SGMII, + MODE_EXT_HSGMII, + MODE_EXT_1000X_100FX, + MODE_EXT_1000X, + MODE_EXT_100FX, + MODE_EXT_RGMII_2, + MODE_EXT_MII_MAC_2, + MODE_EXT_MII_PHY_2, + MODE_EXT_TMII_MAC_2, + MODE_EXT_TMII_PHY_2, + MODE_EXT_RMII_MAC_2, + MODE_EXT_RMII_PHY_2, + MODE_EXT_END +} rtk_mode_ext_t; + +typedef enum rtk_port_duplex_e +{ + PORT_HALF_DUPLEX = 0, + PORT_FULL_DUPLEX, + PORT_DUPLEX_END +} rtk_port_duplex_t; + +typedef enum rtk_port_linkStatus_e +{ + PORT_LINKDOWN = 0, + PORT_LINKUP, + PORT_LINKSTATUS_END +} rtk_port_linkStatus_t; + +typedef struct rtk_port_mac_ability_s +{ + rtk_uint32 forcemode; + rtk_uint32 speed; + rtk_uint32 duplex; + rtk_uint32 link; + rtk_uint32 nway; + rtk_uint32 txpause; + rtk_uint32 rxpause; +}rtk_port_mac_ability_t; + +typedef struct rtk_port_phy_ability_s +{ + rtk_uint32 AutoNegotiation; /*PHY register 0.12 setting for auto-negotiation process*/ + rtk_uint32 Half_10; /*PHY register 4.5 setting for 10BASE-TX half duplex capable*/ + rtk_uint32 Full_10; /*PHY register 4.6 setting for 10BASE-TX full duplex capable*/ + rtk_uint32 Half_100; /*PHY register 4.7 setting for 100BASE-TX half duplex capable*/ + rtk_uint32 Full_100; /*PHY register 4.8 setting for 100BASE-TX full duplex capable*/ + rtk_uint32 Full_1000; /*PHY register 9.9 setting for 1000BASE-T full duplex capable*/ + rtk_uint32 FC; /*PHY register 4.10 setting for flow control capability*/ + rtk_uint32 AsyFC; /*PHY register 4.11 setting for asymmetric flow control capability*/ +} rtk_port_phy_ability_t; + +typedef rtk_uint32 rtk_port_phy_data_t; /* phy page */ + +typedef enum rtk_port_phy_mdix_mode_e +{ + PHY_AUTO_CROSSOVER_MODE= 0, + PHY_FORCE_MDI_MODE, + PHY_FORCE_MDIX_MODE, + PHY_FORCE_MODE_END +} rtk_port_phy_mdix_mode_t; + +typedef enum rtk_port_phy_mdix_status_e +{ + PHY_STATUS_AUTO_MDI_MODE= 0, + PHY_STATUS_AUTO_MDIX_MODE, + PHY_STATUS_FORCE_MDI_MODE, + PHY_STATUS_FORCE_MDIX_MODE, + PHY_STATUS_FORCE_MODE_END +} rtk_port_phy_mdix_status_t; + +typedef rtk_uint32 rtk_port_phy_page_t; /* phy page */ + +typedef enum rtk_port_phy_reg_e +{ + PHY_REG_CONTROL = 0, + PHY_REG_STATUS, + PHY_REG_IDENTIFIER_1, + PHY_REG_IDENTIFIER_2, + PHY_REG_AN_ADVERTISEMENT, + PHY_REG_AN_LINKPARTNER, + PHY_REG_1000_BASET_CONTROL = 9, + PHY_REG_1000_BASET_STATUS, + PHY_REG_END = 32 +} rtk_port_phy_reg_t; + +typedef enum rtk_port_phy_test_mode_e +{ + PHY_TEST_MODE_NORMAL= 0, + PHY_TEST_MODE_1, + PHY_TEST_MODE_2, + PHY_TEST_MODE_3, + PHY_TEST_MODE_4, + PHY_TEST_MODE_END +} rtk_port_phy_test_mode_t; + +typedef enum rtk_port_speed_e +{ + PORT_SPEED_10M = 0, + PORT_SPEED_100M, + PORT_SPEED_1000M, + PORT_SPEED_500M, + PORT_SPEED_2500M, + PORT_SPEED_END +} rtk_port_speed_t; + +typedef enum rtk_port_media_e +{ + PORT_MEDIA_COPPER = 0, + PORT_MEDIA_FIBER, + PORT_MEDIA_END +}rtk_port_media_t; + +typedef struct rtk_rtctResult_s +{ + rtk_port_speed_t linkType; + union + { + struct fe_result_s + { + rtk_uint32 isRxShort; + rtk_uint32 isTxShort; + rtk_uint32 isRxOpen; + rtk_uint32 isTxOpen; + rtk_uint32 isRxMismatch; + rtk_uint32 isTxMismatch; + rtk_uint32 isRxLinedriver; + rtk_uint32 isTxLinedriver; + rtk_uint32 rxLen; + rtk_uint32 txLen; + } fe_result; + + struct ge_result_s + { + rtk_uint32 channelAShort; + rtk_uint32 channelBShort; + rtk_uint32 channelCShort; + rtk_uint32 channelDShort; + + rtk_uint32 channelAOpen; + rtk_uint32 channelBOpen; + rtk_uint32 channelCOpen; + rtk_uint32 channelDOpen; + + rtk_uint32 channelAMismatch; + rtk_uint32 channelBMismatch; + rtk_uint32 channelCMismatch; + rtk_uint32 channelDMismatch; + + rtk_uint32 channelALinedriver; + rtk_uint32 channelBLinedriver; + rtk_uint32 channelCLinedriver; + rtk_uint32 channelDLinedriver; + + rtk_uint32 channelALen; + rtk_uint32 channelBLen; + rtk_uint32 channelCLen; + rtk_uint32 channelDLen; + } ge_result; + }result; +} rtk_rtctResult_t; + +/* Function Name: + * rtk_port_phyAutoNegoAbility_set + * Description: + * Set Ethernet PHY auto-negotiation desired ability. + * Input: + * port - port id. + * pAbility - Ability structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will + * be set as following 100F > 100H > 10F > 10H priority sequence. + */ +extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility); + +/* Function Name: + * rtk_port_phyAutoNegoAbility_get + * Description: + * Get PHY ability through PHY registers. + * Input: + * port - Port id. + * Output: + * pAbility - Ability structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * Get the capability of specified PHY. + */ +extern rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility); + +/* Function Name: + * rtk_port_phyForceModeAbility_set + * Description: + * Set the port speed/duplex mode/pause/asy_pause in the PHY force mode. + * Input: + * port - port id. + * pAbility - Ability structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will + * be set as following 100F > 100H > 10F > 10H priority sequence. + */ +extern rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility); + +/* Function Name: + * rtk_port_phyForceModeAbility_get + * Description: + * Get PHY ability through PHY registers. + * Input: + * port - Port id. + * Output: + * pAbility - Ability structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * Get the capability of specified PHY. + */ +extern rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility); + +/* Function Name: + * rtk_port_phyStatus_get + * Description: + * Get Ethernet PHY linking status + * Input: + * port - Port id. + * Output: + * linkStatus - PHY link status + * speed - PHY link speed + * duplex - PHY duplex mode + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * API will return auto negotiation status of phy. + */ +extern rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex); + +/* Function Name: + * rtk_port_macForceLink_set + * Description: + * Set port force linking configuration. + * Input: + * port - port id. + * pPortability - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can set Port/MAC force mode properties. + */ +extern rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability); + +/* Function Name: + * rtk_port_macForceLink_get + * Description: + * Get port force linking configuration. + * Input: + * port - Port id. + * Output: + * pPortability - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get Port/MAC force mode properties. + */ +extern rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability); + +/* Function Name: + * rtk_port_macForceLinkExt_set + * Description: + * Set external interface force linking configuration. + * Input: + * port - external port ID + * mode - external interface mode + * pPortability - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface force mode properties. + * The external interface can be set to: + * - MODE_EXT_DISABLE, + * - MODE_EXT_RGMII, + * - MODE_EXT_MII_MAC, + * - MODE_EXT_MII_PHY, + * - MODE_EXT_TMII_MAC, + * - MODE_EXT_TMII_PHY, + * - MODE_EXT_GMII, + * - MODE_EXT_RMII_MAC, + * - MODE_EXT_RMII_PHY, + * - MODE_EXT_SGMII, + * - MODE_EXT_HSGMII, + * - MODE_EXT_1000X_100FX, + * - MODE_EXT_1000X, + * - MODE_EXT_100FX, + */ +extern rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability); + +/* Function Name: + * rtk_port_macForceLinkExt_get + * Description: + * Set external interface force linking configuration. + * Input: + * port - external port ID + * Output: + * pMode - external interface mode + * pPortability - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get external interface force mode properties. + */ +extern rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability); + +/* Function Name: + * rtk_port_macStatus_get + * Description: + * Get port link status. + * Input: + * port - Port id. + * Output: + * pPortstatus - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get Port/PHY properties. + */ +extern rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus); + +/* Function Name: + * rtk_port_macLocalLoopbackEnable_set + * Description: + * Set Port Local Loopback. (Redirect TX to RX.) + * Input: + * port - Port id. + * enable - Loopback state, 0:disable, 1:enable + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can enable/disable Local loopback in MAC. + * For UTP port, This API will also enable the digital + * loopback bit in PHY register for sync of speed between + * PHY and MAC. For EXT port, users need to force the + * link state by themselves. + */ +extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_port_macLocalLoopbackEnable_get + * Description: + * Get Port Local Loopback. (Redirect TX to RX.) + * Input: + * port - Port id. + * Output: + * pEnable - Loopback state, 0:disable, 1:enable + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +extern rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_port_phyReg_set + * Description: + * Set PHY register data of the specific port. + * Input: + * port - port id. + * reg - Register id + * regData - Register data + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * This API can set PHY register data of the specific port. + */ +extern rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t value); + +/* Function Name: + * rtk_port_phyReg_get + * Description: + * Get PHY register data of the specific port. + * Input: + * port - Port id. + * reg - Register id + * Output: + * pData - Register data + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * This API can get PHY register data of the specific port. + */ +extern rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData); + +/* Function Name: + * rtk_port_backpressureEnable_set + * Description: + * Set the half duplex back-pressure enable status of the specific port. + * Input: + * port - port id. + * enable - Back pressure status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set the half duplex back-pressure enable status of the specific port. + * The half duplex back-pressure enable status of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_port_backpressureEnable_get + * Description: + * Get the half duplex back-pressure enable status of the specific port. + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get the half duplex back-pressure enable status of the specific port. + * The half duplex back-pressure enable status of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_port_adminEnable_set + * Description: + * Set port admin configuration of the specific port. + * Input: + * port - port id. + * enable - Back pressure status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set port admin configuration of the specific port. + * The port admin configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_port_adminEnable_get + * Description: + * Get port admin configuration of the specific port. + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get port admin configuration of the specific port. + * The port admin configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_port_isolation_set + * Description: + * Set permitted port isolation portmask + * Input: + * port - port id. + * pPortmask - Permit port mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * This API set the port mask that a port can transmit packet to of each port + * A port can only transmit packet to ports included in permitted portmask + */ +extern rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_port_isolation_get + * Description: + * Get permitted port isolation portmask + * Input: + * port - Port id. + * Output: + * pPortmask - Permit port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API get the port mask that a port can transmit packet to of each port + * A port can only transmit packet to ports included in permitted portmask + */ +extern rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_port_rgmiiDelayExt_set + * Description: + * Set RGMII interface delay value for TX and RX. + * Input: + * txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay + * rxDelay - RX delay value, 0~7 for delay setup. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface 2 RGMII delay. + * In TX delay, there are 2 selection: no-delay and 2ns delay. + * In RX delay, there are 8 steps for delay tuning. 0 for no-delay, and 7 for maximum delay. + */ +extern rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay); + +/* Function Name: + * rtk_port_rgmiiDelayExt_get + * Description: + * Get RGMII interface delay value for TX and RX. + * Input: + * None + * Output: + * pTxDelay - TX delay value + * pRxDelay - RX delay value + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface 2 RGMII delay. + * In TX delay, there are 2 selection: no-delay and 2ns delay. + * In RX delay, there are 8 steps for delay tuning. 0 for n0-delay, and 7 for maximum delay. + */ +extern rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay); + +/* Function Name: + * rtk_port_phyEnableAll_set + * Description: + * Set all PHY enable status. + * Input: + * enable - PHY Enable State. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set all PHY status. + * The configuration of all PHY is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable); + +/* Function Name: + * rtk_port_phyEnableAll_get + * Description: + * Get all PHY enable status. + * Input: + * None + * Output: + * pEnable - PHY Enable State. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API can set all PHY status. + * The configuration of all PHY is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_port_efid_set + * Description: + * Set port-based enhanced filtering database + * Input: + * port - Port id. + * efid - Specified enhanced filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid fid. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can set port-based enhanced filtering database. + */ +extern rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid); + +/* Function Name: + * rtk_port_efid_get + * Description: + * Get port-based enhanced filtering database + * Input: + * port - Port id. + * Output: + * pEfid - Specified enhanced filtering database. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get port-based enhanced filtering database status. + */ +extern rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid); + +/* Function Name: + * rtk_port_phyComboPortMedia_set + * Description: + * Set Combo port media type + * Input: + * port - Port id. (Should be Port 4) + * media - Media (COPPER or FIBER) + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can Set Combo port media type. + */ +extern rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media); + +/* Function Name: + * rtk_port_phyComboPortMedia_get + * Description: + * Get Combo port media type + * Input: + * port - Port id. (Should be Port 4) + * Output: + * pMedia - Media (COPPER or FIBER) + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can Set Combo port media type. + */ +extern rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia); + +/* Function Name: + * rtk_port_rtctEnable_set + * Description: + * Enable RTCT test + * Input: + * pPortmask - Port mask of RTCT enabled port + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * The API can enable RTCT Test + */ +extern rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_port_rtctDisable_set + * Description: + * Disable RTCT test + * Input: + * pPortmask - Port mask of RTCT disabled port + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * The API can disable RTCT Test + */ +rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask); + + +/* Function Name: + * rtk_port_rtctResult_get + * Description: + * Get the result of RTCT test + * Input: + * port - Port ID + * Output: + * pRtctResult - The result of RTCT result + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_PHY_RTCT_NOT_FINISH - Testing does not finish. + * Note: + * The API can get RTCT test result. + * RTCT test may takes 4.8 seconds to finish its test at most. + * Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or + * other error code, the result can not be referenced and + * user should call this API again until this API returns + * a RT_ERR_OK. + * The result is stored at pRtctResult->ge_result + * pRtctResult->linkType is unused. + * The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M + */ +extern rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult); + +/* Function Name: + * rtk_port_sds_reset + * Description: + * Reset Serdes + * Input: + * port - Port ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can reset Serdes + */ +extern rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port); + +/* Function Name: + * rtk_port_sgmiiLinkStatus_get + * Description: + * Get SGMII status + * Input: + * port - Port ID + * Output: + * pSignalDetect - Signal detect + * pSync - Sync + * pLink - Link + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can reset Serdes + */ +extern rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink); + +/* Function Name: + * rtk_port_sgmiiNway_set + * Description: + * Configure SGMII/HSGMII port Nway state + * Input: + * port - Port ID + * state - Nway state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API configure SGMII/HSGMII port Nway state + */ +extern rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state); + +/* Function Name: + * rtk_port_sgmiiNway_get + * Description: + * Get SGMII/HSGMII port Nway state + * Input: + * port - Port ID + * Output: + * pState - Nway state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get SGMII/HSGMII port Nway state + */ +extern rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState); + +#endif /* __RTK_API_PORT_H__ */ + + + diff --git a/drivers/net/phy/rtk/rtl8367c/include/ptp.h b/drivers/net/phy/rtk/rtl8367c/include/ptp.h new file mode 100644 index 000000000000..d18c4a01ed43 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/ptp.h @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes time module high-layer API definition + * + */ + +#ifndef __RTK_API_PTP_H__ +#define __RTK_API_PTP_H__ + +/* + * Symbol Definition + */ +#define RTK_MAX_NUM_OF_NANO_SECOND 0x3B9AC9FF +#define RTK_PTP_INTR_MASK 0xFF +#define RTK_MAX_NUM_OF_TPID 0xFFFF + +/* Message Type */ +typedef enum rtk_ptp_msgType_e +{ + PTP_MSG_TYPE_TX_SYNC = 0, + PTP_MSG_TYPE_TX_DELAY_REQ, + PTP_MSG_TYPE_TX_PDELAY_REQ, + PTP_MSG_TYPE_TX_PDELAY_RESP, + PTP_MSG_TYPE_RX_SYNC, + PTP_MSG_TYPE_RX_DELAY_REQ, + PTP_MSG_TYPE_RX_PDELAY_REQ, + PTP_MSG_TYPE_RX_PDELAY_RESP, + PTP_MSG_TYPE_END +} rtk_ptp_msgType_t; + +typedef enum rtk_ptp_intType_e +{ + PTP_INT_TYPE_TX_SYNC = 0, + PTP_INT_TYPE_TX_DELAY_REQ, + PTP_INT_TYPE_TX_PDELAY_REQ, + PTP_INT_TYPE_TX_PDELAY_RESP, + PTP_INT_TYPE_RX_SYNC, + PTP_INT_TYPE_RX_DELAY_REQ, + PTP_INT_TYPE_RX_PDELAY_REQ, + PTP_INT_TYPE_RX_PDELAY_RESP, + PTP_INT_TYPE_ALL, + PTP_INT_TYPE_END +}rtk_ptp_intType_t; + +typedef enum rtk_ptp_sys_adjust_e +{ + SYS_ADJUST_PLUS = 0, + SYS_ADJUST_MINUS, + SYS_ADJUST_END +} rtk_ptp_sys_adjust_t; + + +/* Reference Time */ +typedef struct rtk_ptp_timeStamp_s +{ + rtk_uint32 sec; + rtk_uint32 nsec; +} rtk_ptp_timeStamp_t; + +typedef struct rtk_ptp_info_s +{ + rtk_uint32 sequenceId; + rtk_ptp_timeStamp_t timeStamp; +} rtk_ptp_info_t; + +typedef rtk_uint32 rtk_ptp_tpid_t; + +typedef rtk_uint32 rtk_ptp_intStatus_t; /* interrupt status mask */ + +/* + * Data Declaration + */ + +/* + * Function Declaration + */ +/* Function Name: + * rtk_time_init + * Description: + * PTP function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API is used to initialize EEE status. + */ +extern rtk_api_ret_t rtk_ptp_init(void); + +/* Function Name: + * rtk_ptp_mac_set + * Description: + * Configure PTP mac address. + * Input: + * mac - mac address to parser PTP packets. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac); + +/* Function Name: + * rtk_ptp_mac_get + * Description: + * Get PTP mac address. + * Input: + * None + * Output: + * pMac - mac address to parser PTP packets. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac); + +/* Function Name: + * rtk_ptp_tpid_set + * Description: + * Configure PTP accepted outer & inner tag TPID. + * Input: + * outerId - Ether type of S-tag frame parsing in PTP ports. + * innerId - Ether type of C-tag frame parsing in PTP ports. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId); + +/* Function Name: + * rtk_ptp_tpid_get + * Description: + * Get PTP accepted outer & inner tag TPID. + * Input: + * None + * Output: + * pOuterId - Ether type of S-tag frame parsing in PTP ports. + * pInnerId - Ether type of C-tag frame parsing in PTP ports. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId); + +/* Function Name: + * rtk_ptp_refTime_set + * Description: + * Set the reference time of the specified device. + * Input: + * timeStamp - reference timestamp value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Applicable: + * 8390, 8380 + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp); + +/* Function Name: + * rtk_ptp_refTime_get + * Description: + * Get the reference time of the specified device. + * Input: + * Output: + * pTimeStamp - pointer buffer of the reference time + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp); + +/* Function Name: + * rtk_ptp_refTimeAdjust_set + * Description: + * Adjust the reference time. + * Input: + * unit - unit id + * sign - significant + * timeStamp - reference timestamp value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * sign=0 for positive adjustment, sign=1 for negative adjustment. + */ +extern rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp); + +/* Function Name: + * rtk_ptp_refTimeEnable_set + * Description: + * Set the enable state of reference time of the specified device. + * Input: + * enable - status + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable); + +/* Function Name: + * rtk_ptp_refTimeEnable_get + * Description: + * Get the enable state of reference time of the specified device. + * Input: + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_ptp_portEnable_set + * Description: + * Set PTP status of the specified port. + * Input: + * port - port id + * enable - status + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_ptp_portEnable_get + * Description: + * Get PTP status of the specified port. + * Input: + * port - port id + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_ptp_portTimestamp_get + * Description: + * Get PTP timestamp according to the PTP identifier on the dedicated port from the specified device. + * Input: + * unit - unit id + * port - port id + * type - PTP message type + * Output: + * pInfo - pointer buffer of sequence ID and timestamp + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo); + +/* Function Name: + * rtk_ptp_intControl_set + * Description: + * Set PTP interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * enable - Interrupt status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set PTP interrupt status configuration. + * The interrupt trigger status is shown in the following: + * PTP_INT_TYPE_TX_SYNC = 0, + * PTP_INT_TYPE_TX_DELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_RESP, + * PTP_INT_TYPE_RX_SYNC, + * PTP_INT_TYPE_RX_DELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_RESP, + * PTP_INT_TYPE_ALL, + */ +extern rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable); + +/* Function Name: + * rtk_ptp_intControl_get + * Description: + * Get PTP interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * Output: + * pEnable - Interrupt status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt status configuration. + * The interrupt trigger status is shown in the following: + * PTP_INT_TYPE_TX_SYNC = 0, + * PTP_INT_TYPE_TX_DELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_RESP, + * PTP_INT_TYPE_RX_SYNC, + * PTP_INT_TYPE_RX_DELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_RESP, + */ +extern rtk_api_ret_t rtk_ptp_intControl_get(rtk_ptp_intType_t type, rtk_enable_t *pEnable); + + +/* Function Name: + * rtk_ptp_intStatus_get + * Description: + * Get PTP port interrupt trigger status. + * Input: + * port - physical port + * Output: + * pStatusMask - Interrupt status bit mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - PORT 0 INT (value[0] (Bit0)) + * - PORT 1 INT (value[0] (Bit1)) + * - PORT 2 INT (value[0] (Bit2)) + * - PORT 3 INT (value[0] (Bit3)) + * - PORT 4 INT (value[0] (Bit4)) + + * + */ +extern rtk_api_ret_t rtk_ptp_intStatus_get(rtk_ptp_intStatus_t *pStatusMask); + +/* Function Name: + * rtk_ptp_portIntStatus_set + * Description: + * Set PTP port interrupt trigger status to clean. + * Input: + * port - physical port + * statusMask - Interrupt status bit mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can clean interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - PTP_INT_TYPE_TX_SYNC (value[0] (Bit0)) + * - PTP_INT_TYPE_TX_DELAY_REQ (value[0] (Bit1)) + * - PTP_INT_TYPE_TX_PDELAY_REQ (value[0] (Bit2)) + * - PTP_INT_TYPE_TX_PDELAY_RESP (value[0] (Bit3)) + * - PTP_INT_TYPE_RX_SYNC (value[0] (Bit4)) + * - PTP_INT_TYPE_RX_DELAY_REQ (value[0] (Bit5)) + * - PTP_INT_TYPE_RX_PDELAY_REQ (value[0] (Bit6)) + * - PTP_INT_TYPE_RX_PDELAY_RESP (value[0] (Bit7)) + * The status will be cleared after execute this API. + */ +extern rtk_api_ret_t rtk_ptp_portIntStatus_set(rtk_port_t port, rtk_ptp_intStatus_t statusMask); + +/* Function Name: + * rtk_ptp_portIntStatus_get + * Description: + * Get PTP port interrupt trigger status. + * Input: + * port - physical port + * Output: + * pStatusMask - Interrupt status bit mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - PTP_INT_TYPE_TX_SYNC (value[0] (Bit0)) + * - PTP_INT_TYPE_TX_DELAY_REQ (value[0] (Bit1)) + * - PTP_INT_TYPE_TX_PDELAY_REQ (value[0] (Bit2)) + * - PTP_INT_TYPE_TX_PDELAY_RESP (value[0] (Bit3)) + * - PTP_INT_TYPE_RX_SYNC (value[0] (Bit4)) + * - PTP_INT_TYPE_RX_DELAY_REQ (value[0] (Bit5)) + * - PTP_INT_TYPE_RX_PDELAY_REQ (value[0] (Bit6)) + * - PTP_INT_TYPE_RX_PDELAY_RESP (value[0] (Bit7)) + * + */ +extern rtk_api_ret_t rtk_ptp_portIntStatus_get(rtk_port_t port, rtk_ptp_intStatus_t *pStatusMask); + +/* Function Name: + * rtk_ptp_portPtpTrap_set + * Description: + * Set PTP packet trap of the specified port. + * Input: + * port - port id + * enable - status + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_portTrap_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_ptp_portPtpEnable_get + * Description: + * Get PTP packet trap of the specified port. + * Input: + * port - port id + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +extern rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable); + +#endif /* __RTK_API_PTP_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/qos.h b/drivers/net/phy/rtk/rtl8367c/include/qos.h new file mode 100644 index 000000000000..d2d8fac24a23 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/qos.h @@ -0,0 +1,781 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes QoS module high-layer API definition + * + */ + +#ifndef __RTK_API_QOS_H__ +#define __RTK_API_QOS_H__ + +/* + * Data Type Declaration + */ +#define QOS_DEFAULT_TICK_PERIOD (19-1) +#define QOS_DEFAULT_BYTE_PER_TOKEN 34 +#define QOS_DEFAULT_LK_THRESHOLD (34*3) /* Why use 0x400? */ + + +#define QOS_DEFAULT_INGRESS_BANDWIDTH 0x3FFF /* 0x3FFF => unlimit */ +#define QOS_DEFAULT_EGRESS_BANDWIDTH 0x3D08 /*( 0x3D08 + 1) * 64Kbps => 1Gbps*/ +#define QOS_DEFAULT_PREIFP 1 +#define QOS_DEFAULT_PACKET_USED_PAGES_FC 0x60 +#define QOS_DEFAULT_PACKET_USED_FC_EN 0 +#define QOS_DEFAULT_QUEUE_BASED_FC_EN 1 + +#define QOS_DEFAULT_PRIORITY_SELECT_PORT 8 +#define QOS_DEFAULT_PRIORITY_SELECT_1Q 0 +#define QOS_DEFAULT_PRIORITY_SELECT_ACL 0 +#define QOS_DEFAULT_PRIORITY_SELECT_DSCP 0 + +#define QOS_DEFAULT_DSCP_MAPPING_PRIORITY 0 + +#define QOS_DEFAULT_1Q_REMARKING_ABILITY 0 +#define QOS_DEFAULT_DSCP_REMARKING_ABILITY 0 +#define QOS_DEFAULT_QUEUE_GAP 20 +#define QOS_DEFAULT_QUEUE_NO_MAX 6 +#define QOS_DEFAULT_AVERAGE_PACKET_RATE 0x3FFF +#define QOS_DEFAULT_BURST_SIZE_IN_APR 0x3F +#define QOS_DEFAULT_PEAK_PACKET_RATE 2 +#define QOS_DEFAULT_SCHEDULER_ABILITY_APR 1 /*disable*/ +#define QOS_DEFAULT_SCHEDULER_ABILITY_PPR 1 /*disable*/ +#define QOS_DEFAULT_SCHEDULER_ABILITY_WFQ 1 /*disable*/ + +#define QOS_WEIGHT_MAX 127 + +#define RTK_MAX_NUM_OF_PRIORITY 8 +#define RTK_MAX_NUM_OF_QUEUE 8 + +#define RTK_PRIMAX 7 +#define RTK_QIDMAX 7 +#define RTK_DSCPMAX 63 + + +/* enum Priority Selection Index */ +typedef enum rtk_qos_priDecTbl_e +{ + PRIDECTBL_IDX0 = 0, + PRIDECTBL_IDX1, + PRIDECTBL_END, +}rtk_qos_priDecTbl_t; + + +/* Types of 802.1p remarking source */ +typedef enum rtk_qos_1pRmkSrc_e +{ + DOT1P_RMK_SRC_USER_PRI, + DOT1P_RMK_SRC_TAG_PRI, + DOT1P_RMK_SRC_END +} rtk_qos_1pRmkSrc_t; + + +/* Types of DSCP remarking source */ +typedef enum rtk_qos_dscpRmkSrc_e +{ + DSCP_RMK_SRC_INT_PRI, + DSCP_RMK_SRC_DSCP, + DSCP_RMK_SRC_USER_PRI, + DSCP_RMK_SRC_END +} rtk_qos_dscpRmkSrc_t; + + + + +typedef struct rtk_priority_select_s +{ + rtk_uint32 port_pri; + rtk_uint32 dot1q_pri; + rtk_uint32 acl_pri; + rtk_uint32 dscp_pri; + rtk_uint32 cvlan_pri; + rtk_uint32 svlan_pri; + rtk_uint32 dmac_pri; + rtk_uint32 smac_pri; +} rtk_priority_select_t; + +typedef struct rtk_qos_pri2queue_s +{ + rtk_uint32 pri2queue[RTK_MAX_NUM_OF_PRIORITY]; +} rtk_qos_pri2queue_t; + +typedef struct rtk_qos_queue_weights_s +{ + rtk_uint32 weights[RTK_MAX_NUM_OF_QUEUE]; +} rtk_qos_queue_weights_t; + +typedef enum rtk_qos_scheduling_type_e +{ + WFQ = 0, /* Weighted-Fair-Queue */ + WRR, /* Weighted-Round-Robin */ + SCHEDULING_TYPE_END +} rtk_qos_scheduling_type_t; + +typedef rtk_uint32 rtk_queue_num_t; /* queue number*/ + +/* Function Name: + * rtk_qos_init + * Description: + * Configure QoS default settings with queue number assignment to each port. + * Input: + * queueNum - Queue number of each port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QUEUE_NUM - Invalid queue number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API will initialize related QoS setting with queue number assignment. + * The queue number is from 1 to 8. + */ +extern rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum); + +/* Function Name: + * rtk_qos_priSel_set + * Description: + * Configure the priority order among different priority mechanism. + * Input: + * index - Priority decision table index (0~1) + * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter. + * Note: + * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. + * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to + * assign queue priority to receiving frame. + * The priority sources are: + * - PRIDEC_PORT + * - PRIDEC_ACL + * - PRIDEC_DSCP + * - PRIDEC_1Q + * - PRIDEC_1AD + * - PRIDEC_CVLAN + * - PRIDEC_DA + * - PRIDEC_SA + */ +extern rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec); + + +/* Function Name: + * rtk_qos_priSel_get + * Description: + * Get the priority order configuration among different priority mechanism. + * Input: + * index - Priority decision table index (0~1) + * Output: + * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision . + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. + * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to + * assign queue priority to receiving frame. + * The priority sources are: + * - PRIDEC_PORT, + * - PRIDEC_ACL, + * - PRIDEC_DSCP, + * - PRIDEC_1Q, + * - PRIDEC_1AD, + * - PRIDEC_CVLAN, + * - PRIDEC_DA, + * - PRIDEC_SA, + */ +extern rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec); + +/* Function Name: + * rtk_qos_1pPriRemap_set + * Description: + * Configure 1Q priorities mapping to internal absolute priority. + * Input: + * dot1p_pri - 802.1p priority value. + * int_pri - internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri); + +/* Function Name: + * rtk_qos_1pPriRemap_get + * Description: + * Get 1Q priorities mapping to internal absolute priority. + * Input: + * dot1p_pri - 802.1p priority value . + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri); + + +/* Function Name: + * rtk_qos_1pRemarkSrcSel_set + * Description: + * Set remarking source of 802.1p remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure 802.1p remark functionality to map original 802.1p value or internal + * priority to TX DSCP value. + */ +extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type); + +/* Function Name: + * rtk_qos_1pRemarkSrcSel_get + * Description: + * Get remarking source of 802.1p remarking. + * Input: + * none + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +extern rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType); + +/* Function Name: + * rtk_qos_dscpPriRemap_set + * Description: + * Map dscp value to internal priority. + * Input: + * dscp - Dscp value of receiving frame + * int_pri - internal priority value . + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically + * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of + * DSCP are carefully chosen then backward compatibility can be achieved. + */ +extern rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri); + +/* Function Name: + * rtk_qos_dscpPriRemap_get + * Description: + * Get dscp value to internal priority. + * Input: + * dscp - Dscp value of receiving frame + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * Note: + * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically + * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of + * DSCP are carefully chosen then backward compatibility can be achieved. + */ +extern rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri); + +/* Function Name: + * rtk_qos_portPri_set + * Description: + * Configure priority usage to each port. + * Input: + * port - Port id. + * int_pri - internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can set priority of port assignments for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) ; + +/* Function Name: + * rtk_qos_portPri_get + * Description: + * Get priority usage to each port. + * Input: + * port - Port id. + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get priority of port assignments for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) ; + +/* Function Name: + * rtk_qos_queueNum_set + * Description: + * Set output queue number for each port. + * Input: + * port - Port id. + * index - Mapping queue number (1~8) + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * Note: + * The API can set the output queue number of the specified port. The queue number is from 1 to 8. + */ +extern rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num); + +/* Function Name: + * rtk_qos_queueNum_get + * Description: + * Get output queue number. + * Input: + * port - Port id. + * Output: + * pQueue_num - Mapping queue number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API will return the output queue number of the specified port. The queue number is from 1 to 8. + */ +extern rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num); + +/* Function Name: + * rtk_qos_priMap_set + * Description: + * Set output queue number for each port. + * Input: + * queue_num - Queue number usage. + * pPri2qid - Priority mapping to queue ID. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * RT_ERR_QUEUE_ID - Invalid queue id. + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * ASIC supports priority mapping to queue with different queue number from 1 to 8. + * For different queue numbers usage, ASIC supports different internal available queue IDs. + */ +extern rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid); + + +/* Function Name: + * rtk_qos_priMap_get + * Description: + * Get priority to queue ID mapping table parameters. + * Input: + * queue_num - Queue number usage. + * Output: + * pPri2qid - Priority mapping to queue ID. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * Note: + * The API can return the mapping queue id of the specified priority and queue number. + * The queue number is from 1 to 8. + */ +extern rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid); + +/* Function Name: + * rtk_qos_schedulingQueue_set + * Description: + * Set weight and type of queues in dedicated port. + * Input: + * port - Port id. + * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight. + * Note: + * The API can set weight and type, strict priority or weight fair queue (WFQ) for + * dedicated port for using queues. If queue id is not included in queue usage, + * then its type and weight setting in dummy for setting. There are priorities + * as queue id in strict queues. It means strict queue id 5 carrying higher priority + * than strict queue id 4. The WFQ queue weight is from 1 to 128, and weight 0 is + * for strict priority queue type. + */ +extern rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights); + +/* Function Name: + * rtk_qos_schedulingQueue_get + * Description: + * Get weight and type of queues in dedicated port. + * Input: + * port - Port id. + * Output: + * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues. + * The WFQ queue weight is from 1 to 128, and weight 0 is for strict priority queue type. + */ +extern rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights); + +/* Function Name: + * rtk_qos_1pRemarkEnable_set + * Description: + * Set 1p Remarking state + * Input: + * port - Port id. + * enable - State of per-port 1p Remarking + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable parameter. + * Note: + * The API can enable or disable 802.1p remarking ability for whole system. + * The status of 802.1p remark: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_qos_1pRemarkEnable_get + * Description: + * Get 802.1p remarking ability. + * Input: + * port - Port id. + * Output: + * pEnable - Status of 802.1p remark. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1p remarking ability. + * The status of 802.1p remark: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_qos_1pRemark_set + * Description: + * Set 802.1p remarking parameter. + * Input: + * int_pri - Internal priority value. + * dot1p_pri - 802.1p priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can set 802.1p parameters source priority and new priority. + */ +extern rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri); + +/* Function Name: + * rtk_qos_1pRemark_get + * Description: + * Get 802.1p remarking parameter. + * Input: + * int_pri - Internal priority value. + * Output: + * pDot1p_pri - 802.1p priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can get 802.1p remarking parameters. It would return new priority of ingress priority. + */ +extern rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri); + +/* Function Name: + * rtk_qos_dscpRemarkEnable_set + * Description: + * Set DSCP remarking ability. + * Input: + * port - Port id. + * enable - status of DSCP remark. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * RT_ERR_ENABLE - Invalid enable parameter. + * Note: + * The API can enable or disable DSCP remarking ability for whole system. + * The status of DSCP remark: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_qos_dscpRemarkEnable_get + * Description: + * Get DSCP remarking ability. + * Input: + * port - Port id. + * Output: + * pEnable - status of DSCP remarking. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get DSCP remarking ability. + * The status of DSCP remark: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_qos_dscpRemark_set + * Description: + * Set DSCP remarking parameter. + * Input: + * int_pri - Internal priority value. + * dscp - DSCP value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * Note: + * The API can set DSCP value and mapping priority. + */ +extern rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp); + +/* Function Name: + * rtk_qos_dscpRemark_get + * Description: + * Get DSCP remarking parameter. + * Input: + * int_pri - Internal priority value. + * Output: + * Dscp - DSCP value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can get DSCP parameters. It would return DSCP value for mapping priority. + */ +extern rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp); + +/* Function Name: + * rtk_qos_dscpRemarkSrcSel_set + * Description: + * Set remarking source of DSCP remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure DSCP remark functionality to map original DSCP value or internal + * priority to TX DSCP value. + */ +extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type); + + +/* Function Name: + * rtk_qos_dcpRemarkSrcSel_get + * Description: + * Get remarking source of DSCP remarking. + * Input: + * none + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +extern rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType); + + +/* Function Name: + * rtk_qos_dscpRemark2Dscp_set + * Description: + * Set DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * rmkDscp - remarked DSCP value + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * Note: + * dscp parameter can be DSCP value or internal priority according to configuration of API + * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP + * value or internal priority to TX DSCP value. + */ +extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp); + +/* Function Name: + * rtk_qos_dscpRemark2Dscp_get + * Description: + * Get DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * Output: + * pDscp - remarked DSCP value + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * None. + */ +extern rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp); + +/* Function Name: + * rtk_qos_portPriSelIndex_set + * Description: + * Configure priority decision index to each port. + * Input: + * port - Port id. + * index - priority decision index. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENTRY_INDEX - Invalid entry index. + * Note: + * The API can set priority of port assignments for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index); + +/* Function Name: + * rtk_qos_portPriSelIndex_get + * Description: + * Get priority decision index from each port. + * Input: + * port - Port id. + * Output: + * pIndex - priority decision index. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get priority of port assignments for queue usage and packet scheduling. + */ +extern rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex); + +#endif /* __RTK_API_QOS_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/rate.h b/drivers/net/phy/rtk/rtl8367c/include/rate.h new file mode 100644 index 000000000000..b3cdf432f747 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rate.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes rate module high-layer API definition + * + */ + +#ifndef __RTK_API_RATE_H__ +#define __RTK_API_RATE_H__ + +/* + * Include Files + */ +//#include + +/* + * Data Type Declaration + */ +#define RTK_MAX_METER_ID (rtk_switch_maxMeterId_get()) +#define RTK_METER_NUM (RTK_MAX_METER_ID + 1) + +typedef enum rtk_meter_type_e{ + METER_TYPE_KBPS = 0, /* Kbps */ + METER_TYPE_PPS, /* Packet per second */ + METER_TYPE_END +}rtk_meter_type_t; + + +/* + * Function Declaration + */ + + /* Rate */ +/* Function Name: + * rtk_rate_shareMeter_set + * Description: + * Set meter configuration + * Input: + * index - shared meter index + * type - shared meter type + * rate - rate of share meter + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * RT_ERR_RATE - Invalid rate + * RT_ERR_INPUT - Invalid input parameters + * Note: + * The API can set shared meter rate and ifg include for each meter. + * The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and + * the granularity of rate is 8 kbps. + * The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS. + * The ifg_include parameter is used + * for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include); + +/* Function Name: + * rtk_rate_shareMeter_get + * Description: + * Get meter configuration + * Input: + * index - shared meter index + * Output: + * pType - Meter Type + * pRate - pointer of rate of share meter + * pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * + */ +rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include); + +/* Function Name: + * rtk_rate_shareMeterBucket_set + * Description: + * Set meter Bucket Size + * Input: + * index - shared meter index + * bucket_size - Bucket Size + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Error Input + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * The API can set shared meter bucket size. + */ +extern rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size); + +/* Function Name: + * rtk_rate_shareMeterBucket_get + * Description: + * Get meter Bucket Size + * Input: + * index - shared meter index + * Output: + * pBucket_size - Bucket Size + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * The API can get shared meter bucket size. + */ +extern rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size); + +/* Function Name: + * rtk_rate_igrBandwidthCtrlRate_set + * Description: + * Set port ingress bandwidth control + * Input: + * port - Port id + * rate - Rate of share meter + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * fc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid IFG parameter. + * RT_ERR_INBW_RATE - Invalid ingress rate parameter. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include, rtk_enable_t fc_enable); + +/* Function Name: + * rtk_rate_igrBandwidthCtrlRate_get + * Description: + * Get port ingress bandwidth control + * Input: + * port - Port id + * Output: + * pRate - Rate of share meter + * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude + * pFc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +extern rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable); + +/* Function Name: + * rtk_rate_egrBandwidthCtrlRate_set + * Description: + * Set port egress bandwidth control + * Input: + * port - Port id + * rate - Rate of egress bandwidth + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_includ); + +/* Function Name: + * rtk_rate_egrBandwidthCtrlRate_get + * Description: + * Get port egress bandwidth control + * Input: + * port - Port id + * Output: + * pRate - Rate of egress bandwidth + * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +extern rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include); + +/* Function Name: + * rtk_rate_egrQueueBwCtrlEnable_set + * Description: + * Set enable status of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * enable - enable status of egress queue bandwidth control + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable); + +/* Function Name: + * rtk_rate_egrQueueBwCtrlRate_get + * Description: + * Get rate of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * pIndex - shared meter index + * Output: + * pRate - pointer to rate of egress queue bandwidth control + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter id + * Note: + * None. + */ +extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_rate_egrQueueBwCtrlRate_set + * Description: + * Set rate of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * index - shared meter index + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter id + * Note: + * The actual rate control is set in shared meters. + * The unit of granularity is 8Kbps. + */ +extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index); + +/* Function Name: + * rtk_rate_egrQueueBwCtrlRate_get + * Description: + * Get rate of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * pIndex - shared meter index + * Output: + * pRate - pointer to rate of egress queue bandwidth control + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter id + * Note: + * The actual rate control is set in shared meters. + * The unit of granularity is 8Kbps. + */ +extern rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex); + +#endif /* __RTK_API_RATE_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rldp.h b/drivers/net/phy/rtk/rtl8367c/include/rldp.h new file mode 100644 index 000000000000..111de0c09377 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rldp.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : Declaration of RLDP and RLPP API + * + * Feature : The file have include the following module and sub-modules + * 1) RLDP and RLPP configuration and status + * + */ + + +#ifndef __RTK_RLDP_H__ +#define __RTK_RLDP_H__ + + +/* + * Include Files + */ + + +/* + * Symbol Definition + */ +typedef enum rtk_rldp_trigger_e +{ + RTK_RLDP_TRIGGER_SAMOVING = 0, + RTK_RLDP_TRIGGER_PERIOD, + RTK_RLDP_TRIGGER_END +} rtk_rldp_trigger_t; + +typedef enum rtk_rldp_cmpType_e +{ + RTK_RLDP_CMPTYPE_MAGIC = 0, /* Compare the RLDP with magic only */ + RTK_RLDP_CMPTYPE_MAGIC_ID, /* Compare the RLDP with both magic + ID */ + RTK_RLDP_CMPTYPE_END +} rtk_rldp_cmpType_t; + +typedef enum rtk_rldp_loopStatus_e +{ + RTK_RLDP_LOOPSTS_NONE = 0, + RTK_RLDP_LOOPSTS_LOOPING, + RTK_RLDP_LOOPSTS_END +} rtk_rldp_loopStatus_t; + +typedef enum rtk_rlpp_trapType_e +{ + RTK_RLPP_TRAPTYPE_NONE = 0, + RTK_RLPP_TRAPTYPE_CPU, + RTK_RLPP_TRAPTYPE_END +} rtk_rlpp_trapType_t; + +typedef struct rtk_rldp_config_s +{ + rtk_enable_t rldp_enable; + rtk_rldp_trigger_t trigger_mode; + rtk_mac_t magic; + rtk_rldp_cmpType_t compare_type; + rtk_uint32 interval_check; /* Checking interval for check state */ + rtk_uint32 num_check; /* Checking number for check state */ + rtk_uint32 interval_loop; /* Checking interval for loop state */ + rtk_uint32 num_loop; /* Checking number for loop state */ +} rtk_rldp_config_t; + +typedef struct rtk_rldp_portConfig_s +{ + rtk_enable_t tx_enable; +} rtk_rldp_portConfig_t; + +typedef struct rtk_rldp_status_s +{ + rtk_mac_t id; +} rtk_rldp_status_t; + +typedef struct rtk_rldp_portStatus_s +{ + rtk_rldp_loopStatus_t loop_status; + rtk_rldp_loopStatus_t loop_enter; + rtk_rldp_loopStatus_t loop_leave; +} rtk_rldp_portStatus_t; + +/* + * Data Declaration + */ + + +/* + * Macro Declaration + */ + +#define RTK_RLDP_INTERVAL_MAX 0xffff +#define RTK_RLDP_NUM_MAX 0xff + + +/* + * Function Declaration + */ + +/* Module Name : RLDP */ + + +/* Function Name: + * rtk_rldp_config_set + * Description: + * Set RLDP module configuration + * Input: + * pConfig - configuration structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig); + + +/* Function Name: + * rtk_rldp_config_get + * Description: + * Get RLDP module configuration + * Input: + * None + * Output: + * pConfig - configuration structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig); + + +/* Function Name: + * rtk_rldp_portConfig_set + * Description: + * Set per port RLDP module configuration + * Input: + * port - port number to be configured + * pPortConfig - per port configuration structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig); + + +/* Function Name: + * rtk_rldp_portConfig_get + * Description: + * Get per port RLDP module configuration + * Input: + * port - port number to be get + * Output: + * pPortConfig - per port configuration structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_portConfig_get(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig); + + +/* Function Name: + * rtk_rldp_status_get + * Description: + * Get RLDP module status + * Input: + * None + * Output: + * pStatus - status structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus); + + +/* Function Name: + * rtk_rldp_portStatus_get + * Description: + * Get RLDP module status + * Input: + * port - port number to be get + * Output: + * pPortStatus - per port status structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus); + + +/* Function Name: + * rtk_rldp_portStatus_clear + * Description: + * Clear RLDP module status + * Input: + * port - port number to be clear + * pPortStatus - per port status structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * Clear operation effect loop_enter and loop_leave only, other field in + * the structure are don't care + */ +extern rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus); + + +/* Function Name: + * rtk_rldp_portLoopPair_get + * Description: + * Get RLDP port loop pairs + * Input: + * port - port number to be get + * Output: + * pPortmask - per port related loop ports + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +extern rtk_api_ret_t rtk_rldp_portLoopPair_get(rtk_port_t port, rtk_portmask_t *pPortmask); + +#endif /* __RTK_RLDP_H__ */ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h new file mode 100644 index 000000000000..54d1a13f3bee --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_error.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : Definition the error number in the SDK. + * Feature : error definition + * + */ + +#ifndef __COMMON_RT_ERROR_H__ +#define __COMMON_RT_ERROR_H__ + +/* + * Include Files + */ + +/* + * Data Type Declaration + */ +typedef enum rt_error_code_e +{ + RT_ERR_FAILED = -1, /* General Error */ + + /* 0x0000xxxx for common error code */ + RT_ERR_OK = 0, /* 0x00000000, OK */ + RT_ERR_INPUT, /* 0x00000001, invalid input parameter */ + RT_ERR_UNIT_ID, /* 0x00000002, invalid unit id */ + RT_ERR_PORT_ID, /* 0x00000003, invalid port id */ + RT_ERR_PORT_MASK, /* 0x00000004, invalid port mask */ + RT_ERR_PORT_LINKDOWN, /* 0x00000005, link down port status */ + RT_ERR_ENTRY_INDEX, /* 0x00000006, invalid entry index */ + RT_ERR_NULL_POINTER, /* 0x00000007, input parameter is null pointer */ + RT_ERR_QUEUE_ID, /* 0x00000008, invalid queue id */ + RT_ERR_QUEUE_NUM, /* 0x00000009, invalid queue number */ + RT_ERR_BUSYWAIT_TIMEOUT, /* 0x0000000a, busy waiting time out */ + RT_ERR_MAC, /* 0x0000000b, invalid mac address */ + RT_ERR_OUT_OF_RANGE, /* 0x0000000c, input parameter out of range */ + RT_ERR_CHIP_NOT_SUPPORTED, /* 0x0000000d, functions not supported by this chip model */ + RT_ERR_SMI, /* 0x0000000e, SMI error */ + RT_ERR_NOT_INIT, /* 0x0000000f, The module is not initial */ + RT_ERR_CHIP_NOT_FOUND, /* 0x00000010, The chip can not found */ + RT_ERR_NOT_ALLOWED, /* 0x00000011, actions not allowed by the function */ + RT_ERR_DRIVER_NOT_FOUND, /* 0x00000012, The driver can not found */ + RT_ERR_SEM_LOCK_FAILED, /* 0x00000013, Failed to lock semaphore */ + RT_ERR_SEM_UNLOCK_FAILED, /* 0x00000014, Failed to unlock semaphore */ + RT_ERR_ENABLE, /* 0x00000015, invalid enable parameter */ + RT_ERR_TBL_FULL, /* 0x00000016, input table full */ + + /* 0x0001xxxx for vlan */ + RT_ERR_VLAN_VID = 0x00010000, /* 0x00010000, invalid vid */ + RT_ERR_VLAN_PRIORITY, /* 0x00010001, invalid 1p priority */ + RT_ERR_VLAN_EMPTY_ENTRY, /* 0x00010002, empty entry of vlan table */ + RT_ERR_VLAN_ACCEPT_FRAME_TYPE, /* 0x00010003, invalid accept frame type */ + RT_ERR_VLAN_EXIST, /* 0x00010004, vlan is exist */ + RT_ERR_VLAN_ENTRY_NOT_FOUND, /* 0x00010005, specified vlan entry not found */ + RT_ERR_VLAN_PORT_MBR_EXIST, /* 0x00010006, member port exist in the specified vlan */ + RT_ERR_VLAN_PROTO_AND_PORT, /* 0x00010008, invalid protocol and port based vlan */ + + /* 0x0002xxxx for svlan */ + RT_ERR_SVLAN_ENTRY_INDEX = 0x00020000, /* 0x00020000, invalid svid entry no */ + RT_ERR_SVLAN_ETHER_TYPE, /* 0x00020001, invalid SVLAN ether type */ + RT_ERR_SVLAN_TABLE_FULL, /* 0x00020002, no empty entry in SVLAN table */ + RT_ERR_SVLAN_ENTRY_NOT_FOUND, /* 0x00020003, specified svlan entry not found */ + RT_ERR_SVLAN_EXIST, /* 0x00020004, SVLAN entry is exist */ + RT_ERR_SVLAN_VID, /* 0x00020005, invalid svid */ + + /* 0x0003xxxx for MSTP */ + RT_ERR_MSTI = 0x00030000, /* 0x00030000, invalid msti */ + RT_ERR_MSTP_STATE, /* 0x00030001, invalid spanning tree status */ + RT_ERR_MSTI_EXIST, /* 0x00030002, MSTI exist */ + RT_ERR_MSTI_NOT_EXIST, /* 0x00030003, MSTI not exist */ + + /* 0x0004xxxx for BUCKET */ + RT_ERR_TIMESLOT = 0x00040000, /* 0x00040000, invalid time slot */ + RT_ERR_TOKEN, /* 0x00040001, invalid token amount */ + RT_ERR_RATE, /* 0x00040002, invalid rate */ + RT_ERR_TICK, /* 0x00040003, invalid tick */ + + /* 0x0005xxxx for RMA */ + RT_ERR_RMA_ADDR = 0x00050000, /* 0x00050000, invalid rma mac address */ + RT_ERR_RMA_ACTION, /* 0x00050001, invalid rma action */ + + /* 0x0006xxxx for L2 */ + RT_ERR_L2_HASH_KEY = 0x00060000, /* 0x00060000, invalid L2 Hash key */ + RT_ERR_L2_HASH_INDEX, /* 0x00060001, invalid L2 Hash index */ + RT_ERR_L2_CAM_INDEX, /* 0x00060002, invalid L2 CAM index */ + RT_ERR_L2_ENRTYSEL, /* 0x00060003, invalid EntrySel */ + RT_ERR_L2_INDEXTABLE_INDEX, /* 0x00060004, invalid L2 index table(=portMask table) index */ + RT_ERR_LIMITED_L2ENTRY_NUM, /* 0x00060005, invalid limited L2 entry number */ + RT_ERR_L2_AGGREG_PORT, /* 0x00060006, this aggregated port is not the lowest physical + port of its aggregation group */ + RT_ERR_L2_FID, /* 0x00060007, invalid fid */ + RT_ERR_L2_VID, /* 0x00060008, invalid cvid */ + RT_ERR_L2_NO_EMPTY_ENTRY, /* 0x00060009, no empty entry in L2 table */ + RT_ERR_L2_ENTRY_NOTFOUND, /* 0x0006000a, specified entry not found */ + RT_ERR_L2_INDEXTBL_FULL, /* 0x0006000b, the L2 index table is full */ + RT_ERR_L2_INVALID_FLOWTYPE, /* 0x0006000c, invalid L2 flow type */ + RT_ERR_L2_L2UNI_PARAM, /* 0x0006000d, invalid L2 unicast parameter */ + RT_ERR_L2_L2MULTI_PARAM, /* 0x0006000e, invalid L2 multicast parameter */ + RT_ERR_L2_IPMULTI_PARAM, /* 0x0006000f, invalid L2 ip multicast parameter */ + RT_ERR_L2_PARTIAL_HASH_KEY, /* 0x00060010, invalid L2 partial Hash key */ + RT_ERR_L2_EMPTY_ENTRY, /* 0x00060011, the entry is empty(invalid) */ + RT_ERR_L2_FLUSH_TYPE, /* 0x00060012, the flush type is invalid */ + RT_ERR_L2_NO_CPU_PORT, /* 0x00060013, CPU port not exist */ + + /* 0x0007xxxx for FILTER (PIE) */ + RT_ERR_FILTER_BLOCKNUM = 0x00070000, /* 0x00070000, invalid block number */ + RT_ERR_FILTER_ENTRYIDX, /* 0x00070001, invalid entry index */ + RT_ERR_FILTER_CUTLINE, /* 0x00070002, invalid cutline value */ + RT_ERR_FILTER_FLOWTBLBLOCK, /* 0x00070003, block belongs to flow table */ + RT_ERR_FILTER_INACLBLOCK, /* 0x00070004, block belongs to ingress ACL */ + RT_ERR_FILTER_ACTION, /* 0x00070005, action doesn't consist to entry type */ + RT_ERR_FILTER_INACL_RULENUM, /* 0x00070006, invalid ACL rulenum */ + RT_ERR_FILTER_INACL_TYPE, /* 0x00070007, entry type isn't an ingress ACL rule */ + RT_ERR_FILTER_INACL_EXIST, /* 0x00070008, ACL entry is already exit */ + RT_ERR_FILTER_INACL_EMPTY, /* 0x00070009, ACL entry is empty */ + RT_ERR_FILTER_FLOWTBL_TYPE, /* 0x0007000a, entry type isn't an flow table rule */ + RT_ERR_FILTER_FLOWTBL_RULENUM, /* 0x0007000b, invalid flow table rulenum */ + RT_ERR_FILTER_FLOWTBL_EMPTY, /* 0x0007000c, flow table entry is empty */ + RT_ERR_FILTER_FLOWTBL_EXIST, /* 0x0007000d, flow table entry is already exist */ + RT_ERR_FILTER_METER_ID, /* 0x0007000e, invalid metering id */ + RT_ERR_FILTER_LOG_ID, /* 0x0007000f, invalid log id */ + RT_ERR_FILTER_INACL_NONE_BEGIN_IDX, /* 0x00070010, entry index is not starting index of a group of rules */ + RT_ERR_FILTER_INACL_ACT_NOT_SUPPORT, /* 0x00070011, action not support */ + RT_ERR_FILTER_INACL_RULE_NOT_SUPPORT, /* 0x00070012, rule not support */ + + /* 0x0008xxxx for ACL Rate Limit */ + RT_ERR_ACLRL_HTHR = 0x00080000, /* 0x00080000, invalid high threshold */ + RT_ERR_ACLRL_TIMESLOT, /* 0x00080001, invalid time slot */ + RT_ERR_ACLRL_TOKEN, /* 0x00080002, invalid token amount */ + RT_ERR_ACLRL_RATE, /* 0x00080003, invalid rate */ + + /* 0x0009xxxx for Link aggregation */ + RT_ERR_LA_CPUPORT = 0x00090000, /* 0x00090000, CPU port can not be aggregated port */ + RT_ERR_LA_TRUNK_ID, /* 0x00090001, invalid trunk id */ + RT_ERR_LA_PORTMASK, /* 0x00090002, invalid port mask */ + RT_ERR_LA_HASHMASK, /* 0x00090003, invalid hash mask */ + RT_ERR_LA_DUMB, /* 0x00090004, this API should be used in 802.1ad dumb mode */ + RT_ERR_LA_PORTNUM_DUMB, /* 0x00090005, it can only aggregate at most four ports when 802.1ad dumb mode */ + RT_ERR_LA_PORTNUM_NORMAL, /* 0x00090006, it can only aggregate at most eight ports when 802.1ad normal mode */ + RT_ERR_LA_MEMBER_OVERLAP, /* 0x00090007, the specified port mask is overlapped with other group */ + RT_ERR_LA_NOT_MEMBER_PORT, /* 0x00090008, the port is not a member port of the trunk */ + RT_ERR_LA_TRUNK_NOT_EXIST, /* 0x00090009, the trunk doesn't exist */ + + + /* 0x000axxxx for storm filter */ + RT_ERR_SFC_TICK_PERIOD = 0x000a0000, /* 0x000a0000, invalid SFC tick period */ + RT_ERR_SFC_UNKNOWN_GROUP, /* 0x000a0001, Unknown Storm filter group */ + + /* 0x000bxxxx for pattern match */ + RT_ERR_PM_MASK = 0x000b0000, /* 0x000b0000, invalid pattern length. Pattern length should be 8 */ + RT_ERR_PM_LENGTH, /* 0x000b0001, invalid pattern match mask, first byte must care */ + RT_ERR_PM_MODE, /* 0x000b0002, invalid pattern match mode */ + + /* 0x000cxxxx for input bandwidth control */ + RT_ERR_INBW_TICK_PERIOD = 0x000c0000, /* 0x000c0000, invalid tick period for input bandwidth control */ + RT_ERR_INBW_TOKEN_AMOUNT, /* 0x000c0001, invalid amount of token for input bandwidth control */ + RT_ERR_INBW_FCON_VALUE, /* 0x000c0002, invalid flow control ON threshold value for input bandwidth control */ + RT_ERR_INBW_FCOFF_VALUE, /* 0x000c0003, invalid flow control OFF threshold value for input bandwidth control */ + RT_ERR_INBW_FC_ALLOWANCE, /* 0x000c0004, invalid allowance of incoming packet for input bandwidth control */ + RT_ERR_INBW_RATE, /* 0x000c0005, invalid input bandwidth */ + + /* 0x000dxxxx for QoS */ + RT_ERR_QOS_1P_PRIORITY = 0x000d0000, /* 0x000d0000, invalid 802.1P priority */ + RT_ERR_QOS_DSCP_VALUE, /* 0x000d0001, invalid DSCP value */ + RT_ERR_QOS_INT_PRIORITY, /* 0x000d0002, invalid internal priority */ + RT_ERR_QOS_SEL_DSCP_PRI, /* 0x000d0003, invalid DSCP selection priority */ + RT_ERR_QOS_SEL_PORT_PRI, /* 0x000d0004, invalid port selection priority */ + RT_ERR_QOS_SEL_IN_ACL_PRI, /* 0x000d0005, invalid ingress ACL selection priority */ + RT_ERR_QOS_SEL_CLASS_PRI, /* 0x000d0006, invalid classifier selection priority */ + RT_ERR_QOS_EBW_RATE, /* 0x000d0007, invalid egress bandwidth rate */ + RT_ERR_QOS_SCHE_TYPE, /* 0x000d0008, invalid QoS scheduling type */ + RT_ERR_QOS_QUEUE_WEIGHT, /* 0x000d0009, invalid Queue weight */ + RT_ERR_QOS_SEL_PRI_SOURCE, /* 0x000d000a, invalid selection of priority source */ + + /* 0x000exxxx for port ability */ + RT_ERR_PHY_PAGE_ID = 0x000e0000, /* 0x000e0000, invalid PHY page id */ + RT_ERR_PHY_REG_ID, /* 0x000e0001, invalid PHY reg id */ + RT_ERR_PHY_DATAMASK, /* 0x000e0002, invalid PHY data mask */ + RT_ERR_PHY_AUTO_NEGO_MODE, /* 0x000e0003, invalid PHY auto-negotiation mode*/ + RT_ERR_PHY_SPEED, /* 0x000e0004, invalid PHY speed setting */ + RT_ERR_PHY_DUPLEX, /* 0x000e0005, invalid PHY duplex setting */ + RT_ERR_PHY_FORCE_ABILITY, /* 0x000e0006, invalid PHY force mode ability parameter */ + RT_ERR_PHY_FORCE_1000, /* 0x000e0007, invalid PHY force mode 1G speed setting */ + RT_ERR_PHY_TXRX, /* 0x000e0008, invalid PHY tx/rx */ + RT_ERR_PHY_ID, /* 0x000e0009, invalid PHY id */ + RT_ERR_PHY_RTCT_NOT_FINISH, /* 0x000e000a, PHY RTCT in progress */ + + /* 0x000fxxxx for mirror */ + RT_ERR_MIRROR_DIRECTION = 0x000f0000, /* 0x000f0000, invalid error mirror direction */ + RT_ERR_MIRROR_SESSION_FULL, /* 0x000f0001, mirroring session is full */ + RT_ERR_MIRROR_SESSION_NOEXIST, /* 0x000f0002, mirroring session not exist */ + RT_ERR_MIRROR_PORT_EXIST, /* 0x000f0003, mirroring port already exists */ + RT_ERR_MIRROR_PORT_NOT_EXIST, /* 0x000f0004, mirroring port does not exists */ + RT_ERR_MIRROR_PORT_FULL, /* 0x000f0005, Exceeds maximum number of supported mirroring port */ + + /* 0x0010xxxx for stat */ + RT_ERR_STAT_INVALID_GLOBAL_CNTR = 0x00100000, /* 0x00100000, Invalid Global Counter */ + RT_ERR_STAT_INVALID_PORT_CNTR, /* 0x00100001, Invalid Port Counter */ + RT_ERR_STAT_GLOBAL_CNTR_FAIL, /* 0x00100002, Could not retrieve/reset Global Counter */ + RT_ERR_STAT_PORT_CNTR_FAIL, /* 0x00100003, Could not retrieve/reset Port Counter */ + RT_ERR_STAT_INVALID_CNTR, /* 0x00100004, Invalid Counter */ + RT_ERR_STAT_CNTR_FAIL, /* 0x00100005, Could not retrieve/reset Counter */ + + /* 0x0011xxxx for dot1x */ + RT_ERR_DOT1X_INVALID_DIRECTION = 0x00110000, /* 0x00110000, Invalid Authentication Direction */ + RT_ERR_DOT1X_PORTBASEDPNEN, /* 0x00110001, Port-based enable port error */ + RT_ERR_DOT1X_PORTBASEDAUTH, /* 0x00110002, Port-based auth port error */ + RT_ERR_DOT1X_PORTBASEDOPDIR, /* 0x00110003, Port-based opdir error */ + RT_ERR_DOT1X_MACBASEDPNEN, /* 0x00110004, MAC-based enable port error */ + RT_ERR_DOT1X_MACBASEDOPDIR, /* 0x00110005, MAC-based opdir error */ + RT_ERR_DOT1X_PROC, /* 0x00110006, unauthorized behavior error */ + RT_ERR_DOT1X_GVLANIDX, /* 0x00110007, guest vlan index error */ + RT_ERR_DOT1X_GVLANTALK, /* 0x00110008, guest vlan OPDIR error */ + RT_ERR_DOT1X_MAC_PORT_MISMATCH, /* 0x00110009, Auth MAC and port mismatch error */ + + RT_ERR_END /* The symbol is the latest symbol */ +} rt_error_code_t; + + +#endif /* __COMMON_RT_ERROR_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h new file mode 100644 index 000000000000..6ddb23f2ede7 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_hal.h @@ -0,0 +1,44 @@ +#ifndef __RTK_HAL_H__ +#define __RTK_HAL_H__ +#include "ra_ioctl.h" + +#define RTK_SW_VID_RANGE 16 +void rtk_hal_switch_init(void); +void rtk_hal_dump_mib(void); +void rtk_hal_dump_full_mib(void); +int rtk_hal_dump_vlan(void); +void rtk_hal_clear_vlan(void); +int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data); +int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data); +int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data); +void rtk_hal_dump_table(void); +void rtk_hal_clear_table(void); +void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data); +void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data); +void rtk_hal_read_reg(struct ra_switch_ioctl_data *data); +void rtk_hal_write_reg(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_en(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data); +void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data); +void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data); +void rtk_hal_disable_igmpsnoop(void); +void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data); +void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data); +void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data); +void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data); +void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority); +void rtk_hal_add_table(struct ra_switch_ioctl_data *data); +void rtk_hal_del_table(struct ra_switch_ioctl_data *data); +void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data); +void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data); +#endif diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h new file mode 100644 index 000000000000..1c92188d6b19 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_switch.h @@ -0,0 +1,741 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76336 $ + * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $ + * + * Purpose : RTK switch high-level API + * Feature : Here is a list of all functions and variables in this module. + * + */ + +#ifndef __RTK_SWITCH_H__ +#define __RTK_SWITCH_H__ + +#include + +#define UNDEFINE_PHY_PORT (0xFF) +#define RTK_SWITCH_PORT_NUM (32) + +#define MAXPKTLEN_CFG_ID_MAX (1) + +#define RTK_SWITCH_MAX_PKTLEN (0x3FFF) + +typedef enum init_state_e +{ + INIT_NOT_COMPLETED = 0, + INIT_COMPLETED, + INIT_STATE_END +} init_state_t; + +typedef enum switch_chip_e +{ + CHIP_RTL8367C = 0, + CHIP_RTL8370B, + CHIP_RTL8364B, + CHIP_RTL8363SC_VB, + CHIP_END +}switch_chip_t; + +typedef enum port_type_e +{ + UTP_PORT = 0, + EXT_PORT, + UNKNOWN_PORT = 0xFF, + PORT_TYPE_END +}port_type_t; + +typedef struct rtk_switch_halCtrl_s +{ + switch_chip_t switch_type; + rtk_uint32 l2p_port[RTK_SWITCH_PORT_NUM]; + rtk_uint32 p2l_port[RTK_SWITCH_PORT_NUM]; + port_type_t log_port_type[RTK_SWITCH_PORT_NUM]; + rtk_uint32 ptp_port[RTK_SWITCH_PORT_NUM]; + rtk_uint32 valid_portmask; + rtk_uint32 valid_utp_portmask; + rtk_uint32 valid_ext_portmask; + rtk_uint32 valid_cpu_portmask; + rtk_uint32 min_phy_port; + rtk_uint32 max_phy_port; + rtk_uint32 phy_portmask; + rtk_uint32 combo_logical_port; + rtk_uint32 hsg_logical_port; + rtk_uint32 sg_logical_portmask; + rtk_uint32 max_meter_id; + rtk_uint32 max_lut_addr_num; + rtk_uint32 trunk_group_mask; + +}rtk_switch_halCtrl_t; + +typedef enum rtk_switch_maxPktLen_linkSpeed_e { + MAXPKTLEN_LINK_SPEED_FE = 0, + MAXPKTLEN_LINK_SPEED_GE, + MAXPKTLEN_LINK_SPEED_END, +} rtk_switch_maxPktLen_linkSpeed_t; + + +/* UTIL MACRO */ +#define RTK_CHK_INIT_STATE() \ + do \ + { \ + if(rtk_switch_initialState_get() != INIT_COMPLETED) \ + { \ + return RT_ERR_NOT_INIT; \ + } \ + }while(0) + +#define RTK_CHK_PORT_VALID(__port__) \ + do \ + { \ + if(rtk_switch_logicalPortCheck(__port__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_ID; \ + } \ + }while(0) + +#define RTK_CHK_PORT_IS_UTP(__port__) \ + do \ + { \ + if(rtk_switch_isUtpPort(__port__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_ID; \ + } \ + }while(0) + +#define RTK_CHK_PORT_IS_EXT(__port__) \ + do \ + { \ + if(rtk_switch_isExtPort(__port__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_ID; \ + } \ + }while(0) + +#define RTK_CHK_PORT_IS_COMBO(__port__) \ + do \ + { \ + if(rtk_switch_isComboPort(__port__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_ID; \ + } \ + }while(0) + +#define RTK_CHK_PORT_IS_PTP(__port__) \ + do \ + { \ + if(rtk_switch_isPtpPort(__port__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_ID; \ + } \ + }while(0) + +#define RTK_CHK_PORTMASK_VALID(__portmask__) \ + do \ + { \ + if(rtk_switch_isPortMaskValid(__portmask__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_MASK; \ + } \ + }while(0) + +#define RTK_CHK_PORTMASK_VALID_ONLY_UTP(__portmask__) \ + do \ + { \ + if(rtk_switch_isPortMaskUtp(__portmask__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_MASK; \ + } \ + }while(0) + +#define RTK_CHK_PORTMASK_VALID_ONLY_EXT(__portmask__) \ + do \ + { \ + if(rtk_switch_isPortMaskExt(__portmask__) != RT_ERR_OK) \ + { \ + return RT_ERR_PORT_MASK; \ + } \ + }while(0) + +#define RTK_CHK_TRUNK_GROUP_VALID(__grpId__) \ + do \ + { \ + if(rtk_switch_isValidTrunkGrpId(__grpId__) != RT_ERR_OK) \ + { \ + return RT_ERR_LA_TRUNK_ID; \ + } \ + }while(0) + +#define RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__) (((__portmask__).bits[0] & (0x00000001 << __port__)) ? 1 : 0) +#define RTK_PORTMASK_IS_EMPTY(__portmask__) (((__portmask__).bits[0] == 0) ? 1 : 0) +#define RTK_PORTMASK_CLEAR(__portmask__) ((__portmask__).bits[0] = 0) +#define RTK_PORTMASK_PORT_SET(__portmask__, __port__) ((__portmask__).bits[0] |= (0x00000001 << __port__)) +#define RTK_PORTMASK_PORT_CLEAR(__portmask__, __port__) ((__portmask__).bits[0] &= ~(0x00000001 << __port__)) +#define RTK_PORTMASK_ALLPORT_SET(__portmask__) (rtk_switch_logPortMask_get(&__portmask__)) +#define RTK_PORTMASK_SCAN(__portmask__, __port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if(RTK_PORTMASK_IS_PORT_SET(__portmask__, __port__)) +#define RTK_PORTMASK_COMPARE(__portmask_A__, __portmask_B__) ((__portmask_A__).bits[0] - (__portmask_B__).bits[0]) + +#define RTK_SCAN_ALL_PHY_PORTMASK(__port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if( (rtk_switch_phyPortMask_get() & (0x00000001 << __port__))) +#define RTK_SCAN_ALL_LOG_PORT(__port__) for(__port__ = 0; __port__ < RTK_SWITCH_PORT_NUM; __port__++) if( rtk_switch_logicalPortCheck(__port__) == RT_ERR_OK) +#define RTK_SCAN_ALL_LOG_PORTMASK(__portmask__) for((__portmask__).bits[0] = 0; (__portmask__).bits[0] < 0x7FFFF; (__portmask__).bits[0]++) if( rtk_switch_isPortMaskValid(&__portmask__) == RT_ERR_OK) + +/* Port mask definition */ +#define RTK_PHY_PORTMASK_ALL (rtk_switch_phyPortMask_get()) + +/* Port definition*/ +#define RTK_MAX_LOGICAL_PORT_ID (rtk_switch_maxLogicalPort_get()) + +/* Function Name: + * rtk_switch_probe + * Description: + * Probe switch + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Switch probed + * RT_ERR_FAILED - Switch Unprobed. + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip); + +/* Function Name: + * rtk_switch_initialState_set + * Description: + * Set initial status + * Input: + * state - Initial state; + * Output: + * None + * Return: + * RT_ERR_OK - Initialized + * RT_ERR_FAILED - Uninitialized + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_initialState_set(init_state_t state); + +/* Function Name: + * rtk_switch_initialState_get + * Description: + * Get initial status + * Input: + * None + * Output: + * None + * Return: + * INIT_COMPLETED - Initialized + * INIT_NOT_COMPLETED - Uninitialized + * Note: + * + */ +extern init_state_t rtk_switch_initialState_get(void); + +/* Function Name: + * rtk_switch_logicalPortCheck + * Description: + * Check logical port ID. + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is correct + * RT_ERR_FAILED - Port ID is not correct + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isUtpPort + * Description: + * Check is logical port a UTP port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a UTP port + * RT_ERR_FAILED - Port ID is not a UTP port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isExtPort + * Description: + * Check is logical port a Extension port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a EXT port + * RT_ERR_FAILED - Port ID is not a EXT port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isHsgPort + * Description: + * Check is logical port a HSG port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a HSG port + * RT_ERR_FAILED - Port ID is not a HSG port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isSgmiiPort + * Description: + * Check is logical port a SGMII port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a SGMII port + * RT_ERR_FAILED - Port ID is not a SGMII port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isCPUPort + * Description: + * Check is logical port a CPU port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a CPU port + * RT_ERR_FAILED - Port ID is not a CPU port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_isComboPort + * Description: + * Check is logical port a Combo port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a combo port + * RT_ERR_FAILED - Port ID is not a combo port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_ComboPort_get + * Description: + * Get Combo port ID + * Input: + * None + * Output: + * None + * Return: + * Port ID of combo port + * Note: + * + */ +extern rtk_uint32 rtk_switch_ComboPort_get(void); + +/* Function Name: + * rtk_switch_isPtpPort + * Description: + * Check is logical port a PTP port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a PTP port + * RT_ERR_FAILED - Port ID is not a PTP port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_port_L2P_get + * Description: + * Get physical port ID + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * Physical port ID + * Note: + * + */ +extern rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort); + +/* Function Name: + * rtk_switch_port_P2L_get + * Description: + * Get logical port ID + * Input: + * physicalPort - physical port ID + * Output: + * None + * Return: + * logical port ID + * Note: + * + */ +extern rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort); + +/* Function Name: + * rtk_switch_isPortMaskValid + * Description: + * Check portmask is valid or not + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - port mask is valid + * RT_ERR_FAILED - port mask is not valid + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask); + +/* Function Name: + * rtk_switch_isPortMaskUtp + * Description: + * Check all ports in portmask are only UTP port + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - Only UTP port in port mask + * RT_ERR_FAILED - Not only UTP port in port mask + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask); + +/* Function Name: + * rtk_switch_isPortMaskExt + * Description: + * Check all ports in portmask are only EXT port + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - Only EXT port in port mask + * RT_ERR_FAILED - Not only EXT port in port mask + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask); + +/* Function Name: + * rtk_switch_portmask_L2P_get + * Description: + * Get physical portmask from logical portmask + * Input: + * pLogicalPmask - logical port mask + * Output: + * pPhysicalPortmask - physical port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_PORT_MASK - Error port mask + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask); + +/* Function Name: + * rtk_switch_portmask_P2L_get + * Description: + * Get logical portmask from physical portmask + * Input: + * physicalPortmask - physical port mask + * Output: + * pLogicalPmask - logical port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_PORT_MASK - Error port mask + * Note: + * + */ +extern rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask); + +/* Function Name: + * rtk_switch_phyPortMask_get + * Description: + * Get physical portmask + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Physical port mask + * Note: + * + */ +rtk_uint32 rtk_switch_phyPortMask_get(void); + +/* Function Name: + * rtk_switch_logPortMask_get + * Description: + * Get Logical portmask + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask); + +/* Function Name: + * rtk_switch_init + * Description: + * Set chip to default configuration environment + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can set chip registers to default configuration for different release chip model. + */ +extern rtk_api_ret_t rtk_switch_init(void); + +/* Function Name: + * rtk_switch_portMaxPktLen_set + * Description: + * Set Max packet length + * Input: + * port - Port ID + * speed - Speed + * cfgId - Configuration ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +extern rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId); + +/* Function Name: + * rtk_switch_portMaxPktLen_get + * Description: + * Get Max packet length + * Input: + * port - Port ID + * speed - Speed + * Output: + * pCfgId - Configuration ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +extern rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId); + +/* Function Name: + * rtk_switch_maxPktLenCfg_set + * Description: + * Set Max packet length configuration + * Input: + * cfgId - Configuration ID + * pktLen - Max packet length + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +extern rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen); + +/* Function Name: + * rtk_switch_maxPktLenCfg_get + * Description: + * Get Max packet length configuration + * Input: + * cfgId - Configuration ID + * pPktLen - Max packet length + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +extern rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen); + +/* Function Name: + * rtk_switch_greenEthernet_set + * Description: + * Set all Ports Green Ethernet state. + * Input: + * enable - Green Ethernet state. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set all Ports Green Ethernet state. + * The configuration is as following: + * - DISABLE + * - ENABLE + */ +extern rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable); + +/* Function Name: + * rtk_switch_greenEthernet_get + * Description: + * Get all Ports Green Ethernet state. + * Input: + * None + * Output: + * pEnable - Green Ethernet state. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API can get Green Ethernet state. + */ +extern rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable); + +/* Function Name: + * rtk_switch_maxLogicalPort_get + * Description: + * Get Max logical port ID + * Input: + * None + * Output: + * None + * Return: + * Max logical port + * Note: + * This API can get max logical port + */ +extern rtk_port_t rtk_switch_maxLogicalPort_get(void); + +/* Function Name: + * rtk_switch_maxMeterId_get + * Description: + * Get Max Meter ID + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Max Meter ID + * Note: + * + */ +extern rtk_uint32 rtk_switch_maxMeterId_get(void); + +/* Function Name: + * rtk_switch_maxLutAddrNumber_get + * Description: + * Get Max LUT Address number + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Max LUT Address number + * Note: + * + */ +extern rtk_uint32 rtk_switch_maxLutAddrNumber_get(void); + +/* Function Name: + * rtk_switch_isValidTrunkGrpId + * Description: + * Check if trunk group is valid or not + * Input: + * grpId - Group ID + * Output: + * None + * Return: + * RT_ERR_OK - Trunk Group ID is valid + * RT_ERR_LA_TRUNK_ID - Trunk Group ID is not valid + * Note: + * + */ +rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId); + +int gsw_debug_proc_init(void); +void gsw_debug_proc_exit(void); +int rtl8367s_swconfig_init(void (*reset_func)(void)); + +#endif diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h b/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h new file mode 100644 index 000000000000..cafc7ff9da36 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtk_types.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level type enum definition. + * Feature : + * + */ + +#ifndef _RTL8367C_TYPES_H_ +#define _RTL8367C_TYPES_H_ + +//#include + +typedef unsigned long long rtk_uint64; +typedef long long rtk_int64; +typedef unsigned int rtk_uint32; +typedef int rtk_int32; +typedef unsigned short rtk_uint16; +typedef short rtk_int16; +typedef unsigned char rtk_uint8; +typedef char rtk_int8; + +#define CONST_T const + +#define RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST 1 + +#define RTK_MAX_NUM_OF_PORT 8 +#define RTK_PORT_ID_MAX (RTK_MAX_NUM_OF_PORT-1) +#define RTK_PHY_ID_MAX (RTK_MAX_NUM_OF_PORT-4) +#define RTK_MAX_PORT_MASK 0xFF + +#define RTK_WHOLE_SYSTEM 0xFF + +typedef struct rtk_portmask_s +{ + rtk_uint32 bits[RTK_TOTAL_NUM_OF_WORD_FOR_1BIT_PORT_LIST]; +} rtk_portmask_t; + +typedef enum rtk_enable_e +{ + DISABLED = 0, + ENABLED, + RTK_ENABLE_END +} rtk_enable_t; + +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 6 +#endif + +/* Ethernet address type */ +typedef struct rtk_mac_s +{ + rtk_uint8 octet[ETHER_ADDR_LEN]; +} rtk_mac_t; + +typedef rtk_uint32 rtk_pri_t; /* priority value */ +typedef rtk_uint32 rtk_qid_t; /* queue id type */ +typedef rtk_uint32 rtk_data_t; +typedef rtk_uint32 rtk_dscp_t; /* dscp vlaue */ +typedef rtk_uint32 rtk_fid_t; /* filter id type */ +typedef rtk_uint32 rtk_vlan_t; /* vlan id type */ +typedef rtk_uint32 rtk_mac_cnt_t; /* MAC count type */ +typedef rtk_uint32 rtk_meter_id_t; /* meter id type */ +typedef rtk_uint32 rtk_rate_t; /* rate type */ + +typedef enum rtk_port_e +{ + UTP_PORT0 = 0, + UTP_PORT1, + UTP_PORT2, + UTP_PORT3, + UTP_PORT4, + UTP_PORT5, + UTP_PORT6, + UTP_PORT7, + + EXT_PORT0 = 16, + EXT_PORT1, + EXT_PORT2, + + UNDEFINE_PORT = 30, + RTK_PORT_MAX = 31 +} rtk_port_t; + + +#ifndef _RTL_TYPES_H + +#if 0 +typedef unsigned long long uint64; +typedef long long int64; +typedef unsigned int uint32; +typedef int int32; +typedef unsigned short uint16; +typedef short int16; +typedef unsigned char uint8; +typedef char int8; +#endif + +typedef rtk_uint32 ipaddr_t; +typedef rtk_uint32 memaddr; + +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 6 +#endif + +typedef struct ether_addr_s { + rtk_uint8 octet[ETHER_ADDR_LEN]; +} ether_addr_t; + +#ifdef __KERNEL__ +#define rtlglue_printf printk +#else +#define rtlglue_printf printf +#endif +#define PRINT rtlglue_printf +#endif /*_RTL_TYPES_H*/ + +/* type abstraction */ +#ifdef EMBEDDED_SUPPORT + +typedef rtk_int16 rtk_api_ret_t; +typedef rtk_int16 ret_t; +typedef rtk_uint32 rtk_u_long; + +#else + +typedef rtk_int32 rtk_api_ret_t; +typedef rtk_int32 ret_t; +typedef rtk_uint64 rtk_u_long_t; + +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define CONST const +#endif /* _RTL8367C_TYPES_H_ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h new file mode 100644 index 000000000000..55cb41b06728 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : + * + */ + + +#ifndef _RTL8367C_ASICDRV_H_ +#define _RTL8367C_ASICDRV_H_ + +#include +#include +#include +#include + +#define RTL8367C_REGBITLENGTH 16 +#define RTL8367C_REGDATAMAX 0xFFFF + +#define RTL8367C_VIDMAX 0xFFF +#define RTL8367C_EVIDMAX 0x1FFF +#define RTL8367C_CVIDXNO 32 +#define RTL8367C_CVIDXMAX (RTL8367C_CVIDXNO-1) + +#define RTL8367C_PRIMAX 7 +#define RTL8367C_DSCPMAX 63 + +#define RTL8367C_PORTNO 11 +#define RTL8367C_PORTIDMAX (RTL8367C_PORTNO-1) +#define RTL8367C_PMSKMAX ((1<<(RTL8367C_PORTNO))-1) +#define RTL8367C_PORTMASK 0x7FF + +#define RTL8367C_PHYNO 5 +#define RTL8367C_PHYIDMAX (RTL8367C_PHYNO-1) + +#define RTL8367C_SVIDXNO 64 +#define RTL8367C_SVIDXMAX (RTL8367C_SVIDXNO-1) +#define RTL8367C_MSTIMAX 15 + +#define RTL8367C_METERNO 64 +#define RTL8367C_METERMAX (RTL8367C_METERNO-1) +#define RTL8367C_METERBUCKETSIZEMAX 0xFFFF + +#define RTL8367C_QUEUENO 8 +#define RTL8367C_QIDMAX (RTL8367C_QUEUENO-1) + +#define RTL8367C_PHY_BUSY_CHECK_COUNTER 1000 + +#define RTL8367C_QOS_GRANULARTY_MAX 0x7FFFF +#define RTL8367C_QOS_GRANULARTY_LSB_MASK 0xFFFF +#define RTL8367C_QOS_GRANULARTY_LSB_OFFSET 0 +#define RTL8367C_QOS_GRANULARTY_MSB_MASK 0x70000 +#define RTL8367C_QOS_GRANULARTY_MSB_OFFSET 16 + +#define RTL8367C_QOS_GRANULARTY_UNIT_KBPS 8 + +#define RTL8367C_QOS_RATE_INPUT_MAX (0x1FFFF * 8) +#define RTL8367C_QOS_RATE_INPUT_MAX_HSG (0x7FFFF * 8) +#define RTL8367C_QOS_RATE_INPUT_MIN 8 +#define RTL8367C_QOS_PPS_INPUT_MAX (0x7FFFF) +#define RTL8367C_QOS_PPS_INPUT_MIN 1 + +#define RTL8367C_QUEUE_MASK 0xFF + +#define RTL8367C_EFIDMAX 0x7 +#define RTL8367C_FIDMAX 0xF + +#define RTL8367C_EAV_SECONDMAX 0xFFFFFFFF +#define RTL8367C_EAV_NANOSECONDMAX 0x3B9AC9FF + + +/* the above macro is generated by genDotH */ +#define RTL8367C_VALID_REG_NO 3869 + +/*======================================================================= + * Enum + *========================================================================*/ +enum RTL8367C_TABLE_ACCESS_OP +{ + TB_OP_READ = 0, + TB_OP_WRITE +}; + +enum RTL8367C_TABLE_ACCESS_TARGET +{ + TB_TARGET_ACLRULE = 1, + TB_TARGET_ACLACT, + TB_TARGET_CVLAN, + TB_TARGET_L2, + TB_TARGET_IGMP_GROUP +}; + +#define RTL8367C_TABLE_ACCESS_REG_DATA(op, target) ((op << 3) | target) + +/*======================================================================= + * Structures + *========================================================================*/ + + +#ifdef __cplusplus +extern "C" { +#endif +extern ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value); +extern ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue); + +extern ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value); +extern ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue); + +extern ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value); +extern ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue); + +#ifdef __cplusplus +} +#endif + + + +#endif /*#ifndef _RTL8367C_ASICDRV_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h new file mode 100644 index 000000000000..8ae69ac332c2 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_acl.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : ACL related function drivers + * + */ + +#ifndef _RTL8367C_ASICDRV_ACL_H_ +#define _RTL8367C_ASICDRV_ACL_H_ + +#include + +#define RTL8367C_ACLRULENO 96 + +#define RTL8367C_ACLRULEMAX (RTL8367C_ACLRULENO-1) +#define RTL8367C_ACLRULEFIELDNO 8 +#define RTL8367C_ACLTEMPLATENO 5 +#define RTL8367C_ACLTYPEMAX (RTL8367C_ACLTEMPLATENO-1) + +#define RTL8367C_ACLRULETBLEN 9 +#define RTL8367C_ACLACTTBLEN 4 +#define RTL8367C_ACLRULETBADDR(type, rule) ((type << 6) | rule) +#define RTL8367C_ACLRULETBADDR2(type, rule) ((type << 5) | (rule + 64)) + +#define ACL_ACT_CVLAN_ENABLE_MASK 0x1 +#define ACL_ACT_SVLAN_ENABLE_MASK 0x2 +#define ACL_ACT_PRIORITY_ENABLE_MASK 0x4 +#define ACL_ACT_POLICING_ENABLE_MASK 0x8 +#define ACL_ACT_FWD_ENABLE_MASK 0x10 +#define ACL_ACT_INTGPIO_ENABLE_MASK 0x20 + +#define RTL8367C_ACLRULETAGBITS 5 + +#define RTL8367C_ACLRANGENO 16 + +#define RTL8367C_ACLRANGEMAX (RTL8367C_ACLRANGENO-1) + +#define RTL8367C_ACL_PORTRANGEMAX (0xFFFF) +#define RTL8367C_ACL_ACT_TABLE_LEN (4) + +enum ACLTCAMTYPES +{ + CAREBITS= 0, + DATABITS +}; + +typedef enum aclFwdAct +{ + RTL8367C_ACL_FWD_MIRROR = 0, + RTL8367C_ACL_FWD_REDIRECT, + RTL8367C_ACL_FWD_MIRRORFUNTION, + RTL8367C_ACL_FWD_TRAP, +} rtl8367c_aclFwd_t; + +enum ACLFIELDTYPES +{ + ACL_UNUSED, + ACL_DMAC0, + ACL_DMAC1, + ACL_DMAC2, + ACL_SMAC0, + ACL_SMAC1, + ACL_SMAC2, + ACL_ETHERTYPE, + ACL_STAG, + ACL_CTAG, + ACL_IP4SIP0 = 0x10, + ACL_IP4SIP1, + ACL_IP4DIP0, + ACL_IP4DIP1, + ACL_IP6SIP0WITHIPV4 = 0x20, + ACL_IP6SIP1WITHIPV4, + ACL_IP6DIP0WITHIPV4 = 0x28, + ACL_IP6DIP1WITHIPV4, + ACL_VIDRANGE = 0x30, + ACL_IPRANGE, + ACL_PORTRANGE, + ACL_FIELD_VALID, + ACL_FIELD_SELECT00 = 0x40, + ACL_FIELD_SELECT01, + ACL_FIELD_SELECT02, + ACL_FIELD_SELECT03, + ACL_FIELD_SELECT04, + ACL_FIELD_SELECT05, + ACL_FIELD_SELECT06, + ACL_FIELD_SELECT07, + ACL_FIELD_SELECT08, + ACL_FIELD_SELECT09, + ACL_FIELD_SELECT10, + ACL_FIELD_SELECT11, + ACL_FIELD_SELECT12, + ACL_FIELD_SELECT13, + ACL_FIELD_SELECT14, + ACL_FIELD_SELECT15, + ACL_TCPSPORT = 0x80, + ACL_TCPDPORT, + ACL_TCPFLAG, + ACL_UDPSPORT, + ACL_UDPDPORT, + ACL_ICMPCODETYPE, + ACL_IGMPTYPE, + ACL_SPORT, + ACL_DPORT, + ACL_IP4TOSPROTO, + ACL_IP4FLAGOFF, + ACL_TCNH, + ACL_CPUTAG, + ACL_L2PAYLOAD, + ACL_IP6SIP0, + ACL_IP6SIP1, + ACL_IP6SIP2, + ACL_IP6SIP3, + ACL_IP6SIP4, + ACL_IP6SIP5, + ACL_IP6SIP6, + ACL_IP6SIP7, + ACL_IP6DIP0, + ACL_IP6DIP1, + ACL_IP6DIP2, + ACL_IP6DIP3, + ACL_IP6DIP4, + ACL_IP6DIP5, + ACL_IP6DIP6, + ACL_IP6DIP7, + ACL_TYPE_END +}; + +struct acl_rule_smi_st{ + rtk_uint16 rule_info; + rtk_uint16 field[RTL8367C_ACLRULEFIELDNO]; +}; + +struct acl_rule_smi_ext_st{ + rtk_uint16 rule_info; +}; + +typedef struct ACLRULESMI{ + struct acl_rule_smi_st care_bits; + rtk_uint16 valid:1; + struct acl_rule_smi_st data_bits; + + struct acl_rule_smi_ext_st care_bits_ext; + struct acl_rule_smi_ext_st data_bits_ext; +}rtl8367c_aclrulesmi; + +struct acl_rule_st{ + rtk_uint16 active_portmsk:11; + rtk_uint16 type:3; + rtk_uint16 tag_exist:5; + rtk_uint16 field[RTL8367C_ACLRULEFIELDNO]; +}; + +typedef struct ACLRULE{ + struct acl_rule_st data_bits; + rtk_uint16 valid:1; + struct acl_rule_st care_bits; +}rtl8367c_aclrule; + + +typedef struct rtl8367c_acltemplate_s{ + rtk_uint8 field[8]; +}rtl8367c_acltemplate_t; + + +typedef struct acl_act_s{ + rtk_uint16 cvidx_cact:7; + rtk_uint16 cact:2; + rtk_uint16 svidx_sact:7; + rtk_uint16 sact:2; + + + rtk_uint16 aclmeteridx:7; + rtk_uint16 fwdpmask:11; + rtk_uint16 fwdact:2; + + rtk_uint16 pridx:7; + rtk_uint16 priact:2; + rtk_uint16 gpio_pin:4; + rtk_uint16 gpio_en:1; + rtk_uint16 aclint:1; + + rtk_uint16 cact_ext:2; + rtk_uint16 fwdact_ext:1; + rtk_uint16 tag_fmt:2; +}rtl8367c_acl_act_t; + +typedef struct acl_rule_union_s +{ + rtl8367c_aclrule aclRule; + rtl8367c_acl_act_t aclAct; + rtk_uint32 aclActCtrl; + rtk_uint32 aclNot; +}rtl8367c_acl_rule_union_t; + + +extern ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule); +extern ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule); +extern ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not); +extern ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot); +extern ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType); +extern ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType); +extern ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct); +extern ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct); +extern ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl); +extern ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *aclActCtrl); +extern ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort); +extern ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort); +extern ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid); +extern ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid); +extern ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp); +extern ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp); +extern ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity); +extern ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity); + +#endif /*_RTL8367C_ASICDRV_ACL_H_*/ + + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h new file mode 100644 index 000000000000..982e2c4bfcdb --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_cputag.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Proprietary CPU-tag related function drivers + * + */ + +#ifndef _RTL8367C_ASICDRV_CPUTAG_H_ +#define _RTL8367C_ASICDRV_CPUTAG_H_ + +#include + +enum CPUTAG_INSERT_MODE +{ + CPUTAG_INSERT_TO_ALL = 0, + CPUTAG_INSERT_TO_TRAPPING, + CPUTAG_INSERT_TO_NO, + CPUTAG_INSERT_END +}; + +extern ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port); +extern ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort); +extern ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPmsk); +extern ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode); +extern ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri); +extern ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri); +extern ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 position); +extern ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion); +extern ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode); +extern ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode); + +#endif /*#ifndef _RTL8367C_ASICDRV_CPUTAG_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h new file mode 100644 index 000000000000..7639ae782b5c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_dot1x.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : 802.1X related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_DOT1X_H_ +#define _RTL8367C_ASICDRV_DOT1X_H_ + +#include + +enum DOT1X_UNAUTH_BEHAV +{ + DOT1X_UNAUTH_DROP = 0, + DOT1X_UNAUTH_TRAP, + DOT1X_UNAUTH_GVLAN, + DOT1X_UNAUTH_END +}; + +extern ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth); +extern ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth); +extern ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir); +extern ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 *pOpdir); +extern ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir); +extern ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir); +extern ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc); +extern ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32 *pProc); +extern ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index); +extern ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex); +extern ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority); +extern ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority); + + +#endif /*_RTL8367C_ASICDRV_DOT1X_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h new file mode 100644 index 000000000000..b633f66fb0c0 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eav.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Ethernet AV related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_EAV_H_ +#define _RTL8367C_ASICDRV_EAV_H_ + +#include + +typedef enum RTL8367C_PTP_TIME_CMD_E +{ + PTP_TIME_READ = 0, + PTP_TIME_WRITE, + PTP_TIME_INC, + PTP_TIME_DEC, + PTP_TIME_CMD_END +}RTL8367C_PTP_TIME_CMD; + +typedef enum RTL8367C_PTP_TIME_ADJ_E +{ + PTP_TIME_ADJ_INC = 0, + PTP_TIME_ADJ_DEC, + PTP_TIME_ADJ_END +}RTL8367C_PTP_TIME_ADJ; + +typedef enum RTL8367C_PTP_TIME_CTRL_E +{ + PTP_TIME_CTRL_STOP = 0, + PTP_TIME_CTRL_START, + PTP_TIME_CTRL_END +}RTL8367C_PTP_TIME_CTRL; + +typedef enum RTL8367C_PTP_INTR_IMRS_E +{ + PTP_IMRS_TX_SYNC, + PTP_IMRS_TX_DELAY_REQ, + PTP_IMRS_TX_PDELAY_REQ, + PTP_IMRS_TX_PDELAY_RESP, + PTP_IMRS_RX_SYNC, + PTP_IMRS_RX_DELAY_REQ, + PTP_IMRS_RX_PDELAY_REQ, + PTP_IMRS_RX_PDELAY_RESP, + PTP_IMRS_END, +}RTL8367C_PTP_INTR_IMRS; + + +typedef enum RTL8367C_PTP_PKT_TYPE_E +{ + PTP_PKT_TYPE_TX_SYNC, + PTP_PKT_TYPE_TX_DELAY_REQ, + PTP_PKT_TYPE_TX_PDELAY_REQ, + PTP_PKT_TYPE_TX_PDELAY_RESP, + PTP_PKT_TYPE_RX_SYNC, + PTP_PKT_TYPE_RX_DELAY_REQ, + PTP_PKT_TYPE_RX_PDELAY_REQ, + PTP_PKT_TYPE_RX_PDELAY_RESP, + PTP_PKT_TYPE_END, +}RTL8367C_PTP_PKT_TYPE; + +typedef struct rtl8367c_ptp_time_stamp_s{ + rtk_uint32 sequence_id; + rtk_uint32 second; + rtk_uint32 nano_second; +}rtl8367c_ptp_time_stamp_t; + +#define RTL8367C_PTP_INTR_MASK 0xFF + +#define RTL8367C_PTP_PORT_MASK 0x3FF + +extern ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac); +extern ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac); +extern ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag); +extern ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag); +extern ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond); +extern ret_t rtl8367c_getAsicEavSysTime(rtk_uint32* pSecond, rtk_uint32* pNanoSecond); +extern ret_t rtl8367c_setAsicEavSysTimeAdjust(rtk_uint32 type, rtk_uint32 second, rtk_uint32 nanoSecond); +extern ret_t rtl8367c_setAsicEavSysTimeCtrl(rtk_uint32 control); +extern ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl); +extern ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr); +extern ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr); +extern ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms); +extern ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims); +extern ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms); +extern ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp); + +extern ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority); +extern ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority); + +#endif /*#ifndef _RTL8367C_ASICDRV_EAV_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h new file mode 100644 index 000000000000..6bedce62b0ad --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_eee.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 48989 $ + * $Date: 2014-07-01 15:45:24 +0800 (gG, 01 C 2014) $ + * + * Purpose : RTL8370 switch high-level API for RTL8367C + * Feature : + * + */ + +#ifndef _RTL8367C_ASICDRV_EEE_H_ +#define _RTL8367C_ASICDRV_EEE_H_ + +#include + +#define EEE_OCP_PHY_ADDR (0xA5D0) + +extern ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable); +extern ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable); + + +#endif /*_RTL8367C_ASICDRV_EEE_H_*/ diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h new file mode 100644 index 000000000000..ce67cdebacad --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_fc.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Flow control related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_FC_H_ +#define _RTL8367C_ASICDRV_FC_H_ + +#include + +#define RTL8367C_PAGE_NUMBER 0x600 + + +enum FLOW_CONTROL_TYPE +{ + FC_EGRESS = 0, + FC_INGRESS, +}; + +enum FC_JUMBO_SIZE +{ + FC_JUMBO_SIZE_3K = 0, + FC_JUMBO_SIZE_4K, + FC_JUMBO_SIZE_6K, + FC_JUMBO_SIZE_9K, + FC_JUMBO_SIZE_END, + +}; + + +extern ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select); +extern ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect); +extern ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size); +extern ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize); +extern ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall); +extern ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall); +extern ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold); +extern ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold); +extern ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); +extern ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold); +extern ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold); + +extern ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap); +extern ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap); +extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap); +extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap); +extern ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold); +extern ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold); +extern ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold); +extern ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold); +extern ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount); +extern ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount); +extern ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount); +extern ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount); +extern ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount); +extern ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount); +extern ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable); + +#endif /*_RTL8367C_ASICDRV_FC_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h new file mode 100644 index 000000000000..95c1b20bd49f --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_green.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Green Ethernet related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_GREEN_H_ +#define _RTL8367C_ASICDRV_GREEN_H_ + +#include +#include + +#define PHY_POWERSAVING_REG 24 + +extern ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype); +extern ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype); +extern ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage); +extern ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator); +extern ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port); +extern ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green); +extern ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green); +extern ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable); +#endif /*#ifndef _RTL8367C_ASICDRV_GREEN_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h new file mode 100644 index 000000000000..f4f9bb377b9f --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_hsb.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Field selector related functions + * + */ + +#ifndef _RTL8367C_ASICDRV__HSB_H_ +#define _RTL8367C_ASICDRV__HSB_H_ + +#include + +#define RTL8367C_FIELDSEL_FORMAT_NUMBER (16) +#define RTL8367C_FIELDSEL_MAX_OFFSET (255) + +enum FIELDSEL_FORMAT_FORMAT +{ + FIELDSEL_FORMAT_DEFAULT = 0, + FIELDSEL_FORMAT_RAW, + FIELDSEL_FORMAT_LLC, + FIELDSEL_FORMAT_IPV4, + FIELDSEL_FORMAT_ARP, + FIELDSEL_FORMAT_IPV6, + FIELDSEL_FORMAT_IPPAYLOAD, + FIELDSEL_FORMAT_L4PAYLOAD, + FIELDSEL_FORMAT_END +}; + +extern ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset); +extern ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset); + +#endif /*_RTL8367C_ASICDRV__HSB_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h new file mode 100644 index 000000000000..d5b095a0e5c6 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_i2c.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 38651 $ + * $Date: 2016-02-27 14:32:56 +0800 (PT, 17 | 2016) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : I2C related functions + * + */ + + +#ifndef _RTL8367C_ASICDRV_I2C_H_ +#define _RTL8367C_ASICDRV_I2C_H_ +#include +#include + + +#define TIMEROUT_FOR_MICROSEMI (0x400) + +#define GPIO_INPUT 1 +#define GPIO_OUTPUT 2 + +extern ret_t rtl8367c_setAsicI2C_checkBusIdle(void); +extern ret_t rtl8367c_setAsicI2CStartCmd(void); +extern ret_t rtl8367c_setAsicI2CStopCmd(void); +extern ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar); +extern ret_t rtl8367c_setAsicI2CcheckRxAck(void); +extern ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue); +extern ret_t rtl8367c_setAsicI2CTxAckCmd(void); +extern ret_t rtl8367c_setAsicI2CTxNoAckCmd(void); +extern ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void); +extern ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID); +extern ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID); + + + + + +#endif /*#ifndef _RTL8367C_ASICDRV_I2C_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h new file mode 100644 index 000000000000..b879b6b520e4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_igmp.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : IGMP related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_IGMP_H_ +#define _RTL8367C_ASICDRV_IGMP_H_ + +/****************************************************************/ +/* Header File inclusion */ +/****************************************************************/ +#include + +#define RTL8367C_MAX_LEAVE_TIMER (7) +#define RTL8367C_MAX_QUERY_INT (0xFFFF) +#define RTL8367C_MAX_ROB_VAR (7) + +#define RTL8367C_IGMP_GOUP_NO (256) +#define RTL8367C_IGMP_MAX_GOUP (0xFF) +#define RTL8367C_IGMP_GRP_BLEN (3) +#define RTL8367C_ROUTER_PORT_INVALID (0xF) + +enum RTL8367C_IGMPTABLE_FULL_OP +{ + TABLE_FULL_FORWARD = 0, + TABLE_FULL_DROP, + TABLE_FULL_TRAP, + TABLE_FULL_OP_END +}; + +enum RTL8367C_CRC_ERR_OP +{ + CRC_ERR_DROP = 0, + CRC_ERR_TRAP, + CRC_ERR_FORWARD, + CRC_ERR_OP_END +}; + +enum RTL8367C_IGMP_MLD_PROTOCOL_OP +{ + PROTOCOL_OP_ASIC = 0, + PROTOCOL_OP_FLOOD, + PROTOCOL_OP_TRAP, + PROTOCOL_OP_DROP, + PROTOCOL_OP_END +}; + +enum RTL8367C_IGMP_MLD_BYPASS_GROUP +{ + BYPASS_224_0_0_X = 0, + BYPASS_224_0_1_X, + BYPASS_239_255_255_X, + BYPASS_IPV6_00XX, + BYPASS_GROUP_END +}; + +typedef struct +{ + rtk_uint32 p0_timer; + rtk_uint32 p1_timer; + rtk_uint32 p2_timer; + rtk_uint32 p3_timer; + rtk_uint32 p4_timer; + rtk_uint32 p5_timer; + rtk_uint32 p6_timer; + rtk_uint32 p7_timer; + rtk_uint32 p8_timer; + rtk_uint32 p9_timer; + rtk_uint32 p10_timer; + rtk_uint32 report_supp_flag; + +}rtl8367c_igmpgroup; +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * This program is the proprietary software of Realtek Semiconductor + * Corporation and/or its licensors, and only be used, duplicated, + * modified or distributed under the authorized license from Realtek. + * + * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER + * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : IGMP related functions + * + */ +#include + +ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled); +ret_t rtl8367c_getAsicIgmp(rtk_uint32 *pEnabled); +ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled ); +ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *pEnabled ); +ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation); +ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *pOperation); +ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation); +ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *pOperation); +ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled); +ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *pEnabled); +ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer); +ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pLeave_timer); +ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval); +ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pInterval); +ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var); +ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *pRob_var); +ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk); +ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pMsk); +ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk); +ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk); +ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *pPort, rtk_uint32 *pTimer); +ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *pPort, rtk_uint32 *pTimer); +ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled); +ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *pReport_supp_enabled, rtk_uint32 *pLeave_supp_enabled); +ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query); +ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *pAllow_query); +ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report); +ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *pAllow_report); +ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave); +ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *pAllow_leave); +ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp); +ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *pAllow_mrp); +ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata); +ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *pAllow_mcdata); +ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op); +ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv1_op); +ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op); +ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv2_op); +ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op); +ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *pIgmpv3_op); +ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op); +ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *pMldv1_op); +ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op); +ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *pMldv2_op); +ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group); +ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *pMax_group); +ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *pCurrent_group); +ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *pValid, rtl8367c_igmpgroup *pGrp); +ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled); +ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *pEnabled); +ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood); +ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood); +ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop); +ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop); +ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass); +ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass); +ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky); +ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky); +ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky); +ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky); +ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled); +ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled); + +#endif /*#ifndef _RTL8367C_ASICDRV_IGMP_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h new file mode 100644 index 000000000000..10f3545322c9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_inbwctrl.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Ingress bandwidth control related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_INBWCTRL_H_ +#define _RTL8367C_ASICDRV_INBWCTRL_H_ + +#include + +extern ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC); +extern ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC ); +extern ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled); + + +#endif /*_RTL8367C_ASICDRV_INBWCTRL_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h new file mode 100644 index 000000000000..8b78014ab01b --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_interrupt.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Interrupt related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_ +#define _RTL8367C_ASICDRV_INTERRUPT_H_ + +#include + +typedef enum RTL8367C_INTR_IMRS_E +{ + IMRS_LINK_CHANGE, + IMRS_METER_EXCEED, + IMRS_L2_LEARN, + IMRS_SPEED_CHANGE, + IMRS_SPECIAL_CONGESTION, + IMRS_GREEN_FEATURE, + IMRS_LOOP_DETECTION, + IMRS_8051, + IMRS_CABLE_DIAG, + IMRS_ACL, + IMRS_RESERVED, /* Unused */ + IMRS_SLIENT, + IMRS_END, +}RTL8367C_INTR_IMRS; + +typedef enum RTL8367C_INTR_INDICATOR_E +{ + INTRST_L2_LEARN = 0, + INTRST_SPEED_CHANGE, + INTRST_SPECIAL_CONGESTION, + INTRST_PORT_LINKDOWN, + INTRST_PORT_LINKUP, + INTRST_METER0_15, + INTRST_METER16_31, + INTRST_RLDP_LOOPED, + INTRST_RLDP_RELEASED, + INTRST_SYS_LEARN, + INTRST_END, +}RTL8367C_INTR_INDICATOR; + +extern ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity); +extern ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity); +extern ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr); +extern ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr); +extern ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims); +extern ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms); +extern ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status); +extern ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus); + + +#endif /*#ifndef _RTL8367C_ASICDRV_INTERRUPT_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h new file mode 100644 index 000000000000..a7f8e2064320 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_led.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : LED related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_LED_H_ +#define _RTL8367C_ASICDRV_LED_H_ + +#include + +#define RTL8367C_LEDGROUPNO 3 +#define RTL8367C_LEDGROUPMASK 0x7 +#define RTL8367C_LED_FORCE_MODE_BASE RTL8367C_REG_CPU_FORCE_LED0_CFG0 +#define RTL8367C_LED_FORCE_CTRL RTL8367C_REG_CPU_FORCE_LED_CFG + +enum RTL8367C_LEDOP{ + + LEDOP_SCAN0=0, + LEDOP_SCAN1, + LEDOP_PARALLEL, + LEDOP_SERIAL, + LEDOP_END, +}; + +enum RTL8367C_LEDSERACT{ + + LEDSERACT_HIGH=0, + LEDSERACT_LOW, + LEDSERACT_MAX, +}; + +enum RTL8367C_LEDSER{ + + LEDSER_16G=0, + LEDSER_8G, + LEDSER_MAX, +}; + +enum RTL8367C_LEDCONF{ + + LEDCONF_LEDOFF=0, + LEDCONF_DUPCOL, + LEDCONF_LINK_ACT, + LEDCONF_SPD1000, + LEDCONF_SPD100, + LEDCONF_SPD10, + LEDCONF_SPD1000ACT, + LEDCONF_SPD100ACT, + LEDCONF_SPD10ACT, + LEDCONF_SPD10010ACT, + LEDCONF_LOOPDETECT, + LEDCONF_EEE, + LEDCONF_LINKRX, + LEDCONF_LINKTX, + LEDCONF_MASTER, + LEDCONF_ACT, + LEDCONF_END +}; + +enum RTL8367C_LEDBLINKRATE{ + + LEDBLINKRATE_32MS=0, + LEDBLINKRATE_64MS, + LEDBLINKRATE_128MS, + LEDBLINKRATE_256MS, + LEDBLINKRATE_512MS, + LEDBLINKRATE_1024MS, + LEDBLINKRATE_48MS, + LEDBLINKRATE_96MS, + LEDBLINKRATE_END, +}; + +enum RTL8367C_LEDFORCEMODE{ + + LEDFORCEMODE_NORMAL=0, + LEDFORCEMODE_BLINK, + LEDFORCEMODE_OFF, + LEDFORCEMODE_ON, + LEDFORCEMODE_END, +}; + +enum RTL8367C_LEDFORCERATE{ + + LEDFORCERATE_512MS=0, + LEDFORCERATE_1024MS, + LEDFORCERATE_2048MS, + LEDFORCERATE_NORMAL, + LEDFORCERATE_END, + +}; + +enum RTL8367C_LEDMODE +{ + RTL8367C_LED_MODE_0 = 0, + RTL8367C_LED_MODE_1, + RTL8367C_LED_MODE_2, + RTL8367C_LED_MODE_3, + RTL8367C_LED_MODE_END +}; + +extern ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config); +extern ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig); +extern ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode); +extern ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode); +extern ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate); +extern ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate); +extern ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate); +extern ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate); +extern ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask); +extern ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode); +extern ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode); +extern ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode); +extern ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled); +extern ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask); +extern ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask); + + +#endif /*#ifndef _RTL8367C_ASICDRV_LED_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h new file mode 100644 index 000000000000..c94ea0760193 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_lut.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : LUT related functions + * + */ + + +#ifndef _RTL8367C_ASICDRV_LUT_H_ +#define _RTL8367C_ASICDRV_LUT_H_ + +#include + +#define RTL8367C_LUT_AGETIMERMAX (7) +#define RTL8367C_LUT_AGESPEEDMAX (3) +#define RTL8367C_LUT_LEARNLIMITMAX (0x1040) +#define RTL8367C_LUT_ADDRMAX (0x103F) +#define RTL8367C_LUT_IPMCGRP_TABLE_MAX (0x3F) +#define RTL8367C_LUT_ENTRY_SIZE (6) +#define RTL8367C_LUT_BUSY_CHECK_NO (10) + +#define RTL8367C_LUT_TABLE_SIZE (6) + +enum RTL8367C_LUTHASHMETHOD{ + + LUTHASHMETHOD_SVL=0, + LUTHASHMETHOD_IVL, + LUTHASHMETHOD_END, +}; + + +enum RTL8367C_LRNOVERACT{ + + LRNOVERACT_FORWARD=0, + LRNOVERACT_DROP, + LRNOVERACT_TRAP, + LRNOVERACT_END, +}; + +enum RTL8367C_LUTREADMETHOD{ + + LUTREADMETHOD_MAC =0, + LUTREADMETHOD_ADDRESS, + LUTREADMETHOD_NEXT_ADDRESS, + LUTREADMETHOD_NEXT_L2UC, + LUTREADMETHOD_NEXT_L2MC, + LUTREADMETHOD_NEXT_L3MC, + LUTREADMETHOD_NEXT_L2L3MC, + LUTREADMETHOD_NEXT_L2UCSPA, +}; + +enum RTL8367C_FLUSHMODE +{ + FLUSHMDOE_PORT = 0, + FLUSHMDOE_VID, + FLUSHMDOE_FID, + FLUSHMDOE_END, +}; + +enum RTL8367C_FLUSHTYPE +{ + FLUSHTYPE_DYNAMIC = 0, + FLUSHTYPE_BOTH, + FLUSHTYPE_END, +}; + + +typedef struct LUTTABLE{ + + ipaddr_t sip; + ipaddr_t dip; + ether_addr_t mac; + rtk_uint16 ivl_svl:1; + rtk_uint16 cvid_fid:12; + rtk_uint16 fid:4; + rtk_uint16 efid:3; + + rtk_uint16 nosalearn:1; + rtk_uint16 da_block:1; + rtk_uint16 sa_block:1; + rtk_uint16 auth:1; + rtk_uint16 lut_pri:3; + rtk_uint16 sa_en:1; + rtk_uint16 fwd_en:1; + rtk_uint16 mbr:11; + rtk_uint16 spa:4; + rtk_uint16 age:3; + rtk_uint16 l3lookup:1; + rtk_uint16 igmp_asic:1; + rtk_uint16 igmpidx:8; + + rtk_uint16 lookup_hit:1; + rtk_uint16 lookup_busy:1; + rtk_uint16 address:13; + + rtk_uint16 l3vidlookup:1; + rtk_uint16 l3_vid:12; + + rtk_uint16 wait_time; + +}rtl8367c_luttb; + +extern ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed); +extern ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed); +extern ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled); +extern ret_t rtl8367c_getAsicLutCamType(rtk_uint32* pType); +extern ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number); +extern ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber); +extern ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number); +extern ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber); +extern ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action); +extern ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction); +extern ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action); +extern ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction); +extern ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table); +extern ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table); +extern ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber); +extern ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type); +extern ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType); +extern ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type); +extern ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType); +extern ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid); +extern ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid); +extern ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid); +extern ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid); +extern ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled); +extern ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled); +extern ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid); +extern ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid); +extern ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable); +extern ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable); +extern ret_t rtl8367c_setAsicLutFlushAll(void); +extern ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus); +extern ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable); +extern ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable); + +#endif /*_RTL8367C_ASICDRV_LUT_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h new file mode 100644 index 000000000000..ba761a94f8da --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_meter.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Shared meter related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_METER_H_ +#define _RTL8367C_ASICDRV_METER_H_ + +#include + + +extern ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg); +extern ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg); +extern ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbThreshold); +extern ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbThreshold); +extern ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type); +extern ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType); +extern ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index); +extern ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus); + +#endif /*_RTL8367C_ASICDRV_FC_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h new file mode 100644 index 000000000000..ca46e0f4706c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mib.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : MIB related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_MIB_H_ +#define _RTL8367C_ASICDRV_MIB_H_ + +#include + +#define RTL8367C_MIB_PORT_OFFSET (0x7C) +#define RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET (0x420) + +#define RTL8367C_MAX_LOG_CNT_NUM (32) +#define RTL8367C_MIB_MAX_LOG_CNT_IDX (RTL8367C_MAX_LOG_CNT_NUM - 1) +#define RTL8367C_MIB_LOG_CNT_OFFSET (0x3E0) +#define RTL8367C_MIB_MAX_LOG_MODE_IDX (16-1) + +typedef enum RTL8367C_MIBCOUNTER_E{ + + /* RX */ + ifInOctets = 0, + + dot3StatsFCSErrors, + dot3StatsSymbolErrors, + dot3InPauseFrames, + dot3ControlInUnknownOpcodes, + + etherStatsFragments, + etherStatsJabbers, + ifInUcastPkts, + etherStatsDropEvents, + + ifInMulticastPkts, + ifInBroadcastPkts, + inMldChecksumError, + inIgmpChecksumError, + inMldSpecificQuery, + inMldGeneralQuery, + inIgmpSpecificQuery, + inIgmpGeneralQuery, + inMldLeaves, + inIgmpLeaves, + + /* TX/RX */ + etherStatsOctets, + + etherStatsUnderSizePkts, + etherOversizeStats, + etherStatsPkts64Octets, + etherStatsPkts65to127Octets, + etherStatsPkts128to255Octets, + etherStatsPkts256to511Octets, + etherStatsPkts512to1023Octets, + etherStatsPkts1024to1518Octets, + + /* TX */ + ifOutOctets, + + dot3StatsSingleCollisionFrames, + dot3StatMultipleCollisionFrames, + dot3sDeferredTransmissions, + dot3StatsLateCollisions, + etherStatsCollisions, + dot3StatsExcessiveCollisions, + dot3OutPauseFrames, + ifOutDiscards, + + /* ALE */ + dot1dTpPortInDiscards, + ifOutUcastPkts, + ifOutMulticastPkts, + ifOutBroadcastPkts, + outOampduPkts, + inOampduPkts, + + inIgmpJoinsSuccess, + inIgmpJoinsFail, + inMldJoinsSuccess, + inMldJoinsFail, + inReportSuppressionDrop, + inLeaveSuppressionDrop, + outIgmpReports, + outIgmpLeaves, + outIgmpGeneralQuery, + outIgmpSpecificQuery, + outMldReports, + outMldLeaves, + outMldGeneralQuery, + outMldSpecificQuery, + inKnownMulticastPkts, + + /*Device only */ + dot1dTpLearnedEntryDiscards, + RTL8367C_MIBS_NUMBER, + +}RTL8367C_MIBCOUNTER; + + +extern ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 pmask); +extern ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port,RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter); +extern ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter); +extern ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask); + +extern ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value); +extern ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value); + +extern ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer); +extern ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer); +extern ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode); +extern ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type); +extern ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType); +extern ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index); +extern ret_t rtl8367c_setAsicMIBsLength(rtk_uint32 txLengthMode, rtk_uint32 rxLengthMode); +extern ret_t rtl8367c_getAsicMIBsLength(rtk_uint32 *pTxLengthMode, rtk_uint32 *pRxLengthMode); + +#endif /*#ifndef _RTL8367C_ASICDRV_MIB_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h new file mode 100644 index 000000000000..816763fae1e8 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76333 $ + * $Date: 2017-03-09 09:33:15 +0800 (g|, 09 T 2017) $ + * + * Purpose : RTL8367C switch MII access + * Feature : MII access functions + * + */ + +#ifndef _RTL8367C_ASICDRV_MII_MGR_H_ +#define _RTL8367C_ASICDRV_MII_MGR_H_ + +#define u32 unsigned int +extern u32 mii_mgr_read(u32 phy_addr, u32 phy_register, u32 *read_data); +extern u32 mii_mgr_write(u32 phy_addr, u32 phy_register, u32 write_data); + +#endif /*_RTL8367C_ASICDRV_MII_MGR_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h new file mode 100644 index 000000000000..23b788d7a629 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_mirror.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port mirror related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_MIRROR_H_ +#define _RTL8367C_ASICDRV_MIRROR_H_ + +#include + +extern ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor); +extern ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor); +extern ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorPriority(rtk_uint32 priority); +extern ret_t rtl8367c_getAsicPortMirrorPriority(rtk_uint32* pPriority); +extern ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask); +extern ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask); +extern ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror); +extern ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror); + +#endif /*#ifndef _RTL8367C_ASICDRV_MIRROR_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h new file mode 100644 index 000000000000..c666a7b58bd5 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_misc.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Miscellaneous functions + * + */ + +#ifndef _RTL8367C_ASICDRV_MISC_H_ +#define _RTL8367C_ASICDRV_MISC_H_ + +#include + +extern ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac); +extern ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac); +extern ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo); +extern ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength); +extern ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength); +extern ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId); +extern ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId); + +#endif /*_RTL8367C_ASICDRV_MISC_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h new file mode 100644 index 000000000000..c09dc7698868 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_oam.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 42321 $ + * $Date: 2013-08-26 13:51:29 +0800 (g@, 26 K 2013) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : OAM related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_OAM_H_ +#define _RTL8367C_ASICDRV_OAM_H_ + +#include + +enum OAMPARACT +{ + OAM_PARFWD = 0, + OAM_PARLB, + OAM_PARDISCARD, + OAM_PARFWDCPU +}; + +enum OAMMULACT +{ + OAM_MULFWD = 0, + OAM_MULDISCARD, + OAM_MULCPU +}; + +extern ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser); +extern ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser); +extern ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer); +extern ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer); +extern ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority); +extern ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority); +extern ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled); +#endif /*_RTL8367C_ASICDRV_OAM_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h new file mode 100644 index 000000000000..e993d6edf73c --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_phy.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : PHY related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_PHY_H_ +#define _RTL8367C_ASICDRV_PHY_H_ + +#include + +#define RTL8367C_PHY_REGNOMAX 0x1F +#define RTL8367C_PHY_EXTERNALMAX 0x7 + +#define RTL8367C_PHY_BASE 0x2000 +#define RTL8367C_PHY_EXT_BASE 0xA000 + +#define RTL8367C_PHY_OFFSET 5 +#define RTL8367C_PHY_EXT_OFFSET 9 + +#define RTL8367C_PHY_PAGE_ADDRESS 31 + + +extern ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 regData ); +extern ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32* pRegData ); +extern ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ); +extern ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ); +extern ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 value); +extern ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value); + +#endif /*#ifndef _RTL8367C_ASICDRV_PHY_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h new file mode 100644 index 000000000000..ad99d8560b7e --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_port.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76333 $ + * $Date: 2017-03-09 09:33:15 +0800 (g|, 09 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port security related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_PORTSECURITY_H_ +#define _RTL8367C_ASICDRV_PORTSECURITY_H_ + +#include +#include +#include + +/****************************************************************/ +/* Type Definition */ +/****************************************************************/ + +#define RTL8367C_MAC7 7 +#define RTL8367C_EXTNO 3 + +#define RTL8367C_RTCT_PAGE (11) +#define RTL8367C_RTCT_RESULT_A_REG (27) +#define RTL8367C_RTCT_RESULT_B_REG (28) +#define RTL8367C_RTCT_RESULT_C_REG (29) +#define RTL8367C_RTCT_RESULT_D_REG (30) +#define RTL8367C_RTCT_STATUS_REG (26) + +enum L2_SECURITY_BEHAVE +{ + L2_BEHAVE_FLOODING = 0, + L2_BEHAVE_DROP, + L2_BEHAVE_TRAP, + L2_BEHAVE_END +}; + +enum L2_UNDA_BEHAVE +{ + L2_UNDA_BEHAVE_FLOODING_PMASK = 0, + L2_UNDA_BEHAVE_DROP, + L2_UNDA_BEHAVE_TRAP, + L2_UNDA_BEHAVE_FLOODING, + L2_UNDA_BEHAVE_END +}; + +enum L2_SECURITY_SA_BEHAVE +{ + L2_BEHAVE_SA_FLOODING = 0, + L2_BEHAVE_SA_DROP, + L2_BEHAVE_SA_TRAP, + L2_BEHAVE_SA_COPY28051, + L2_BEHAVE_SA_END +}; + +/* enum for port current link speed */ +enum SPEEDMODE +{ + SPD_10M = 0, + SPD_100M, + SPD_1000M, + SPD_2500M +}; + +/* enum for mac link mode */ +enum LINKMODE +{ + MAC_NORMAL = 0, + MAC_FORCE, +}; + +/* enum for port current link duplex mode */ +enum DUPLEXMODE +{ + HALF_DUPLEX = 0, + FULL_DUPLEX +}; + +/* enum for port current MST mode */ +enum MSTMODE +{ + SLAVE_MODE= 0, + MASTER_MODE +}; + + +enum EXTMODE +{ + EXT_DISABLE = 0, + EXT_RGMII, + EXT_MII_MAC, + EXT_MII_PHY, + EXT_TMII_MAC, + EXT_TMII_PHY, + EXT_GMII, + EXT_RMII_MAC, + EXT_RMII_PHY, + EXT_SGMII, + EXT_HSGMII, + EXT_1000X_100FX, + EXT_1000X, + EXT_100FX, + EXT_RGMII_2, + EXT_MII_MAC_2, + EXT_MII_PHY_2, + EXT_TMII_MAC_2, + EXT_TMII_PHY_2, + EXT_RMII_MAC_2, + EXT_RMII_PHY_2, + EXT_END +}; + +enum DOSTYPE +{ + DOS_DAEQSA = 0, + DOS_LANDATTACKS, + DOS_BLATATTACKS, + DOS_SYNFINSCAN, + DOS_XMASCAN, + DOS_NULLSCAN, + DOS_SYN1024, + DOS_TCPSHORTHDR, + DOS_TCPFRAGERROR, + DOS_ICMPFRAGMENT, + DOS_END, + +}; + +typedef struct rtl8367c_port_ability_s{ + rtk_uint16 forcemode; + rtk_uint16 mstfault; + rtk_uint16 mstmode; + rtk_uint16 nway; + rtk_uint16 txpause; + rtk_uint16 rxpause; + rtk_uint16 link; + rtk_uint16 duplex; + rtk_uint16 speed; +}rtl8367c_port_ability_t; + +typedef struct rtl8367c_port_status_s{ + + rtk_uint16 lpi1000; + rtk_uint16 lpi100; + rtk_uint16 mstfault; + rtk_uint16 mstmode; + rtk_uint16 nway; + rtk_uint16 txpause; + rtk_uint16 rxpause; + rtk_uint16 link; + rtk_uint16 duplex; + rtk_uint16 speed; + +}rtl8367c_port_status_t; + +typedef struct rtct_result_s +{ + rtk_uint32 channelAShort; + rtk_uint32 channelBShort; + rtk_uint32 channelCShort; + rtk_uint32 channelDShort; + + rtk_uint32 channelAOpen; + rtk_uint32 channelBOpen; + rtk_uint32 channelCOpen; + rtk_uint32 channelDOpen; + + rtk_uint32 channelAMismatch; + rtk_uint32 channelBMismatch; + rtk_uint32 channelCMismatch; + rtk_uint32 channelDMismatch; + + rtk_uint32 channelALinedriver; + rtk_uint32 channelBLinedriver; + rtk_uint32 channelCLinedriver; + rtk_uint32 channelDLinedriver; + + rtk_uint32 channelALen; + rtk_uint32 channelBLen; + rtk_uint32 channelCLen; + rtk_uint32 channelDLen; +} rtl8367c_port_rtct_result_t; + + +/****************************************************************/ +/* Driver Proto Type Definition */ +/****************************************************************/ +extern ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior); +extern ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior); +extern ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior); +extern ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior); +extern ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior); +extern ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior); +extern ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 block); +extern ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 *pBlock); +extern ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility); +extern ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility); +extern ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus); +extern ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility); +extern ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility); +extern ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode); +extern ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode); +extern ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop); +extern ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop); +extern ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable); +extern ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable); +extern ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable); +extern ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable); +extern ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable); +extern ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask); +extern ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult); +extern ret_t rtl8367c_sdsReset(rtk_uint32 id); +extern ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink); +extern ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state); +extern ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState); + +#endif /*_RTL8367C_ASICDRV_PORTSECURITY_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h new file mode 100644 index 000000000000..e23d88e81f60 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_portIsolation.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port isolation related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_PORTISOLATION_H_ +#define _RTL8367C_ASICDRV_PORTISOLATION_H_ + +#include + +extern ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask); +extern ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask); +extern ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid); +extern ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid); + +#endif /*_RTL8367C_ASICDRV_PORTISOLATION_H_*/ diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h new file mode 100644 index 000000000000..d0a8995879c3 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_qos.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : QoS related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_QOS_H_ +#define _RTL8367C_ASICDRV_QOS_H_ + +#include + +#define RTL8367C_DECISIONPRIMAX 0xFF + +/* enum Priority Selection Types */ +enum PRIDECISION +{ + PRIDEC_PORT = 0, + PRIDEC_ACL, + PRIDEC_DSCP, + PRIDEC_1Q, + PRIDEC_1AD, + PRIDEC_CVLAN, + PRIDEC_DA, + PRIDEC_SA, + PRIDEC_END, +}; + +/* enum Priority Selection Index */ +enum RTL8367C_PRIDEC_TABLE +{ + PRIDEC_IDX0 = 0, + PRIDEC_IDX1, + PRIDEC_IDX_END, +}; + +enum RTL8367C_DOT1P_PRISEL +{ + DOT1P_PRISEL_USER = 0, + DOT1P_PRISEL_TAG, + DOT1P_PRISEL_END +}; + +enum RTL8367C_DSCP_PRISEL +{ + DSCP_PRISEL_INTERNAL = 0, + DSCP_PRISEL_DSCP, + DSCP_PRISEL_USER , + DSCP_PRISEL_END +}; + + +extern ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority ); +extern ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority ); +extern ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type); +extern ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType); +extern ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp ); +extern ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp ); + +extern ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority ); +extern ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority ); +extern ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority ); +extern ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority ); +extern ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority ); +extern ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority ); +extern ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri); +extern ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri); +extern ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32 qid ); +extern ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 qnum, rtk_uint32 priority, rtk_uint32* pQid); +extern ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 qnum ); +extern ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pQnum ); + +extern ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type); +extern ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType); +extern ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp); +extern ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp); + +extern ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index ); +extern ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex ); + +#endif /*#ifndef _RTL8367C_ASICDRV_QOS_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h new file mode 100644 index 000000000000..cde970b638b3 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rldp.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 42321 $ + * $Date: 2013-08-26 13:51:29 +0800 (g@, 26 K 2013) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : RLDP related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_RLDP_H_ +#define _RTL8367C_ASICDRV_RLDP_H_ + +#include +#include + +extern ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src); +extern ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc); +extern ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod); +extern ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod); +extern ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod); +extern ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod); +extern ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed); +extern ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed); +extern ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask); + + +extern ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber); +extern ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair); +extern ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled); + +extern ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask); + +extern ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask); + +extern ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled); + +#endif /*_RTL8367C_ASICDRV_RLDP_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h new file mode 100644 index 000000000000..10c707544f93 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_rma.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 64716 $ + * $Date: 2015-12-31 16:31:55 +0800 (g|, 31 QG 2015) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : RMA related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_RMA_H_ +#define _RTL8367C_ASICDRV_RMA_H_ + +#include + +#define RTL8367C_RMAMAX 0x2F + +enum RTL8367C_RMAOP +{ + RMAOP_FORWARD = 0, + RMAOP_TRAP_TO_CPU, + RMAOP_DROP, + RMAOP_FORWARD_EXCLUDE_CPU, + RMAOP_END +}; + + +typedef struct rtl8367c_rma_s{ + + rtk_uint16 operation; + rtk_uint16 discard_storm_filter; + rtk_uint16 trap_priority; + rtk_uint16 keep_format; + rtk_uint16 vlan_leaky; + rtk_uint16 portiso_leaky; + +}rtl8367c_rma_t; + + +extern ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg); +extern ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg); + +#endif /*#ifndef _RTL8367C_ASICDRV_RMA_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h new file mode 100644 index 000000000000..919a4ca69262 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_scheduling.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Packet Scheduling related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_SCHEDULING_H_ +#define _RTL8367C_ASICDRV_SCHEDULING_H_ + +#include + +#define RTL8367C_QWEIGHTMAX 0x7F +#define RTL8367C_PORT_QUEUE_METER_INDEX_MAX 7 + +/* enum for queue type */ +enum QUEUETYPE +{ + QTYPE_STRICT = 0, + QTYPE_WFQ, +}; +extern ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token); +extern ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token); +extern ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx); +extern ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx); +extern ret_t rtl8367c_setAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx); +extern ret_t rtl8367c_getAsicPprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *ppridx); +extern ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable); +extern ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable); +extern ret_t rtl8367c_setAsicPprEnable(rtk_uint32 port, rtk_uint32 pprEnable); +extern ret_t rtl8367c_getAsicPprEnable(rtk_uint32 port, rtk_uint32 *pprEnable); + +extern ret_t rtl8367c_setAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 weight ); +extern ret_t rtl8367c_getAsicWFQWeight(rtk_uint32, rtk_uint32 queueid, rtk_uint32 *weight ); +extern ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize); +extern ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize); + +extern ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType); +extern ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType); +extern ret_t rtl8367c_setAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 ppridx, rtk_uint32 apridx ); +extern ret_t rtl8367c_getAsicQueueRate(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* ppridx, rtk_uint32* apridx ); +extern ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate); +extern ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate); +extern ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg); +extern ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg); + +#endif /*_RTL8367C_ASICDRV_SCHEDULING_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h new file mode 100644 index 000000000000..3865b5225a81 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_storm.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Storm control filtering related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_STORM_H_ +#define _RTL8367C_ASICDRV_STORM_H_ + +#include + +extern ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter); +extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter); +extern ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask); + + +#endif /*_RTL8367C_ASICDRV_STORM_H_*/ + + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h new file mode 100644 index 000000000000..5a6a4a83290a --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_svlan.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : SVLAN related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_SVLAN_H_ +#define _RTL8367C_ASICDRV_SVLAN_H_ + +#include + +#define RTL8367C_C2SIDXNO 128 +#define RTL8367C_C2SIDXMAX (RTL8367C_C2SIDXNO-1) +#define RTL8367C_MC2SIDXNO 32 +#define RTL8367C_MC2SIDXMAX (RTL8367C_MC2SIDXNO-1) +#define RTL8367C_SP2CIDXNO 128 +#define RTL8367C_SP2CMAX (RTL8367C_SP2CIDXNO-1) + +#define RTL8367C_SVLAN_MEMCONF_LEN 4 +#define RTL8367C_SVLAN_MC2S_LEN 5 +#define RTL8367C_SVLAN_SP2C_LEN 2 + +enum RTL8367C_SPRISEL +{ + SPRISEL_INTERNALPRI = 0, + SPRISEL_CTAGPRI, + SPRISEL_VSPRI, + SPRISEL_PBPRI, + SPRISEL_END +}; + +enum RTL8367C_SUNACCEPT +{ + SUNACCEPT_DROP = 0, + SUNACCEPT_TRAP, + SUNACCEPT_SVLAN, + SUNACCEPT_END +}; + +enum RTL8367C_SVLAN_MC2S_MODE +{ + SVLAN_MC2S_MODE_MAC = 0, + SVLAN_MC2S_MODE_IP, + SVLAN_MC2S_MODE_END +}; + + +typedef struct rtl8367c_svlan_memconf_s{ + + rtk_uint16 vs_member:11; + rtk_uint16 vs_untag:11; + + rtk_uint16 vs_fid_msti:4; + rtk_uint16 vs_priority:3; + rtk_uint16 vs_force_fid:1; + rtk_uint16 reserved:8; + + rtk_uint16 vs_svid:12; + rtk_uint16 vs_efiden:1; + rtk_uint16 vs_efid:3; + + +}rtl8367c_svlan_memconf_t; + + +typedef struct rtl8367c_svlan_mc2s_s{ + + rtk_uint16 valid:1; + rtk_uint16 format:1; + rtk_uint16 svidx:6; + rtk_uint32 sdata; + rtk_uint32 smask; +}rtl8367c_svlan_mc2s_t; + + +typedef struct rtl8367c_svlan_s2c_s{ + + rtk_uint16 valid:1; + rtk_uint16 svidx:6; + rtk_uint16 dstport:4; + rtk_uint32 vid:12; +}rtl8367c_svlan_s2c_t; + +extern ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority); +extern ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority); +extern ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index); +extern ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex); + +extern ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg); +extern ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg); + +extern ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel); +extern ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel); +extern ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType); +extern ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType); +extern ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask); +extern ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask); +extern ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx); +extern ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx); +extern ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg); +extern ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg); +extern ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg); +extern ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg); +extern ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index); +extern ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex); +extern ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index); +extern ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex); +extern ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type); +extern ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType); + + +#endif /*#ifndef _RTL8367C_ASICDRV_SVLAN_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h new file mode 100644 index 000000000000..2e3a682819db --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_trunking.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port trunking related functions + * + */ + + +#ifndef _RTL8367C_ASICDRV_TRUNKING_H_ +#define _RTL8367C_ASICDRV_TRUNKING_H_ + +#include + +#define RTL8367C_MAX_TRUNK_GID (2) +#define RTL8367C_TRUNKING_PORTNO (4) +#define RTL8367C_TRUNKING1_PORTN0 (2) +#define RTL8367C_TRUNKING_HASHVALUE_MAX (15) + +extern ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask); +extern ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel); +extern ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel); + +extern ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* pPortmask); + +extern ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode); +extern ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode); +extern ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId); +extern ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId); +extern ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId); +extern ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId); + +#endif /*_RTL8367C_ASICDRV_TRUNKING_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h new file mode 100644 index 000000000000..e492e715b39b --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_unknownMulticast.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Unknown multicast related functions + * + */ + +#ifndef _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_ +#define _RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_ + +#include + +enum L2_UNKOWN_MULTICAST_BEHAVE +{ + L2_UNKOWN_MULTICAST_FLOODING = 0, + L2_UNKOWN_MULTICAST_DROP, + L2_UNKOWN_MULTICAST_TRAP, + L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA, + L2_UNKOWN_MULTICAST_END +}; + +enum L3_UNKOWN_MULTICAST_BEHAVE +{ + L3_UNKOWN_MULTICAST_FLOODING = 0, + L3_UNKOWN_MULTICAST_DROP, + L3_UNKOWN_MULTICAST_TRAP, + L3_UNKOWN_MULTICAST_ROUTER, + L3_UNKOWN_MULTICAST_END +}; + +enum MULTICASTTYPE{ + MULTICAST_TYPE_IPV4 = 0, + MULTICAST_TYPE_IPV6, + MULTICAST_TYPE_L2, + MULTICAST_TYPE_END +}; + +extern ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); +extern ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); +extern ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); +extern ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); +extern ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave); +extern ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave); +extern ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority); +extern ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority); + +#endif /*_RTL8367C_ASICDRV_UNKNOWNMULTICAST_H_*/ + + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h new file mode 100644 index 000000000000..61848650b579 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_asicdrv_vlan.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : VLAN related functions + * + */ + + +#ifndef _RTL8367C_ASICDRV_VLAN_H_ +#define _RTL8367C_ASICDRV_VLAN_H_ + +/****************************************************************/ +/* Header File inclusion */ +/****************************************************************/ +#include + +/****************************************************************/ +/* Constant Definition */ +/****************************************************************/ +#define RTL8367C_PROTOVLAN_GIDX_MAX 3 +#define RTL8367C_PROTOVLAN_GROUPNO 4 + +#define RTL8367C_VLAN_BUSY_CHECK_NO (10) + +#define RTL8367C_VLAN_MBRCFG_LEN (4) +#define RTL8367C_VLAN_4KTABLE_LEN (3) + +/****************************************************************/ +/* Type Definition */ +/****************************************************************/ +typedef struct VLANCONFIGUSER +{ + rtk_uint16 evid; + rtk_uint16 mbr; + rtk_uint16 fid_msti; + rtk_uint16 envlanpol; + rtk_uint16 meteridx; + rtk_uint16 vbpen; + rtk_uint16 vbpri; +}rtl8367c_vlanconfiguser; + +typedef struct USER_VLANTABLE{ + + rtk_uint16 vid; + rtk_uint16 mbr; + rtk_uint16 untag; + rtk_uint16 fid_msti; + rtk_uint16 envlanpol; + rtk_uint16 meteridx; + rtk_uint16 vbpen; + rtk_uint16 vbpri; + rtk_uint16 ivl_svl; + +}rtl8367c_user_vlan4kentry; + +typedef enum +{ + FRAME_TYPE_BOTH = 0, + FRAME_TYPE_TAGGED_ONLY, + FRAME_TYPE_UNTAGGED_ONLY, + FRAME_TYPE_MAX_BOUND +} rtl8367c_accframetype; + +typedef enum +{ + EG_TAG_MODE_ORI = 0, + EG_TAG_MODE_KEEP, + EG_TAG_MODE_PRI_TAG, + EG_TAG_MODE_REAL_KEEP, + EG_TAG_MODE_END +} rtl8367c_egtagmode; + +typedef enum +{ + PPVLAN_FRAME_TYPE_ETHERNET = 0, + PPVLAN_FRAME_TYPE_LLC, + PPVLAN_FRAME_TYPE_RFC1042, + PPVLAN_FRAME_TYPE_END +} rtl8367c_provlan_frametype; + +enum RTL8367C_STPST +{ + STPST_DISABLED = 0, + STPST_BLOCKING, + STPST_LEARNING, + STPST_FORWARDING +}; + +enum RTL8367C_RESVIDACT +{ + RES_VID_ACT_UNTAG = 0, + RES_VID_ACT_TAG, + RES_VID_ACT_END +}; + +typedef struct +{ + rtl8367c_provlan_frametype frameType; + rtk_uint32 etherType; +} rtl8367c_protocolgdatacfg; + +typedef struct +{ + rtk_uint32 valid; + rtk_uint32 vlan_idx; + rtk_uint32 priority; +} rtl8367c_protocolvlancfg; + +extern ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg); +extern ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg); +extern ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ); +extern ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ); +extern ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType); +extern ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType); +extern ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable); +extern ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode); +extern ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode); +extern ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri); +extern ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri); +extern ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg); +extern ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg); +extern ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg); +extern ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg); +extern ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled); + +extern ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid); +extern ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid); +extern ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled); +extern ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state); +extern ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState); +extern ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled); +extern ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled); +extern ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask); +extern ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask); +extern ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask); +extern ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action); +extern ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action); +extern ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled); +extern ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled); +extern ret_t rtl8367c_resetVlan(void); + +#endif /*#ifndef _RTL8367C_ASICDRV_VLAN_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h new file mode 100644 index 000000000000..7a70e158fa6f --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_base.h @@ -0,0 +1,596 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (gT, 08 T 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Register MACRO related definition + * + */ + +#ifndef _RTL8367C_BASE_H_ +#define _RTL8367C_BASE_H_ + +#include + +/* (16'h0000) port_reg */ + +#define RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE RTL8367C_REG_PKTGEN_PORT0_TIMER +#define RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_REG(port) (RTL8367C_PORT_SPECIAL_CONGEST_MODE_TIMER_BASE + (port << 5)) + +#define RTL8367C_PORT_MISC_CFG_BASE RTL8367C_REG_PORT0_MISC_CFG +#define RTL8367C_PORT_MISC_CFG_REG(port) (RTL8367C_PORT_MISC_CFG_BASE + (port << 5)) +#define RTL8367C_1QREMARK_ENABLE_OFFSET RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET +#define RTL8367C_1QREMARK_ENABLE_MASK RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK + +#define RTL8367C_INGRESSBW_PORT_IFG_MASK RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK +#define RTL8367C_VLAN_EGRESS_MDOE_MASK RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK +#define RTL8367C_SPECIALCONGEST_SUSTAIN_TIMER_MASK RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK + +#define RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0 +#define RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port) (RTL8367C_INGRESSBW_PORT_RATE_LSB_BASE + (port << 5)) + +#define RTL8367C_PORT_SMALL_IPG_REG(port) (RTL8367C_REG_PORT0_MISC_CFG + (port*0x20)) + +#define RTL8367C_PORT_EEE_CFG_BASE RTL8367C_REG_PORT0_EEECFG +#define RTL8367C_PORT_EEE_CFG_REG(port) (RTL8367C_REG_PORT0_EEECFG + (port << 5)) +#define RTL8367C_PORT_EEE_100M_OFFSET RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET +#define RTL8367C_PORT_EEE_100M_MASK RTL8367C_PORT0_EEECFG_EEE_100M_MASK +#define RTL8367C_PORT_EEE_GIGA_OFFSET RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET +#define RTL8367C_PORT_EEE_GIGA_MASK RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK + + +/* (16'h0200) outq_reg */ + +#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON +#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(queue) (RTL8367C_FLOWCTRL_QUEUE_DROP_ON_BASE + queue) +#define RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK + +#define RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON +#define RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(PORT) (RTL8367C_FLOWCTRL_PORT_DROP_ON_BASE + PORT) +#define RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK + +#define RTL8367C_FLOWCTRL_PORT_GAP_REG RTL8367C_REG_FLOWCTRL_PORT_GAP +#define RTL8367C_FLOWCTRL_QUEUE_GAP_REG RTL8367C_REG_FLOWCTRL_QUEUE_GAP +#define RTL8367C_FLOWCTRL_PORT_QEMPTY_REG RTL8367C_REG_PORT_QEMPTY + +/* (16'h0300) sch_reg */ + +#define RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE + +#define RTL8367C_SCHEDULE_QUEUE_TYPE_BASE RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0 +#define RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port) (RTL8367C_SCHEDULE_QUEUE_TYPE_BASE + (port >> 1)) +#define RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue) (((port & 0x1) << 3) + queue) +#define RTL8367C_SCHEDULE_QUEUE_TYPE_MASK(port, queue) RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, queue) + +#define RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT +#define RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, queue) (RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_BASE + (port << 3) + queue) + +#define RTL8367C_SCHEDULE_APR_CTRL_REG RTL8367C_REG_SCHEDULE_APR_CTRL0 +#define RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port) (port) +#define RTL8367C_SCHEDULE_APR_CTRL_MASK(port) (1 << RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port)) + +#define RTL8367C_SCHEDULE_PORT_APR_METER_BASE RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0 +#define RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, queue) (RTL8367C_SCHEDULE_PORT_APR_METER_BASE + (port << 2) + (queue / 5)) +#define RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue) (3 * (queue % 5)) +#define RTL8367C_SCHEDULE_PORT_APR_METER_MASK(queue) (RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK << RTL8367C_SCHEDULE_PORT_APR_METER_OFFSET(queue)) + +#define RTL8367C_PORT_EGRESSBW_LSB_BASE RTL8367C_REG_PORT0_EGRESSBW_CTRL0 +#define RTL8367C_PORT_EGRESSBW_LSB_REG(port) (RTL8367C_PORT_EGRESSBW_LSB_BASE + (port << 1)) + +#define RTL8367C_PORT_EGRESSBW_MSB_BASE RTL8367C_REG_PORT0_EGRESSBW_CTRL1 +#define RTL8367C_PORT_EGRESSBW_MSB_REG(port) (RTL8367C_PORT_EGRESSBW_MSB_BASE + (port << 1)) + +/* (16'h0500) table_reg */ + +#define RTL8367C_TABLE_ACCESS_CTRL_REG RTL8367C_REG_TABLE_ACCESS_CTRL + +#define RTL8367C_TABLE_ACCESS_ADDR_REG RTL8367C_REG_TABLE_ACCESS_ADDR + +#define RTL8367C_TABLE_ACCESS_STATUS_REG RTL8367C_REG_TABLE_LUT_ADDR + +#define RTL8367C_TABLE_ACCESS_WRDATA_BASE RTL8367C_REG_TABLE_WRITE_DATA0 +#define RTL8367C_TABLE_ACCESS_WRDATA_REG(index) (RTL8367C_TABLE_ACCESS_WRDATA_BASE + index) + +#define RTL8367C_TABLE_ACCESS_RDDATA_BASE RTL8367C_REG_TABLE_READ_DATA0 +#define RTL8367C_TABLE_ACCESS_RDDATA_REG(index) (RTL8367C_TABLE_ACCESS_RDDATA_BASE + index) + + + +/* (16'h0600) acl_reg */ + +#define RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0 +#define RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(template) (RTL8367C_ACL_RULE_TEMPLATE_CTRL_BASE + template * 0x4) +#define RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field) ((field & 0x01) <<3) +#define RTL8367C_ACL_TEMPLATE_FIELD_MASK(field) (0x3F << RTL8367C_ACL_TEMPLATE_FIELD_OFFSET(field)) + +#define RTL8367C_ACL_ACTION_CTRL_BASE RTL8367C_REG_ACL_ACTION_CTRL0 +#define RTL8367C_ACL_ACTION_CTRL_REG(rule) (RTL8367C_ACL_ACTION_CTRL_BASE + (rule >> 1)) +#define RTL8367C_ACL_ACTION_CTRL2_BASE RTL8367C_REG_ACL_ACTION_CTRL32 +#define RTL8367C_ACL_ACTION_CTRL2_REG(rule) (RTL8367C_ACL_ACTION_CTRL2_BASE + ((rule-64) >> 1)) + +#define RTL8367C_ACL_OP_NOT_OFFSET(rule) (6 + ((rule & 0x1) << 3)) +#define RTL8367C_ACL_OP_NOT_MASK(rule) (1 << RTL8367C_ACL_OP_NOT_OFFSET(rule)) +#define RTL8367C_ACL_OP_ACTION_OFFSET(rule) ((rule & 0x1) << 3) +#define RTL8367C_ACL_OP_ACTION_MASK(rule) (0x3F << RTL8367C_ACL_OP_ACTION_OFFSET(rule)) + +#define RTL8367C_ACL_ENABLE_REG RTL8367C_REG_ACL_ENABLE +#define RTL8367C_ACL_UNMATCH_PERMIT_REG RTL8367C_REG_ACL_UNMATCH_PERMIT + +/* (16'h0700) cvlan_reg */ + +#define RTL8367C_VLAN_PVID_CTRL_BASE RTL8367C_REG_VLAN_PVID_CTRL0 +#define RTL8367C_VLAN_PVID_CTRL_REG(port) (RTL8367C_VLAN_PVID_CTRL_BASE + (port >> 1)) +#define RTL8367C_PORT_VIDX_OFFSET(port) ((port &1)<<3) +#define RTL8367C_PORT_VIDX_MASK(port) (RTL8367C_PORT0_VIDX_MASK << RTL8367C_PORT_VIDX_OFFSET(port)) + +#define RTL8367C_VLAN_PPB_VALID_BASE RTL8367C_REG_VLAN_PPB0_VALID +#define RTL8367C_VLAN_PPB_VALID_REG(item) (RTL8367C_VLAN_PPB_VALID_BASE + (item << 3)) + +#define RTL8367C_VLAN_PPB_CTRL_BASE RTL8367C_REG_VLAN_PPB0_CTRL0 +#define RTL8367C_VLAN_PPB_CTRL_REG(item, port) (RTL8367C_VLAN_PPB_CTRL_BASE + (item << 3) + (port / 3) ) +#define RTL8367C_VLAN_PPB_CTRL_OFFSET(port) ((port % 3) * 5) +#define RTL8367C_VLAN_PPB_CTRL_MASK(port) (RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK << RTL8367C_VLAN_PPB_CTRL_OFFSET(port)) + +#define RTL8367C_VLAN_PPB_FRAMETYPE_BASE RTL8367C_REG_VLAN_PPB0_CTRL2 +#define RTL8367C_VLAN_PPB_FRAMETYPE_REG(item) (RTL8367C_VLAN_PPB_FRAMETYPE_BASE + (item << 3)) +#define RTL8367C_VLAN_PPB_FRAMETYPE_MASK RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK + +#define RTL8367C_VLAN_PPB_ETHERTYPR_BASE RTL8367C_REG_VLAN_PPB0_CTRL3 +#define RTL8367C_VLAN_PPB_ETHERTYPR_REG(item) (RTL8367C_VLAN_PPB_ETHERTYPR_BASE + (item << 3)) + +#define RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0 + + +#define RTL8367C_VLAN_CTRL_REG RTL8367C_REG_VLAN_CTRL + +#define RTL8367C_VLAN_INGRESS_REG RTL8367C_REG_VLAN_INGRESS + +#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0 +#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port) (RTL8367C_VLAN_ACCEPT_FRAME_TYPE_BASE + (port >> 3)) +#define RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port) (RTL8367C_PORT0_FRAME_TYPE_MASK << ((port & 0x7) << 1)) + +#define RTL8367C_PORT_EFID_BASE RTL8367C_REG_PORT_EFID_CTRL0 +#define RTL8367C_PORT_EFID_REG(port) (RTL8367C_PORT_EFID_BASE + (port >> 2)) +#define RTL8367C_PORT_EFID_OFFSET(port) ((port & 0x3) << 2) +#define RTL8367C_PORT_EFID_MASK(port) (RTL8367C_PORT0_EFID_MASK << RTL8367C_PORT_EFID_OFFSET(port)) + +#define RTL8367C_PORT_PBFIDEN_REG RTL8367C_REG_PORT_PBFIDEN + +#define RTL8367C_PORT_PBFID_BASE RTL8367C_REG_PORT0_PBFID +#define RTL8367C_PORT_PBFID_REG(port) (RTL8367C_PORT_PBFID_BASE + port) + +/* (16'h0800) dpm_reg */ + +#define RTL8367C_RMA_CTRL_BASE RTL8367C_REG_RMA_CTRL00 + + +#define RTL8367C_VLAN_PORTBASED_PRIORITY_BASE RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port) (RTL8367C_VLAN_PORTBASED_PRIORITY_BASE + (port >> 2)) +#define RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port) ((port & 0x3) << 2) +#define RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port) (0x7 << RTL8367C_VLAN_PORTBASED_PRIORITY_OFFSET(port)) + +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, item) (RTL8367C_VLAN_PPB_PRIORITY_ITEM_BASE + (item << 2)+ (port>>2)) +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port) ((port & 0x3) <<2) +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port) (RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK << RTL8367C_VLAN_PPB_PRIORITY_ITEM_OFFSET(port)) + +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(pri) (RTL8367C_QOS_1Q_PRIORITY_REMAPPING_BASE + (pri >> 2)) +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri) ((pri & 0x3) << 2) +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(pri) (0x7 << RTL8367C_QOS_1Q_PRIORITY_REMAPPING_OFFSET(pri)) + +#define RTL8367C_QOS_DSCP_TO_PRIORITY_BASE RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0 +#define RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp) (RTL8367C_QOS_DSCP_TO_PRIORITY_BASE + (dscp >> 2)) +#define RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp) ((dscp & 0x3) << 2) +#define RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp) (0x7 << RTL8367C_QOS_DSCP_TO_PRIORITY_OFFSET(dscp)) + +#define RTL8367C_QOS_PORTBASED_PRIORITY_BASE RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0 +#define RTL8367C_QOS_PORTBASED_PRIORITY_REG(port) (RTL8367C_QOS_PORTBASED_PRIORITY_BASE + (port >> 2)) +#define RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port) ((port & 0x3) << 2) +#define RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port) (0x7 << RTL8367C_QOS_PORTBASED_PRIORITY_OFFSET(port)) + +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_BASE + (src >> 1)) +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_OFFSET(src) ((src & 1) << 3) +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src)) + +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_BASE + (src >> 1)) +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src) ((src & 1) << 3) +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(src) (RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK << RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_OFFSET(src)) + +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX(port) (1 << port) + +#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0 +#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(pri) (RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_BASE + (pri >> 2)) +#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri) ((pri & 0x3) << 2) +#define RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(pri) (RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK << RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_OFFSET(pri)) + +#define RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG RTL8367C_REG_QOS_TRAP_PRIORITY0 + +#define RTL8367C_QOS_TRAP_PRIORITY_CTRL1_REG RTL8367C_REG_QOS_TRAP_PRIORITY1 + +#define RTL8367C_QOS_DSCP_TO_DSCP_BASE RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 +#define RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp) (RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 + (dscp >> 1)) +#define RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp) ((dscp & 0x1) << 8) +#define RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp) (0x3F << RTL8367C_QOS_DSCP_TO_DSCP_OFFSET(dscp)) + +#define RTL8367C_UNUCAST_FLOADING_PMSK_REG RTL8367C_REG_UNDA_FLOODING_PMSK + +#define RTL8367C_UNMCAST_FLOADING_PMSK_REG RTL8367C_REG_UNMCAST_FLOADING_PMSK + +#define RTL8367C_BCAST_FLOADING_PMSK_REG RTL8367C_REG_BCAST_FLOADING_PMSK + +#define RTL8367C_PORT_ISOLATION_PORT_MASK_BASE RTL8367C_REG_PORT_ISOLATION_PORT0_MASK +#define RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port) (RTL8367C_PORT_ISOLATION_PORT_MASK_BASE + port) + +#define RTL8367C_FORCE_CTRL_REG RTL8367C_REG_FORCE_CTRL + +#define RTL8367C_SOURCE_PORT_BLOCK_REG RTL8367C_REG_SOURCE_PORT_PERMIT + +#define RTL8367C_IPMCAST_VLAN_LEAKY_REG RTL8367C_REG_IPMCAST_VLAN_LEAKY + +#define RTL8367C_IPMCAST_PORTISO_LEAKY_REG RTL8367C_REG_IPMCAST_PORTISO_LEAKY + +#define RTL8367C_PORT_SECURIT_CTRL_REG RTL8367C_REG_PORT_SECURITY_CTRL + +#define RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0 +#define RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port) (RTL8367C_UNKNOWN_IPV4_MULTICAST_BASE + (port >> 3)) +#define RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port) ((port & 0x7) << 1) +#define RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV4_MULTICAST_OFFSET(port)) + +#define RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0 +#define RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port) (RTL8367C_UNKNOWN_IPV6_MULTICAST_BASE + (port >> 3)) +#define RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port) ((port & 0x7) << 1) +#define RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK << RTL8367C_UNKNOWN_IPV6_MULTICAST_OFFSET(port)) + +#define RTL8367C_UNKNOWN_L2_MULTICAST_BASE RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0 +#define RTL8367C_UNKNOWN_L2_MULTICAST_REG(port) (RTL8367C_UNKNOWN_L2_MULTICAST_BASE + (port >> 3)) +#define RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port) ((port & 0x7) << 1) +#define RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port) (RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK << RTL8367C_UNKNOWN_L2_MULTICAST_OFFSET(port)) + +#define RTL8367C_PORT_TRUNK_CTRL_REG RTL8367C_REG_PORT_TRUNK_CTRL +#define RTL8367C_PORT_TRUNK_HASH_MASK 0x007F + +#define RTL8367C_PORT_TRUNK_GROUP_MASK_REG RTL8367C_REG_PORT_TRUNK_GROUP_MASK +#define RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group) (group << 2) +#define RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(group) (RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(group)) + +#define RTL8367C_PORT_TRUNK_FLOWCTRL_REG RTL8367C_REG_PORT_TRUNK_FLOWCTRL + +#define RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0 +#define RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port) (RTL8367C_QOS_PORT_QUEUE_NUMBER_BASE + (port >> 2)) +#define RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port) ((port & 0x3) << 2) +#define RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port) (0x7 << RTL8367C_QOS_PORT_QUEUE_NUMBER_OFFSET(port)) + +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, pri) (RTL8367C_QOS_1Q_PRIORITY_TO_QID_BASE + (index << 1) + (pri >> 2)) +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri) ((pri & 0x3) << 2) +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(pri) (RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK << RTL8367C_QOS_1Q_PRIORITY_TO_QID_OFFSET(pri)) + +#define RTL8367C_DEBUG_INFO_BASE RTL8367C_REG_PORT_DEBUG_INFO_CTRL0 +#define RTL8367C_DEBUG_INFO_REG(port) (RTL8367C_DEBUG_INFO_BASE + (port >>1)) +#define RTL8367C_DEBUG_INFO_OFFSET(port) ((port&1)<<3) +#define RTL8367C_DEBUG_INFO_MASK(port) (RTL8367C_PORT0_DEBUG_INFO_MASK << RTL8367C_DEBUG_INFO_OFFSET(port)) + +/* (16'h0a00) l2_reg */ + +#define RTL8367C_VLAN_MSTI_BASE RTL8367C_REG_VLAN_MSTI0_CTRL0 +#define RTL8367C_VLAN_MSTI_REG(tree, port) (RTL8367C_VLAN_MSTI_BASE + (tree << 1) + (port >> 3)) +#define RTL8367C_VLAN_MSTI_OFFSET(port) ((port & 0x7) << 1) +#define RTL8367C_VLAN_MSTI_MASK(port) (RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK << RTL8367C_VLAN_MSTI_OFFSET(port)) + +#define RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO +#define RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port) (RTL8367C_LUT_PORT_LEARN_LIMITNO_BASE + port) + +#define RTL8367C_LUT_CFG_REG RTL8367C_REG_LUT_CFG + +#define RTL8367C_LUT_AGEOUT_CTRL_REG RTL8367C_REG_LUT_AGEOUT_CTRL + +#define RTL8367C_FORCE_FLUSH_REG RTL8367C_REG_FORCE_FLUSH + +#define RTL8367C_STORM_BCAST_REG RTL8367C_REG_STORM_BCAST + +#define RTL8367C_STORM_MCAST_REG RTL8367C_REG_STORM_MCAST + +#define RTL8367C_STORM_UNKNOWN_UCAST_REG RTL8367C_REG_STORM_UNKOWN_UCAST + +#define RTL8367C_STORM_UNKNOWN_MCAST_REG RTL8367C_REG_STORM_UNKOWN_MCAST + +#define RTL8367C_STORM_BCAST_METER_CTRL_BASE RTL8367C_REG_STORM_BCAST_METER_CTRL0 +#define RTL8367C_STORM_BCAST_METER_CTRL_REG(port) (RTL8367C_STORM_BCAST_METER_CTRL_BASE + (port >> 1)) +#define RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_STORM_BCAST_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_BCAST_METER_CTRL_OFFSET(port)) + +#define RTL8367C_STORM_MCAST_METER_CTRL_BASE RTL8367C_REG_STORM_MCAST_METER_CTRL0 +#define RTL8367C_STORM_MCAST_METER_CTRL_REG(port) (RTL8367C_STORM_MCAST_METER_CTRL_BASE + (port >> 1)) +#define RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_STORM_MCAST_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_MCAST_METER_CTRL_OFFSET(port)) + +#define RTL8367C_STORM_UNDA_METER_CTRL_BASE RTL8367C_REG_STORM_UNDA_METER_CTRL0 +#define RTL8367C_STORM_UNDA_METER_CTRL_REG(port) (RTL8367C_STORM_UNDA_METER_CTRL_BASE + (port >> 1)) +#define RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_STORM_UNDA_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_UNDA_METER_CTRL_OFFSET(port)) + +#define RTL8367C_STORM_UNMC_METER_CTRL_BASE RTL8367C_REG_STORM_UNMC_METER_CTRL0 +#define RTL8367C_STORM_UNMC_METER_CTRL_REG(port) (RTL8367C_STORM_UNMC_METER_CTRL_BASE + (port >> 1)) +#define RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_STORM_UNMC_METER_CTRL_MASK(port) (0xFF << RTL8367C_STORM_UNMC_METER_CTRL_OFFSET(port)) + +#define RTL8367C_OAM_PARSER_OFFSET(port) (port*2) +#define RTL8367C_OAM_PARSER_MASK(port) (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_PARSER_OFFSET(port)) + +#define RTL8367C_OAM_MULTIPLEXER_OFFSET(port) (port*2) +#define RTL8367C_OAM_MULTIPLEXER_MASK(port) (RTL8367C_PORT0_PARACT_MASK << RTL8367C_OAM_MULTIPLEXER_OFFSET(port)) + +#define RTL8367C_OAM_CTRL_REG RTL8367C_REG_OAM_CTRL + +#define RTL8367C_DOT1X_PORT_ENABLE_REG RTL8367C_REG_DOT1X_PORT_ENABLE + +#define RTL8367C_DOT1X_MAC_ENABLE_REG RTL8367C_REG_DOT1X_MAC_ENABLE + +#define RTL8367C_DOT1X_PORT_AUTH_REG RTL8367C_REG_DOT1X_PORT_AUTH + +#define RTL8367C_DOT1X_PORT_OPDIR_REG RTL8367C_REG_DOT1X_PORT_OPDIR + +#define RTL8367C_DOT1X_UNAUTH_ACT_BASE RTL8367C_REG_DOT1X_UNAUTH_ACT_W0 +#define RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port) ((port & 0x7) << 1) +#define RTL8367C_DOT1X_UNAUTH_ACT_MASK(port) (RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK << RTL8367C_DOT1X_UNAUTH_ACT_OFFSET(port)) + +#define RTL8367C_DOT1X_CFG_REG RTL8367C_REG_DOT1X_CFG + +#define RTL8367C_REG_L2_LRN_CNT_BASE RTL8367C_REG_L2_LRN_CNT_CTRL0 +#define RTL8367C_REG_L2_LRN_CNT_REG(port) (RTL8367C_REG_L2_LRN_CNT_BASE + port) + +/* (16'h0b00) mltvlan_reg */ + +#define RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) (RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0 + index*5) + +/* (16'h0c00) svlan_reg */ + +#define RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) (RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1 + index*3) +#define RTL8367C_SVLAN_C2SCFG_BASE_REG(index) (RTL8367C_REG_SVLAN_C2SCFG0_CTRL0+ index*3) +#define RTL8367C_SVLAN_CFG_REG RTL8367C_REG_SVLAN_CFG + +/* (16'h0f00) hsactrl_reg */ + +#define RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) (RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0 + index*2) + +/* (16'h1000) mib_reg */ + +#define RTL8367C_MIB_COUNTER_BASE_REG RTL8367C_REG_MIB_COUNTER0 + +#define RTL8367C_MIB_ADDRESS_REG RTL8367C_REG_MIB_ADDRESS + +#define RTL8367C_MIB_CTRL_REG RTL8367C_REG_MIB_CTRL0 +#define RTL8367C_MIB_PORT07_MASK (0xFF<> 4)) +#define RTL8367C_REG_METER_EXCEED_INDICATOR_OFFSET(meter) (meter & 0xF) + +/* (16'h1200) swcore_reg */ + +#define RTL8367C_VS_TPID_REG RTL8367C_REG_VS_TPID + +#define RTL8367C_SWITCH_MAC_BASE RTL8367C_REG_SWITCH_MAC0 + +#define RTL8367C_REMARKING_CTRL_REG RTL8367C_REG_SWITCH_CTRL0 + +#define RTL8367C_QOS_DSCP_REMARK_BASE RTL8367C_REG_QOS_DSCP_REMARK_CTRL0 +#define RTL8367C_QOS_DSCP_REMARK_REG(pri) (RTL8367C_QOS_DSCP_REMARK_BASE + (pri >> 1)) +#define RTL8367C_QOS_DSCP_REMARK_OFFSET(pri) (((pri) & 0x1) << 3) +#define RTL8367C_QOS_DSCP_REMARK_MASK(pri) (0x3F << RTL8367C_QOS_DSCP_REMARK_OFFSET(pri)) + +#define RTL8367C_QOS_1Q_REMARK_BASE RTL8367C_REG_QOS_1Q_REMARK_CTRL0 +#define RTL8367C_QOS_1Q_REMARK_REG(pri) (RTL8367C_QOS_1Q_REMARK_BASE + (pri >> 2)) +#define RTL8367C_QOS_1Q_REMARK_OFFSET(pri) ((pri & 0x3) << 2) +#define RTL8367C_QOS_1Q_REMARK_MASK(pri) (0x7 << RTL8367C_QOS_1Q_REMARK_OFFSET(pri)) + +#define RTL8367C_PTKGEN_PAYLOAD_CTRL0_REG RTL8367C_REG_PTKGEN_PAYLOAD_CTRL0 + +#define RTL8367C_PTKGEN_PAYLOAD_CTRL1_REG RTL8367C_REG_PTKGEN_PAYLOAD_CTRL1 + +#define RTL8367C_SVLAN_UPLINK_PORTMASK_REG RTL8367C_REG_SVLAN_UPLINK_PORTMASK + +#define RTL8367C_CPU_PORT_MASK_REG RTL8367C_REG_CPU_PORT_MASK + +#define RTL8367C_CPU_CTRL_REG RTL8367C_REG_CPU_CTRL + +#define RTL8367C_MIRROR_CTRL_REG RTL8367C_REG_MIRROR_CTRL + + +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0 +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port) (RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_BASE + (port >> 1)) +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_MASK(port) (RTL8367C_PORT0_QUEUE_MASK_MASK << RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)) + + +#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER +#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port) (RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_BASE + port) +#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK + +#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX +#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port) (RTL8367C_FLOWCTRL_PORT_PAGE_MAX_BASE + port) +#define RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK + +#define RTL8367C_FIELD_SELECTOR_REG(index) (RTL8367C_REG_FIELD_SELECTOR0 + index) +#define RTL8367C_FIELD_SELECTOR_ENABLE_OFFSET RTL8367C_FIELD_SELECTOR0_ENABLE_OFFSET +#define RTL8367C_FIELD_SELECTOR_ENABLE_MASK RTL8367C_FIELD_SELECTOR0_ENABLE_MASK +#define RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET +#define RTL8367C_FIELD_SELECTOR_FORMAT_MASK RTL8367C_FIELD_SELECTOR0_FORMAT_MASK +#define RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET +#define RTL8367C_FIELD_SELECTOR_OFFSET_MASK RTL8367C_FIELD_SELECTOR0_OFFSET_MASK + +/* (16'h1300) chip_reg*/ + +/* (16'h1400) mtrpool_reg */ +#define RTL8367C_METER_RATE_BASE RTL8367C_REG_METER0_RATE_CTRL0 +#define RTL8367C_METER_RATE_REG(meter) ((meter << 1) + RTL8367C_METER_RATE_BASE) + +#define RTL8367C_METER_BUCKET_SIZE_BASE RTL8367C_REG_METER0_BUCKET_SIZE +#define RTL8367C_METER_BUCKET_SIZE_REG(meter) (RTL8367C_METER_BUCKET_SIZE_BASE + meter) + +#define RTL8367C_LEAKY_BUCKET_TICK_REG RTL8367C_REG_METER_CTRL0 +#define RTL8367C_LEAKY_BUCKET_TICK_OFFSET RTL8367C_METER_TICK_OFFSET +#define RTL8367C_LEAKY_BUCKET_TICK_MASK RTL8367C_METER_TICK_MASK + +#define RTL8367C_LEAKY_BUCKET_TOKEN_REG RTL8367C_REG_METER_CTRL1 +#define RTL8367C_LEAKY_BUCKET_TOKEN_OFFSET RTL8367C_METER_CTRL1_OFFSET +#define RTL8367C_LEAKY_BUCKET_TOKEN_MASK RTL8367C_METER_CTRL1_MASK + +#define RTL8367C_METER_OVERRATE_INDICATOR_BASE RTL8367C_REG_METER_OVERRATE_INDICATOR0 +#define RTL8367C_METER_OVERRATE_INDICATOR_REG(meter) (RTL8367C_METER_OVERRATE_INDICATOR_BASE + (meter >> 4)) +#define RTL8367C_METER_EXCEED_OFFSET(meter) (meter & 0xF) +#define RTL8367C_METER_EXCEED_MASK(meter) (1 << RTL8367C_METER_EXCEED_OFFSET(meter)) + +#define RTL8367C_METER_IFG_CTRL_BASE RTL8367C_REG_METER_IFG_CTRL0 +#define RTL8367C_METER_IFG_CTRL_REG(meter) (RTL8367C_METER_IFG_CTRL_BASE + (meter >> 4)) +#define RTL8367C_METER_IFG_OFFSET(meter) (meter & 0xF) +#define RTL8367C_METER_IFG_MASK(meter) (1 << RTL8367C_METER_IFG_OFFSET(meter)) + +#define RTL8367C_FLOWCTRL_CTRL_REG RTL8367C_REG_FLOWCTRL_CTRL0 + +/* (16'h1800)8051_RLDP_EEE_reg */ +#define RTL8367C_EEELLDP_CTRL0_REG RTL8367C_REG_EEELLDP_CTRL0 + +#define RTL8367C_EEELLDP_CTRL1_REG RTL8367C_REG_EEELLDP_CTRL1 + +#define RTL8367C_EEELLDP_PMSK_REG RTL8367C_REG_EEELLDP_PMSK + +#define RTL8367C_EEELLDP_TX_FRAMEU_REG_BASE RTL8367C_REG_EEELLDP_FRAMEU00 + +#define RTL8367C_EEELLDP_TX_CAP_FRAMEL_REG_BASE RTL8367C_REG_EEELLDP_CAP_FRAMEL00 + +#define RTL8367C_EEELLDP_RX_VALUE_PORT_BASE RTL8367C_REG_EEELLDP_RX_VALUE_P00_00 +#define RTL8367C_EEELLDP_RX_VALUE_PORT_REG(port) (RTL8367C_EEELLDP_RX_VALUE_PORT_BASE + (port * 9)) + +#define RTL8367C_RLDP_CTRL0_REG RTL8367C_REG_RLDP_CTRL0 +#define RTL8367C_RLDP_MODE_OFFSET 14 + +#define RTL8367C_RLDP_RETRY_COUNT_REG RTL8367C_REG_RLDP_CTRL1 + +#define RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG RTL8367C_REG_RLDP_CTRL2 + +#define RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG RTL8367C_REG_RLDP_CTRL3 + +#define RTL8367C_RLDP_TX_PMSK_REG RTL8367C_REG_RLDP_CTRL4 + +#define RTL8367C_RLDP_RAND_NUM_REG_BASE RTL8367C_REG_RLDP_RAND_NUM0 + +#define RTL8367C_RLDP_MAGIC_NUM_REG_BASE RTL8367C_REG_RLDP_MAGIC_NUM0 + +#define RTL8367C_RLDP_LOOP_PMSK_REG RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR + +#define RTL8367C_RLDP_LOOP_PORT_BASE RTL8367C_REG_RLDP_LOOP_PORT_REG0 +#define RTL8367C_RLDP_LOOP_PORT_REG(port) (RTL8367C_RLDP_LOOP_PORT_BASE + (port >> 1)) +#define RTL8367C_RLDP_LOOP_PORT_OFFSET(port) ((port & 0x1) << 3) +#define RTL8367C_RLDP_LOOP_PORT_MASK(port) (RTL8367C_RLDP_LOOP_PORT_00_MASK << RTL8367C_RLDP_LOOP_PORT_OFFSET(port)) + +#define RTL8367C_PAGEMETER_PORT_BASE RTL8367C_REG_PAGEMETER_PORT0_CTRL0 +#define RTL8367C_PAGEMETER_PORT_REG(port) (RTL8367C_PAGEMETER_PORT_BASE + 0x20*port) + +#define RTL8367C_HIGHPRI_INDICATOR_REG RTL8367C_REG_HIGHPRI_INDICATOR +#define RTL8367C_PORT_INDICATOR_OFFSET(port) (port) +#define RTL8367C_PORT_INDICATOR_MASK(port) (RTL8367C_PORT0_INDICATOR_MASK << RTL8367C_PORT_INDICATOR_OFFSET(port)) + +#define RTL8367C_HIGHPRI_CFG_REG RTL8367C_REG_HIGHPRI_CFG + +#define RTL8367C_EAV_PRIORITY_REMAPPING_BASE RTL8367C_REG_EAV_CTRL1 +#define RTL8367C_EAV_PRIORITY_REMAPPING_REG(pri) (RTL8367C_EAV_PRIORITY_REMAPPING_BASE + (pri >> 2)) +#define RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri) ((pri & 0x3) * RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET) +#define RTL8367C_EAV_PRIORITY_REMAPPING_MASK(pri) (RTL8367C_REMAP_EAV_PRI0_REGEN_MASK << RTL8367C_EAV_PRIORITY_REMAPPING_OFFSET(pri)) + +#define RTL8367C_EEEP_CFG_BASE RTL8367C_REG_PORT0_EEECFG +#define RTL8367C_EEEP_CFG_REG(port) (RTL8367C_EEEP_CFG_BASE + (port*0x20)) + +#define RTL8367C_PKG_CFG_BASE RTL8367C_REG_PKTGEN_PORT0_CTRL +#define RTL8367C_PKG_CFG_REG(port) (RTL8367C_PKG_CFG_BASE + (port*0x20)) + +#define RTL8367C_PKG_DA_BASE RTL8367C_REG_PKTGEN_PORT0_DA0 +#define RTL8367C_PKG_DA_REG(port) (RTL8367C_PKG_DA_BASE + (port*0x20)) + +#define RTL8367C_PKG_SA_BASE RTL8367C_REG_PKTGEN_PORT0_SA0 +#define RTL8367C_PKG_SA_REG(port) (RTL8367C_PKG_SA_BASE + (port*0x20)) + +#define RTL8367C_PKG_NUM_BASE RTL8367C_REG_PKTGEN_PORT0_COUNTER0 +#define RTL8367C_PKG_NUM_REG(port) (RTL8367C_PKG_NUM_BASE + (port*0x20)) + +#define RTL8367C_PKG_LENGTH_BASE RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH +#define RTL8367C_PKG_LENGTH_REG(port) (RTL8367C_PKG_LENGTH_BASE + (port*0x20)) + +/* (16'h1c00)IGMP_MLD_reg */ +#define RTL8367C_IGMP_GROUP_USAGE_BASE RTL8367C_REG_IGMP_GROUP_USAGE_LIST0 +#define RTL8367C_IGMP_GROUP_USAGE_REG(idx) (RTL8367C_IGMP_GROUP_USAGE_BASE + (idx / 16)) + +#define RTL8367C_FALLBACK_BASE RTL8367C_REG_FALLBACK_PORT0_CFG0 +#define RTL8367C_FALLBACK_PORT_CFG_REG(port) (RTL8367C_FALLBACK_BASE + (port * 4)) +#define RTL8367C_FALLBACK_PORT_MON_CNT_REG(port) (RTL8367C_FALLBACK_BASE + 1 + (port * 4)) +#define RTL8367C_FALLBACK_PORT_ERR_CNT_REG(port) (RTL8367C_FALLBACK_BASE + 3 + (port * 4)) + + +/* (16'h6400)timer_1588 */ +#define RTL8367C_EAV_CFG_BASE RTL8367C_REG_P0_EAV_CFG +#define RTL8367C_EAV_PORT_CFG_REG(port) (RTL8367C_EAV_CFG_BASE + (port *0x10)) +#define RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET +#define RTL8367C_EAV_CFG_RX_PDELAY_RESP_OFFSET RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET +#define RTL8367C_EAV_CFG_RX_PDELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET +#define RTL8367C_EAV_CFG_RX_DELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET +#define RTL8367C_EAV_CFG_RX_SYNC_OFFSET RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET +#define RTL8367C_EAV_CFG_TX_PDELAY_RESP_OFFSET RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET +#define RTL8367C_EAV_CFG_TX_PDELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET +#define RTL8367C_EAV_CFG_TX_DELAY_REQ_OFFSET RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET +#define RTL8367C_EAV_CFG_TX_SYNC_OFFSET RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET + +#define RTL8367C_REG_TX_SYNC_SEQ_ID_BASE RTL8367C_REG_P0_TX_SYNC_SEQ_ID +#define RTL8367C_REG_TX_SYNC_SEQ_ID(port) (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + (port *0x10)) +#define RTL8367C_REG_SEQ_ID(port, type) (RTL8367C_REG_TX_SYNC_SEQ_ID_BASE + type + (port *0x10)) + +#define RTL8367C_REG_TX_DELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID +#define RTL8367C_REG_TX_PDELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID +#define RTL8367C_REG_TX_PDELAY_RESP_SEQ_ID_BASE RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID +#define RTL8367C_REG_RX_SYNC_SEQ_ID_BASE RTL8367C_REG_P0_RX_SYNC_SEQ_ID +#define RTL8367C_REG_RX_DELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID +#define RTL8367C_REG_RX_PDELAY_REQ_SEQ_ID_BASE RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID +#define RTL8367C_REG_RX_PDELAY_RESP_SEQ_ID_BASE RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID + +#define RTL8367C_REG_PORT_NSEC_L_BASE RTL8367C_REG_P0_PORT_NSEC_15_0 +#define RTL8367C_REG_PORT_NSEC_L(port) (RTL8367C_REG_PORT_NSEC_L_BASE + (port *0x10)) +#define RTL8367C_REG_PORT_NSEC_H_BASE RTL8367C_REG_P0_PORT_NSEC_26_16 +#define RTL8367C_REG_PORT_NSEC_H(port) (RTL8367C_REG_PORT_NSEC_H_BASE + (port *0x10)) +#define RTL8367C_PORT_NSEC_H_OFFSET RTL8367C_P0_PORT_NSEC_26_16_OFFSET +#define RTL8367C_PORT_NSEC_H_MASK RTL8367C_P0_PORT_NSEC_26_16_MASK + +#define RTL8367C_REG_PORT_SEC_L_BASE RTL8367C_REG_P0_PORT_SEC_15_0 +#define RTL8367C_REG_PORT_SEC_L(port) (RTL8367C_REG_PORT_SEC_L_BASE + (port *0x10)) +#define RTL8367C_REG_PORT_SEC_H_BASE RTL8367C_REG_P0_PORT_SEC_31_16 +#define RTL8367C_REG_PORT_SEC_H(port) (RTL8367C_REG_PORT_SEC_H_BASE + (port *0x10)) + +#endif /*#ifndef _RTL8367C_BASE_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h new file mode 100644 index 000000000000..f973c7bcb62d --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/rtl8367c_reg.h @@ -0,0 +1,22819 @@ +#ifndef _RTL8367C_REG_H_ +#define _RTL8367C_REG_H_ + +/************************************************************ +auto-generated register address and field data +*************************************************************/ + +/* (16'h0000)port_reg */ + +#define RTL8367C_REG_PORT0_CGST_HALF_CFG 0x0000 +#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT0_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT0_CTRL 0x0001 +#define RTL8367C_PKTGEN_PORT0_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT0_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT0_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT0_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT0_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT0 0x0002 +#define RTL8367C_TX_ERR_CNT_PORT0_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT0_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT0_DA0 0x0003 + +#define RTL8367C_REG_PKTGEN_PORT0_DA1 0x0004 + +#define RTL8367C_REG_PKTGEN_PORT0_DA2 0x0005 + +#define RTL8367C_REG_PKTGEN_PORT0_SA0 0x0006 + +#define RTL8367C_REG_PKTGEN_PORT0_SA1 0x0007 + +#define RTL8367C_REG_PKTGEN_PORT0_SA2 0x0008 + +#define RTL8367C_REG_PKTGEN_PORT0_COUNTER0 0x0009 + +#define RTL8367C_REG_PKTGEN_PORT0_COUNTER1 0x000a +#define RTL8367C_PKTGEN_PORT0_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT0_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT0_TX_LENGTH 0x000b +#define RTL8367C_PKTGEN_PORT0_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT0_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT0_TIMER 0x000d +#define RTL8367C_PKTGEN_PORT0_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT0_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT0_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT0_MISC_CFG 0x000e +#define RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT0_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT0_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT0_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT0_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT0_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT0_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT0_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT0_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT0_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL0 0x000f + +#define RTL8367C_REG_INGRESSBW_PORT0_RATE_CTRL1 0x0010 +#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT0_FORCE_RATE0 0x0011 + +#define RTL8367C_REG_PORT0_FORCE_RATE1 0x0012 + +#define RTL8367C_REG_PORT0_CURENT_RATE0 0x0013 + +#define RTL8367C_REG_PORT0_CURENT_RATE1 0x0014 + +#define RTL8367C_REG_PORT0_PAGE_COUNTER 0x0015 +#define RTL8367C_PORT0_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT0_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT0_CTRL0 0x0016 + +#define RTL8367C_REG_PAGEMETER_PORT0_CTRL1 0x0017 + +#define RTL8367C_REG_PORT0_EEECFG 0x0018 +#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT0_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT0_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT0_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT0_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT0_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT0_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT0_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT0_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT0_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT0_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT0_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT0_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT0_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT0_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT0_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT0_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT0_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT0_EEETXMTR 0x0019 + +#define RTL8367C_REG_PORT0_EEERXMTR 0x001a + +#define RTL8367C_REG_PORT0_EEEPTXMTR 0x001b + +#define RTL8367C_REG_PORT0_EEEPRXMTR 0x001c + +#define RTL8367C_REG_PTP_PORT0_CFG1 0x001e +#define RTL8367C_PTP_PORT0_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT0_CFG1_MASK 0xFF + +#define RTL8367C_REG_P0_MSIC1 0x001f +#define RTL8367C_P0_MSIC1_OFFSET 0 +#define RTL8367C_P0_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT1_CGST_HALF_CFG 0x0020 +#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT1_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT1_CTRL 0x0021 +#define RTL8367C_PKTGEN_PORT1_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT1_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT1_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT1_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT1_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT1 0x0022 +#define RTL8367C_TX_ERR_CNT_PORT1_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT1_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT1_DA0 0x0023 + +#define RTL8367C_REG_PKTGEN_PORT1_DA1 0x0024 + +#define RTL8367C_REG_PKTGEN_PORT1_DA2 0x0025 + +#define RTL8367C_REG_PKTGEN_PORT1_SA0 0x0026 + +#define RTL8367C_REG_PKTGEN_PORT1_SA1 0x0027 + +#define RTL8367C_REG_PKTGEN_PORT1_SA2 0x0028 + +#define RTL8367C_REG_PKTGEN_PORT1_COUNTER0 0x0029 + +#define RTL8367C_REG_PKTGEN_PORT1_COUNTER1 0x002a +#define RTL8367C_PKTGEN_PORT1_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT1_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT1_TX_LENGTH 0x002b +#define RTL8367C_PKTGEN_PORT1_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT1_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT1_TIMER 0x002d +#define RTL8367C_PKTGEN_PORT1_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT1_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT1_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT1_MISC_CFG 0x002e +#define RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT1_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT1_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT1_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT1_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT1_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT1_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT1_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT1_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT1_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT1_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT1_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT1_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT1_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL0 0x002f + +#define RTL8367C_REG_INGRESSBW_PORT1_RATE_CTRL1 0x0030 +#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT1_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT1_FORCE_RATE0 0x0031 + +#define RTL8367C_REG_PORT1_FORCE_RATE1 0x0032 + +#define RTL8367C_REG_PORT1_CURENT_RATE0 0x0033 + +#define RTL8367C_REG_PORT1_CURENT_RATE1 0x0034 + +#define RTL8367C_REG_PORT1_PAGE_COUNTER 0x0035 +#define RTL8367C_PORT1_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT1_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT1_CTRL0 0x0036 + +#define RTL8367C_REG_PAGEMETER_PORT1_CTRL1 0x0037 + +#define RTL8367C_REG_PORT1_EEECFG 0x0038 +#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT1_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT1_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT1_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT1_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT1_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT1_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT1_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT1_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT1_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT1_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT1_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT1_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT1_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT1_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT1_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT1_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT1_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT1_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT1_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT1_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT1_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT1_EEETXMTR 0x0039 + +#define RTL8367C_REG_PORT1_EEERXMTR 0x003a + +#define RTL8367C_REG_PORT1_EEEPTXMTR 0x003b + +#define RTL8367C_REG_PORT1_EEEPRXMTR 0x003c + +#define RTL8367C_REG_PTP_PORT1_CFG1 0x003e +#define RTL8367C_PTP_PORT1_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT1_CFG1_MASK 0xFF + +#define RTL8367C_REG_P1_MSIC1 0x003f +#define RTL8367C_P1_MSIC1_OFFSET 0 +#define RTL8367C_P1_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT2_CGST_HALF_CFG 0x0040 +#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT2_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT2_CTRL 0x0041 +#define RTL8367C_PKTGEN_PORT2_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT2_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT2_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT2_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT2_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT2 0x0042 +#define RTL8367C_TX_ERR_CNT_PORT2_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT2_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT2_DA0 0x0043 + +#define RTL8367C_REG_PKTGEN_PORT2_DA1 0x0044 + +#define RTL8367C_REG_PKTGEN_PORT2_DA2 0x0045 + +#define RTL8367C_REG_PKTGEN_PORT2_SA0 0x0046 + +#define RTL8367C_REG_PKTGEN_PORT2_SA1 0x0047 + +#define RTL8367C_REG_PKTGEN_PORT2_SA2 0x0048 + +#define RTL8367C_REG_PKTGEN_PORT2_COUNTER0 0x0049 + +#define RTL8367C_REG_PKTGEN_PORT2_COUNTER1 0x004a +#define RTL8367C_PKTGEN_PORT2_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT2_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT2_TX_LENGTH 0x004b +#define RTL8367C_PKTGEN_PORT2_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT2_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT2_TIMER 0x004d +#define RTL8367C_PKTGEN_PORT2_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT2_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT2_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT2_MISC_CFG 0x004e +#define RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT2_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT2_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT2_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT2_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT2_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT2_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT2_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT2_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT2_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT2_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT2_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT2_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT2_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL0 0x004f + +#define RTL8367C_REG_INGRESSBW_PORT2_RATE_CTRL1 0x0050 +#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT2_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT2_FORCE_RATE0 0x0051 + +#define RTL8367C_REG_PORT2_FORCE_RATE1 0x0052 + +#define RTL8367C_REG_PORT2_CURENT_RATE0 0x0053 + +#define RTL8367C_REG_PORT2_CURENT_RATE1 0x0054 + +#define RTL8367C_REG_PORT2_PAGE_COUNTER 0x0055 +#define RTL8367C_PORT2_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT2_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT2_CTRL0 0x0056 + +#define RTL8367C_REG_PAGEMETER_PORT2_CTRL1 0x0057 + +#define RTL8367C_REG_PORT2_EEECFG 0x0058 +#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT2_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT2_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT2_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT2_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT2_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT2_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT2_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT2_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT2_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT2_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT2_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT2_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT2_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT2_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT2_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT2_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT2_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT2_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT2_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT2_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT2_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT2_EEETXMTR 0x0059 + +#define RTL8367C_REG_PORT2_EEERXMTR 0x005a + +#define RTL8367C_REG_PORT2_EEEPTXMTR 0x005b + +#define RTL8367C_REG_PORT2_EEEPRXMTR 0x005c + +#define RTL8367C_REG_PTP_PORT2_CFG1 0x005e +#define RTL8367C_PTP_PORT2_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT2_CFG1_MASK 0xFF + +#define RTL8367C_REG_P2_MSIC1 0x005f +#define RTL8367C_P2_MSIC1_OFFSET 0 +#define RTL8367C_P2_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT3_CGST_HALF_CFG 0x0060 +#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT3_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT3_CTRL 0x0061 +#define RTL8367C_PKTGEN_PORT3_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT3_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT3_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT3_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT3_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT3 0x0062 +#define RTL8367C_TX_ERR_CNT_PORT3_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT3_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT3_DA0 0x0063 + +#define RTL8367C_REG_PKTGEN_PORT3_DA1 0x0064 + +#define RTL8367C_REG_PKTGEN_PORT3_DA2 0x0065 + +#define RTL8367C_REG_PKTGEN_PORT3_SA0 0x0066 + +#define RTL8367C_REG_PKTGEN_PORT3_SA1 0x0067 + +#define RTL8367C_REG_PKTGEN_PORT3_SA2 0x0068 + +#define RTL8367C_REG_PKTGEN_PORT3_COUNTER0 0x0069 + +#define RTL8367C_REG_PKTGEN_PORT3_COUNTER1 0x006a +#define RTL8367C_PKTGEN_PORT3_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT3_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT3_TX_LENGTH 0x006b +#define RTL8367C_PKTGEN_PORT3_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT3_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT3_TIMER 0x006d +#define RTL8367C_PKTGEN_PORT3_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT3_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT3_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT3_MISC_CFG 0x006e +#define RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT3_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT3_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT3_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT3_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT3_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT3_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT3_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT3_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT3_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT3_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT3_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT3_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT3_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL0 0x006f + +#define RTL8367C_REG_INGRESSBW_PORT3_RATE_CTRL1 0x0070 +#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT3_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT3_FORCE_RATE0 0x0071 + +#define RTL8367C_REG_PORT3_FORCE_RATE1 0x0072 + +#define RTL8367C_REG_PORT3_CURENT_RATE0 0x0073 + +#define RTL8367C_REG_PORT3_CURENT_RATE1 0x0074 + +#define RTL8367C_REG_PORT3_PAGE_COUNTER 0x0075 +#define RTL8367C_PORT3_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT3_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT3_CTRL0 0x0076 + +#define RTL8367C_REG_PAGEMETER_PORT3_CTRL1 0x0077 + +#define RTL8367C_REG_PORT3_EEECFG 0x0078 +#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT3_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT3_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT3_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT3_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT3_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT3_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT3_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT3_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT3_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT3_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT3_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT3_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT3_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT3_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT3_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT3_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT3_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT3_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT3_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT3_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT3_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT3_EEETXMTR 0x0079 + +#define RTL8367C_REG_PORT3_EEERXMTR 0x007a + +#define RTL8367C_REG_PORT3_EEEPTXMTR 0x007b + +#define RTL8367C_REG_PORT3_EEEPRXMTR 0x007c + +#define RTL8367C_REG_PTP_PORT3_CFG1 0x007e +#define RTL8367C_PTP_PORT3_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT3_CFG1_MASK 0xFF + +#define RTL8367C_REG_P3_MSIC1 0x007f +#define RTL8367C_P3_MSIC1_OFFSET 0 +#define RTL8367C_P3_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT4_CGST_HALF_CFG 0x0080 +#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT4_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT4_CTRL 0x0081 +#define RTL8367C_PKTGEN_PORT4_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT4_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT4_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT4_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT4_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT4 0x0082 +#define RTL8367C_TX_ERR_CNT_PORT4_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT4_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT4_DA0 0x0083 + +#define RTL8367C_REG_PKTGEN_PORT4_DA1 0x0084 + +#define RTL8367C_REG_PKTGEN_PORT4_DA2 0x0085 + +#define RTL8367C_REG_PKTGEN_PORT4_SA0 0x0086 + +#define RTL8367C_REG_PKTGEN_PORT4_SA1 0x0087 + +#define RTL8367C_REG_PKTGEN_PORT4_SA2 0x0088 + +#define RTL8367C_REG_PKTGEN_PORT4_COUNTER0 0x0089 + +#define RTL8367C_REG_PKTGEN_PORT4_COUNTER1 0x008a +#define RTL8367C_PKTGEN_PORT4_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT4_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT4_TX_LENGTH 0x008b +#define RTL8367C_PKTGEN_PORT4_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT4_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT4_TIMER 0x008d +#define RTL8367C_PKTGEN_PORT4_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT4_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT4_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT4_MISC_CFG 0x008e +#define RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT4_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT4_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT4_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT4_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT4_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT4_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT4_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT4_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT4_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT4_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT4_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT4_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT4_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL0 0x008f + +#define RTL8367C_REG_INGRESSBW_PORT4_RATE_CTRL1 0x0090 +#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT4_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT4_FORCE_RATE0 0x0091 + +#define RTL8367C_REG_PORT4_FORCE_RATE1 0x0092 + +#define RTL8367C_REG_PORT4_CURENT_RATE0 0x0093 + +#define RTL8367C_REG_PORT4_CURENT_RATE1 0x0094 + +#define RTL8367C_REG_PORT4_PAGE_COUNTER 0x0095 +#define RTL8367C_PORT4_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT4_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT4_CTRL0 0x0096 + +#define RTL8367C_REG_PAGEMETER_PORT4_CTRL1 0x0097 + +#define RTL8367C_REG_PORT4_EEECFG 0x0098 +#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT4_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT4_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT4_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT4_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT4_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT4_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT4_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT4_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT4_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT4_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT4_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT4_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT4_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT4_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT4_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT4_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT4_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT4_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT4_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT4_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT4_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT4_EEETXMTR 0x0099 + +#define RTL8367C_REG_PORT4_EEERXMTR 0x009a + +#define RTL8367C_REG_PORT4_EEEPTXMTR 0x009b + +#define RTL8367C_REG_PORT4_EEEPRXMTR 0x009c + +#define RTL8367C_REG_PTP_PORT4_CFG1 0x009e +#define RTL8367C_PTP_PORT4_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT4_CFG1_MASK 0xFF + +#define RTL8367C_REG_P4_MSIC1 0x009f +#define RTL8367C_P4_MSIC1_OFFSET 0 +#define RTL8367C_P4_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT5_CGST_HALF_CFG 0x00a0 +#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT5_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT5_CTRL 0x00a1 +#define RTL8367C_PKTGEN_PORT5_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT5_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT5_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT5_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT5_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT5 0x00a2 +#define RTL8367C_TX_ERR_CNT_PORT5_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT5_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT5_DA0 0x00a3 + +#define RTL8367C_REG_PKTGEN_PORT5_DA1 0x00a4 + +#define RTL8367C_REG_PKTGEN_PORT5_DA2 0x00a5 + +#define RTL8367C_REG_PKTGEN_PORT5_SA0 0x00a6 + +#define RTL8367C_REG_PKTGEN_PORT5_SA1 0x00a7 + +#define RTL8367C_REG_PKTGEN_PORT5_SA2 0x00a8 + +#define RTL8367C_REG_PKTGEN_PORT5_COUNTER0 0x00a9 + +#define RTL8367C_REG_PKTGEN_PORT5_COUNTER1 0x00aa +#define RTL8367C_PKTGEN_PORT5_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT5_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT5_TX_LENGTH 0x00ab +#define RTL8367C_PKTGEN_PORT5_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT5_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT5_TIMER 0x00ad +#define RTL8367C_PKTGEN_PORT5_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT5_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT5_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT5_MISC_CFG 0x00ae +#define RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT5_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT5_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT5_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT5_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT5_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT5_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT5_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT5_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT5_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT5_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT5_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT5_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT5_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL0 0x00af + +#define RTL8367C_REG_INGRESSBW_PORT5_RATE_CTRL1 0x00b0 +#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT5_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT5_FORCE_RATE0 0x00b1 + +#define RTL8367C_REG_PORT5_FORCE_RATE1 0x00b2 + +#define RTL8367C_REG_PORT5_CURENT_RATE0 0x00b3 + +#define RTL8367C_REG_PORT5_CURENT_RATE1 0x00b4 + +#define RTL8367C_REG_PORT5_PAGE_COUNTER 0x00b5 +#define RTL8367C_PORT5_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT5_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT5_CTRL0 0x00b6 + +#define RTL8367C_REG_PAGEMETER_PORT5_CTRL1 0x00b7 + +#define RTL8367C_REG_PORT5_EEECFG 0x00b8 +#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT5_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT5_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT5_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT5_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT5_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT5_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT5_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT5_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT5_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT5_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT5_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT5_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT5_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT5_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT5_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT5_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT5_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT5_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT5_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT5_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT5_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT5_EEETXMTR 0x00b9 + +#define RTL8367C_REG_PORT5_EEERXMTR 0x00ba + +#define RTL8367C_REG_PORT5_EEEPTXMTR 0x00bb + +#define RTL8367C_REG_PORT5_EEEPRXMTR 0x00bc + +#define RTL8367C_REG_PTP_PORT5_CFG1 0x00be +#define RTL8367C_PTP_PORT5_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT5_CFG1_MASK 0xFF + +#define RTL8367C_REG_P5_MSIC1 0x00bf +#define RTL8367C_P5_MSIC1_OFFSET 0 +#define RTL8367C_P5_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT6_CGST_HALF_CFG 0x00c0 +#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT6_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT6_CTRL 0x00c1 +#define RTL8367C_PKTGEN_PORT6_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT6_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT6_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT6_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT6_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT6 0x00c2 +#define RTL8367C_TX_ERR_CNT_PORT6_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT6_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT6_DA0 0x00c3 + +#define RTL8367C_REG_PKTGEN_PORT6_DA1 0x00c4 + +#define RTL8367C_REG_PKTGEN_PORT6_DA2 0x00c5 + +#define RTL8367C_REG_PKTGEN_PORT6_SA0 0x00c6 + +#define RTL8367C_REG_PKTGEN_PORT6_SA1 0x00c7 + +#define RTL8367C_REG_PKTGEN_PORT6_SA2 0x00c8 + +#define RTL8367C_REG_PKTGEN_PORT6_COUNTER0 0x00c9 + +#define RTL8367C_REG_PKTGEN_PORT6_COUNTER1 0x00ca +#define RTL8367C_PKTGEN_PORT6_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT6_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT6_TX_LENGTH 0x00cb +#define RTL8367C_PKTGEN_PORT6_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT6_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT6_TIMER 0x00cd +#define RTL8367C_PKTGEN_PORT6_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT6_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT6_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT6_MISC_CFG 0x00ce +#define RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT6_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT6_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT6_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT6_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT6_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT6_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT6_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT6_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT6_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT6_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT6_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT6_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT6_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL0 0x00cf + +#define RTL8367C_REG_INGRESSBW_PORT6_RATE_CTRL1 0x00d0 +#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT6_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT6_FORCE_RATE0 0x00d1 + +#define RTL8367C_REG_PORT6_FORCE_RATE1 0x00d2 + +#define RTL8367C_REG_PORT6_CURENT_RATE0 0x00d3 + +#define RTL8367C_REG_PORT6_CURENT_RATE1 0x00d4 + +#define RTL8367C_REG_PORT6_PAGE_COUNTER 0x00d5 +#define RTL8367C_PORT6_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT6_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT6_CTRL0 0x00d6 + +#define RTL8367C_REG_PAGEMETER_PORT6_CTRL1 0x00d7 + +#define RTL8367C_REG_PORT6_EEECFG 0x00d8 +#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT6_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT6_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT6_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT6_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT6_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT6_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT6_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT6_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT6_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT6_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT6_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT6_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT6_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT6_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT6_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT6_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT6_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT6_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT6_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT6_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT6_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT6_EEETXMTR 0x00d9 + +#define RTL8367C_REG_PORT6_EEERXMTR 0x00da + +#define RTL8367C_REG_PORT6_EEEPTXMTR 0x00db + +#define RTL8367C_REG_PORT6_EEEPRXMTR 0x00dc + +#define RTL8367C_REG_PTP_PORT6_CFG1 0x00de +#define RTL8367C_PTP_PORT6_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT6_CFG1_MASK 0xFF + +#define RTL8367C_REG_P6_MSIC1 0x00df +#define RTL8367C_P6_MSIC1_OFFSET 0 +#define RTL8367C_P6_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT7_CGST_HALF_CFG 0x00e0 +#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT7_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT7_CTRL 0x00e1 +#define RTL8367C_PKTGEN_PORT7_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT7_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT7_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT7_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT7_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT7 0x00e2 +#define RTL8367C_TX_ERR_CNT_PORT7_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT7_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT7_DA0 0x00e3 + +#define RTL8367C_REG_PKTGEN_PORT7_DA1 0x00e4 + +#define RTL8367C_REG_PKTGEN_PORT7_DA2 0x00e5 + +#define RTL8367C_REG_PKTGEN_PORT7_SA0 0x00e6 + +#define RTL8367C_REG_PKTGEN_PORT7_SA1 0x00e7 + +#define RTL8367C_REG_PKTGEN_PORT7_SA2 0x00e8 + +#define RTL8367C_REG_PKTGEN_PORT7_COUNTER0 0x00e9 + +#define RTL8367C_REG_PKTGEN_PORT7_COUNTER1 0x00ea +#define RTL8367C_PKTGEN_PORT7_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT7_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT7_TX_LENGTH 0x00eb +#define RTL8367C_PKTGEN_PORT7_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT7_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT7_TIMER 0x00ed +#define RTL8367C_PKTGEN_PORT7_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT7_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT7_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT7_MISC_CFG 0x00ee +#define RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT7_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT7_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT7_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT7_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT7_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT7_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT7_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT7_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT7_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT7_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT7_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT7_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT7_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL0 0x00ef + +#define RTL8367C_REG_INGRESSBW_PORT7_RATE_CTRL1 0x00f0 +#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT7_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT7_FORCE_RATE0 0x00f1 + +#define RTL8367C_REG_PORT7_FORCE_RATE1 0x00f2 + +#define RTL8367C_REG_PORT7_CURENT_RATE0 0x00f3 + +#define RTL8367C_REG_PORT7_CURENT_RATE1 0x00f4 + +#define RTL8367C_REG_PORT7_PAGE_COUNTER 0x00f5 +#define RTL8367C_PORT7_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT7_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT7_CTRL0 0x00f6 + +#define RTL8367C_REG_PAGEMETER_PORT7_CTRL1 0x00f7 + +#define RTL8367C_REG_PORT7_EEECFG 0x00f8 +#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT7_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT7_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT7_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT7_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT7_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT7_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT7_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT7_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT7_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT7_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT7_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT7_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT7_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT7_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT7_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT7_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT7_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT7_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT7_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT7_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT7_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT7_EEETXMTR 0x00f9 + +#define RTL8367C_REG_PORT7_EEERXMTR 0x00fa + +#define RTL8367C_REG_PORT7_EEEPTXMTR 0x00fb + +#define RTL8367C_REG_PORT7_EEEPRXMTR 0x00fc + +#define RTL8367C_REG_PTP_PORT7_CFG1 0x00fe +#define RTL8367C_PTP_PORT7_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT7_CFG1_MASK 0xFF + +#define RTL8367C_REG_P7_MSIC1 0x00ff +#define RTL8367C_P7_MSIC1_OFFSET 0 +#define RTL8367C_P7_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT8_CGST_HALF_CFG 0x0100 +#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT8_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT8_CTRL 0x0101 +#define RTL8367C_PKTGEN_PORT8_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT8_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT8_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT8_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT8_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT8 0x0102 +#define RTL8367C_TX_ERR_CNT_PORT8_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT8_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT8_DA0 0x0103 + +#define RTL8367C_REG_PKTGEN_PORT8_DA1 0x0104 + +#define RTL8367C_REG_PKTGEN_PORT8_DA2 0x0105 + +#define RTL8367C_REG_PKTGEN_PORT8_SA0 0x0106 + +#define RTL8367C_REG_PKTGEN_PORT8_SA1 0x0107 + +#define RTL8367C_REG_PKTGEN_PORT8_SA2 0x0108 + +#define RTL8367C_REG_PKTGEN_PORT8_COUNTER0 0x0109 + +#define RTL8367C_REG_PKTGEN_PORT8_COUNTER1 0x010a +#define RTL8367C_PKTGEN_PORT8_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT8_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT8_TX_LENGTH 0x010b +#define RTL8367C_PKTGEN_PORT8_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT8_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT8_TIMER 0x010d +#define RTL8367C_PKTGEN_PORT8_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT8_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT8_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT8_MISC_CFG 0x010e +#define RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT8_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT8_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT8_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT8_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT8_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT8_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT8_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT8_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT8_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT8_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT8_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT8_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT8_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL0 0x010f + +#define RTL8367C_REG_INGRESSBW_PORT8_RATE_CTRL1 0x0110 +#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT8_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT8_FORCE_RATE0 0x0111 + +#define RTL8367C_REG_PORT8_FORCE_RATE1 0x0112 + +#define RTL8367C_REG_PORT8_CURENT_RATE0 0x0113 + +#define RTL8367C_REG_PORT8_CURENT_RATE1 0x0114 + +#define RTL8367C_REG_PORT8_PAGE_COUNTER 0x0115 +#define RTL8367C_PORT8_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT8_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT8_CTRL0 0x0116 + +#define RTL8367C_REG_PAGEMETER_PORT8_CTRL1 0x0117 + +#define RTL8367C_REG_PORT8_EEECFG 0x0118 +#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT8_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT8_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT8_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT8_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT8_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT8_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT8_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT8_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT8_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT8_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT8_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT8_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT8_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT8_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT8_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT8_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT8_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT8_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT8_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT8_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT8_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT8_EEETXMTR 0x0119 + +#define RTL8367C_REG_PORT8_EEERXMTR 0x011a + +#define RTL8367C_REG_PORT8_EEEPTXMTR 0x011b + +#define RTL8367C_REG_PORT8_EEEPRXMTR 0x011c + +#define RTL8367C_REG_PTP_PORT8_CFG1 0x011e +#define RTL8367C_PTP_PORT8_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT8_CFG1_MASK 0xFF + +#define RTL8367C_REG_P8_MSIC1 0x011f +#define RTL8367C_P8_MSIC1_OFFSET 0 +#define RTL8367C_P8_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT9_CGST_HALF_CFG 0x0120 +#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT9_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT9_CTRL 0x0121 +#define RTL8367C_PKTGEN_PORT9_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT9_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT9_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT9_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT9_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT9 0x0122 +#define RTL8367C_TX_ERR_CNT_PORT9_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT9_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT9_DA0 0x0123 + +#define RTL8367C_REG_PKTGEN_PORT9_DA1 0x0124 + +#define RTL8367C_REG_PKTGEN_PORT9_DA2 0x0125 + +#define RTL8367C_REG_PKTGEN_PORT9_SA0 0x0126 + +#define RTL8367C_REG_PKTGEN_PORT9_SA1 0x0127 + +#define RTL8367C_REG_PKTGEN_PORT9_SA2 0x0128 + +#define RTL8367C_REG_PKTGEN_PORT9_COUNTER0 0x0129 + +#define RTL8367C_REG_PKTGEN_PORT9_COUNTER1 0x012a +#define RTL8367C_PKTGEN_PORT9_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT9_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT9_TX_LENGTH 0x012b +#define RTL8367C_PKTGEN_PORT9_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT9_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT9_TIMER 0x012d +#define RTL8367C_PKTGEN_PORT9_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT9_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT9_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT9_MISC_CFG 0x012e +#define RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT9_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT9_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT9_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT9_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT9_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT9_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT9_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT9_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT9_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT9_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT9_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT9_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT9_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL0 0x012f + +#define RTL8367C_REG_INGRESSBW_PORT9_RATE_CTRL1 0x0130 +#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT9_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT9_FORCE_RATE0 0x0131 + +#define RTL8367C_REG_PORT9_FORCE_RATE1 0x0132 + +#define RTL8367C_REG_PORT9_CURENT_RATE0 0x0133 + +#define RTL8367C_REG_PORT9_CURENT_RATE1 0x0134 + +#define RTL8367C_REG_PORT9_PAGE_COUNTER 0x0135 +#define RTL8367C_PORT9_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT9_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT9_CTRL0 0x0136 + +#define RTL8367C_REG_PAGEMETER_PORT9_CTRL1 0x0137 + +#define RTL8367C_REG_PORT9_EEECFG 0x0138 +#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT9_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT9_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT9_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT9_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT9_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT9_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT9_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT9_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT9_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT9_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT9_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT9_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT9_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT9_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT9_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT9_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT9_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT9_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT9_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT9_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT9_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT9_EEETXMTR 0x0139 + +#define RTL8367C_REG_PORT9_EEERXMTR 0x013a + +#define RTL8367C_REG_PORT9_EEEPTXMTR 0x013b + +#define RTL8367C_REG_PORT9_EEEPRXMTR 0x013c + +#define RTL8367C_REG_PTP_PORT9_CFG1 0x013e +#define RTL8367C_PTP_PORT9_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT9_CFG1_MASK 0xFF + +#define RTL8367C_REG_P9_MSIC1 0x013f +#define RTL8367C_P9_MSIC1_OFFSET 0 +#define RTL8367C_P9_MSIC1_MASK 0x1 + +#define RTL8367C_REG_PORT10_CGST_HALF_CFG 0x0140 +#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_OFFSET 4 +#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_TIME_MASK 0xF0 +#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT10_CGST_HALF_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_PKTGEN_PORT10_CTRL 0x0141 +#define RTL8367C_PKTGEN_PORT10_CTRL_STATUS_OFFSET 15 +#define RTL8367C_PKTGEN_PORT10_CTRL_STATUS_MASK 0x8000 +#define RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_OFFSET 13 +#define RTL8367C_PKTGEN_PORT10_CTRL_PKTGEN_STS_MASK 0x2000 +#define RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_OFFSET 4 +#define RTL8367C_PKTGEN_PORT10_CTRL_CRC_NO_ERROR_MASK 0x10 +#define RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_OFFSET 0 +#define RTL8367C_PKTGEN_PORT10_CTRL_CMD_START_MASK 0x1 + +#define RTL8367C_REG_TX_ERR_CNT_PORT10 0x0142 +#define RTL8367C_TX_ERR_CNT_PORT10_OFFSET 0 +#define RTL8367C_TX_ERR_CNT_PORT10_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_PORT10_DA0 0x0143 + +#define RTL8367C_REG_PKTGEN_PORT10_DA1 0x0144 + +#define RTL8367C_REG_PKTGEN_PORT10_DA2 0x0145 + +#define RTL8367C_REG_PKTGEN_PORT10_SA0 0x0146 + +#define RTL8367C_REG_PKTGEN_PORT10_SA1 0x0147 + +#define RTL8367C_REG_PKTGEN_PORT10_SA2 0x0148 + +#define RTL8367C_REG_PKTGEN_PORT10_COUNTER0 0x0149 + +#define RTL8367C_REG_PKTGEN_PORT10_COUNTER1 0x014a +#define RTL8367C_PKTGEN_PORT10_COUNTER1_OFFSET 0 +#define RTL8367C_PKTGEN_PORT10_COUNTER1_MASK 0xFF + +#define RTL8367C_REG_PKTGEN_PORT10_TX_LENGTH 0x014b +#define RTL8367C_PKTGEN_PORT10_TX_LENGTH_OFFSET 0 +#define RTL8367C_PKTGEN_PORT10_TX_LENGTH_MASK 0x3FFF + +#define RTL8367C_REG_PKTGEN_PORT10_TIMER 0x014d +#define RTL8367C_PKTGEN_PORT10_TIMER_TIMER_OFFSET 4 +#define RTL8367C_PKTGEN_PORT10_TIMER_TIMER_MASK 0xF0 +#define RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_OFFSET 3 +#define RTL8367C_PKTGEN_PORT10_TIMER_RX_DMA_ERR_FLAG_MASK 0x8 + +#define RTL8367C_REG_PORT10_MISC_CFG 0x014e +#define RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_OFFSET 15 +#define RTL8367C_PORT10_MISC_CFG_SMALL_TAG_IPG_MASK 0x8000 +#define RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_OFFSET 14 +#define RTL8367C_PORT10_MISC_CFG_TX_ITFSP_MODE_MASK 0x4000 +#define RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_OFFSET 13 +#define RTL8367C_PORT10_MISC_CFG_FLOWCTRL_INDEP_MASK 0x2000 +#define RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_OFFSET 12 +#define RTL8367C_PORT10_MISC_CFG_DOT1Q_REMARK_ENABLE_MASK 0x1000 +#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET 11 +#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_FLOWCTRL_MASK 0x800 +#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_OFFSET 10 +#define RTL8367C_PORT10_MISC_CFG_INGRESSBW_IFG_MASK 0x400 +#define RTL8367C_PORT10_MISC_CFG_RX_SPC_OFFSET 9 +#define RTL8367C_PORT10_MISC_CFG_RX_SPC_MASK 0x200 +#define RTL8367C_PORT10_MISC_CFG_CRC_SKIP_OFFSET 8 +#define RTL8367C_PORT10_MISC_CFG_CRC_SKIP_MASK 0x100 +#define RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_OFFSET 7 +#define RTL8367C_PORT10_MISC_CFG_PKTGEN_TX_FIRST_MASK 0x80 +#define RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_OFFSET 6 +#define RTL8367C_PORT10_MISC_CFG_MAC_LOOPBACK_MASK 0x40 +#define RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_OFFSET 4 +#define RTL8367C_PORT10_MISC_CFG_VLAN_EGRESS_MODE_MASK 0x30 +#define RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_OFFSET 0 +#define RTL8367C_PORT10_MISC_CFG_CONGESTION_SUSTAIN_TIME_MASK 0xF + +#define RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL0 0x014f + +#define RTL8367C_REG_INGRESSBW_PORT10_RATE_CTRL1 0x0150 +#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_OFFSET 3 +#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_DUMMY_MASK 0xFFF8 +#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_OFFSET 0 +#define RTL8367C_INGRESSBW_PORT10_RATE_CTRL1_INGRESSBW_RATE16_MASK 0x7 + +#define RTL8367C_REG_PORT10_FORCE_RATE0 0x0151 + +#define RTL8367C_REG_PORT10_FORCE_RATE1 0x0152 + +#define RTL8367C_REG_PORT10_CURENT_RATE0 0x0153 + +#define RTL8367C_REG_PORT10_CURENT_RATE1 0x0154 + +#define RTL8367C_REG_PORT10_PAGE_COUNTER 0x0155 +#define RTL8367C_PORT10_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_PORT10_PAGE_COUNTER_MASK 0x7F + +#define RTL8367C_REG_PAGEMETER_PORT10_CTRL0 0x0156 + +#define RTL8367C_REG_PAGEMETER_PORT10_CTRL1 0x0157 + +#define RTL8367C_REG_PORT10_EEECFG 0x0158 +#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_OFFSET 14 +#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_TX_MASK 0x4000 +#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_OFFSET 13 +#define RTL8367C_PORT10_EEECFG_EEEP_ENABLE_RX_MASK 0x2000 +#define RTL8367C_PORT10_EEECFG_EEE_FORCE_OFFSET 12 +#define RTL8367C_PORT10_EEECFG_EEE_FORCE_MASK 0x1000 +#define RTL8367C_PORT10_EEECFG_EEE_100M_OFFSET 11 +#define RTL8367C_PORT10_EEECFG_EEE_100M_MASK 0x800 +#define RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_OFFSET 10 +#define RTL8367C_PORT10_EEECFG_EEE_GIGA_500M_MASK 0x400 +#define RTL8367C_PORT10_EEECFG_EEE_TX_OFFSET 9 +#define RTL8367C_PORT10_EEECFG_EEE_TX_MASK 0x200 +#define RTL8367C_PORT10_EEECFG_EEE_RX_OFFSET 8 +#define RTL8367C_PORT10_EEECFG_EEE_RX_MASK 0x100 +#define RTL8367C_PORT10_EEECFG_EEE_DSP_RX_OFFSET 6 +#define RTL8367C_PORT10_EEECFG_EEE_DSP_RX_MASK 0x40 +#define RTL8367C_PORT10_EEECFG_EEE_LPI_OFFSET 5 +#define RTL8367C_PORT10_EEECFG_EEE_LPI_MASK 0x20 +#define RTL8367C_PORT10_EEECFG_EEE_TX_LPI_OFFSET 4 +#define RTL8367C_PORT10_EEECFG_EEE_TX_LPI_MASK 0x10 +#define RTL8367C_PORT10_EEECFG_EEE_RX_LPI_OFFSET 3 +#define RTL8367C_PORT10_EEECFG_EEE_RX_LPI_MASK 0x8 +#define RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_OFFSET 2 +#define RTL8367C_PORT10_EEECFG_EEE_PAUSE_INDICATOR_MASK 0x4 +#define RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_OFFSET 1 +#define RTL8367C_PORT10_EEECFG_EEE_WAKE_REQ_MASK 0x2 +#define RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_OFFSET 0 +#define RTL8367C_PORT10_EEECFG_EEE_SLEEP_REQ_MASK 0x1 + +#define RTL8367C_REG_PORT10_EEETXMTR 0x0159 + +#define RTL8367C_REG_PORT10_EEERXMTR 0x015a + +#define RTL8367C_REG_PORT10_EEEPTXMTR 0x015b + +#define RTL8367C_REG_PORT10_EEEPRXMTR 0x015c + +#define RTL8367C_REG_PTP_PORT10_CFG1 0x015e +#define RTL8367C_PTP_PORT10_CFG1_OFFSET 7 +#define RTL8367C_PTP_PORT10_CFG1_MASK 0xFF + +#define RTL8367C_REG_P10_MSIC1 0x015f +#define RTL8367C_P10_MSIC1_OFFSET 0 +#define RTL8367C_P10_MSIC1_MASK 0x1 + +/* (16'h0200)outq_reg */ + +#define RTL8367C_REG_FLOWCTRL_QUEUE0_DROP_ON 0x0200 +#define RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE0_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE1_DROP_ON 0x0201 +#define RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE1_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE2_DROP_ON 0x0202 +#define RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE2_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE3_DROP_ON 0x0203 +#define RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE3_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE4_DROP_ON 0x0204 +#define RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE4_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE5_DROP_ON 0x0205 +#define RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE5_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE6_DROP_ON 0x0206 +#define RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE6_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE7_DROP_ON 0x0207 +#define RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE7_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT0_DROP_ON 0x0208 +#define RTL8367C_FLOWCTRL_PORT0_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT0_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT1_DROP_ON 0x0209 +#define RTL8367C_FLOWCTRL_PORT1_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT1_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT2_DROP_ON 0x020a +#define RTL8367C_FLOWCTRL_PORT2_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT2_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT3_DROP_ON 0x020b +#define RTL8367C_FLOWCTRL_PORT3_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT3_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT4_DROP_ON 0x020c +#define RTL8367C_FLOWCTRL_PORT4_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT4_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT5_DROP_ON 0x020d +#define RTL8367C_FLOWCTRL_PORT5_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT5_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT6_DROP_ON 0x020e +#define RTL8367C_FLOWCTRL_PORT6_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT6_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT7_DROP_ON 0x020f +#define RTL8367C_FLOWCTRL_PORT7_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT7_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT8_DROP_ON 0x0210 +#define RTL8367C_FLOWCTRL_PORT8_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT8_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT9_DROP_ON 0x0211 +#define RTL8367C_FLOWCTRL_PORT9_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT9_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT10_DROP_ON 0x0212 +#define RTL8367C_FLOWCTRL_PORT10_DROP_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT10_DROP_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_GAP 0x0218 +#define RTL8367C_FLOWCTRL_PORT_GAP_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_GAP_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE_GAP 0x0219 +#define RTL8367C_FLOWCTRL_QUEUE_GAP_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE_GAP_MASK 0x7FF + +#define RTL8367C_REG_PORT_QEMPTY 0x022d +#define RTL8367C_PORT_QEMPTY_OFFSET 0 +#define RTL8367C_PORT_QEMPTY_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_DEBUG_CTRL0 0x022e +#define RTL8367C_FLOWCTRL_DEBUG_CTRL0_OFFSET 0 +#define RTL8367C_FLOWCTRL_DEBUG_CTRL0_MASK 0xF + +#define RTL8367C_REG_FLOWCTRL_DEBUG_CTRL1 0x022f +#define RTL8367C_TOTAL_OFFSET 9 +#define RTL8367C_TOTAL_MASK 0x200 +#define RTL8367C_PORT_MAX_OFFSET 8 +#define RTL8367C_PORT_MAX_MASK 0x100 +#define RTL8367C_QMAX_MASK_OFFSET 0 +#define RTL8367C_QMAX_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCTRL_QUEUE0_PAGE_COUNT 0x0230 +#define RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE0_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE1_PAGE_COUNT 0x0231 +#define RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE1_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE2_PAGE_COUNT 0x0232 +#define RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE2_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE3_PAGE_COUNT 0x0233 +#define RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE3_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE4_PAGE_COUNT 0x0234 +#define RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE4_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE5_PAGE_COUNT 0x0235 +#define RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE5_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE6_PAGE_COUNT 0x0236 +#define RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE6_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE7_PAGE_COUNT 0x0237 +#define RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE7_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_PAGE_COUNT 0x0238 +#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT 0x0239 +#define RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE0_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT 0x023a +#define RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE1_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT 0x023b +#define RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE2_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT 0x023c +#define RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE3_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT 0x023d +#define RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE4_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT 0x023e +#define RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE5_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT 0x023f +#define RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE6_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT 0x0240 +#define RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_QUEUE7_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_MAX_PAGE_COUNT 0x0241 +#define RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_MAX_PAGE_COUNT_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_TOTAL_PACKET_COUNT 0x0243 + +#define RTL8367C_REG_HIGH_QUEUE_MASK0 0x0244 +#define RTL8367C_PORT1_HIGH_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT1_HIGH_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT0_HIGH_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT0_HIGH_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_HIGH_QUEUE_MASK1 0x0245 +#define RTL8367C_PORT3_HIGH_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT3_HIGH_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT2_HIGH_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT2_HIGH_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_HIGH_QUEUE_MASK2 0x0246 +#define RTL8367C_PORT5_HIGH_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT5_HIGH_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT4_HIGH_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT4_HIGH_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_HIGH_QUEUE_MASK3 0x0247 +#define RTL8367C_PORT7_HIGH_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT7_HIGH_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT6_HIGH_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT6_HIGH_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_HIGH_QUEUE_MASK4 0x0248 +#define RTL8367C_PORT9_HIGH_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT9_HIGH_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT8_HIGH_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT8_HIGH_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_HIGH_QUEUE_MASK5 0x0249 +#define RTL8367C_HIGH_QUEUE_MASK5_OFFSET 0 +#define RTL8367C_HIGH_QUEUE_MASK5_MASK 0xFF + +#define RTL8367C_REG_LOW_QUEUE_TH 0x024c +#define RTL8367C_LOW_QUEUE_TH_OFFSET 0 +#define RTL8367C_LOW_QUEUE_TH_MASK 0x7FF + +#define RTL8367C_REG_TH_TX_PREFET 0x0250 +#define RTL8367C_TH_TX_PREFET_OFFSET 0 +#define RTL8367C_TH_TX_PREFET_MASK 0xFF + +#define RTL8367C_REG_DUMMY_0251 0x0251 + +#define RTL8367C_REG_DUMMY_0252 0x0252 + +#define RTL8367C_REG_DUMMY_0253 0x0253 + +#define RTL8367C_REG_DUMMY_0254 0x0254 + +#define RTL8367C_REG_DUMMY_0255 0x0255 + +#define RTL8367C_REG_DUMMY_0256 0x0256 + +#define RTL8367C_REG_DUMMY_0257 0x0257 + +#define RTL8367C_REG_DUMMY_0258 0x0258 + +#define RTL8367C_REG_DUMMY_0259 0x0259 + +#define RTL8367C_REG_DUMMY_025A 0x025A + +#define RTL8367C_REG_DUMMY_025B 0x025B + +#define RTL8367C_REG_DUMMY_025C 0x025C + +#define RTL8367C_REG_Q_TXPKT_CNT_CTL 0x025d +#define RTL8367C_QUEUE_PKT_CNT_CLR_OFFSET 4 +#define RTL8367C_QUEUE_PKT_CNT_CLR_MASK 0x10 +#define RTL8367C_PORT_ID_QUEUE_PKT_CNT_OFFSET 0 +#define RTL8367C_PORT_ID_QUEUE_PKT_CNT_MASK 0xF + +#define RTL8367C_REG_Q0_TXPKT_CNT_L 0x025e + +#define RTL8367C_REG_Q0_TXPKT_CNT_H 0x025f + +#define RTL8367C_REG_Q1_TXPKT_CNT_L 0x0260 + +#define RTL8367C_REG_Q1_TXPKT_CNT_H 0x0261 + +#define RTL8367C_REG_Q2_TXPKT_CNT_L 0x0262 + +#define RTL8367C_REG_Q2_TXPKT_CNT_H 0x0263 + +#define RTL8367C_REG_Q3_TXPKT_CNT_L 0x0264 + +#define RTL8367C_REG_Q3_TXPKT_CNT_H 0x0265 + +#define RTL8367C_REG_Q4_TXPKT_CNT_L 0x0266 + +#define RTL8367C_REG_Q4_TXPKT_CNT_H 0x0267 + +#define RTL8367C_REG_Q5_TXPKT_CNT_L 0x0268 + +#define RTL8367C_REG_Q5_TXPKT_CNT_H 0x0269 + +#define RTL8367C_REG_Q6_TXPKT_CNT_L 0x026a + +#define RTL8367C_REG_Q6_TXPKT_CNT_H 0x026b + +#define RTL8367C_REG_Q7_TXPKT_CNT_L 0x026c + +#define RTL8367C_REG_Q7_TXPKT_CNT_H 0x026d + +/* (16'h0300)sch_reg */ + +#define RTL8367C_REG_SCHEDULE_WFQ_CTRL 0x0300 +#define RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET 0 +#define RTL8367C_SCHEDULE_WFQ_CTRL_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_WFQ_BURST_SIZE 0x0301 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL0 0x0302 +#define RTL8367C_PORT1_QUEUE7_TYPE_OFFSET 15 +#define RTL8367C_PORT1_QUEUE7_TYPE_MASK 0x8000 +#define RTL8367C_PORT1_QUEUE6_TYPE_OFFSET 14 +#define RTL8367C_PORT1_QUEUE6_TYPE_MASK 0x4000 +#define RTL8367C_PORT1_QUEUE5_TYPE_OFFSET 13 +#define RTL8367C_PORT1_QUEUE5_TYPE_MASK 0x2000 +#define RTL8367C_PORT1_QUEUE4_TYPE_OFFSET 12 +#define RTL8367C_PORT1_QUEUE4_TYPE_MASK 0x1000 +#define RTL8367C_PORT1_QUEUE3_TYPE_OFFSET 11 +#define RTL8367C_PORT1_QUEUE3_TYPE_MASK 0x800 +#define RTL8367C_PORT1_QUEUE2_TYPE_OFFSET 10 +#define RTL8367C_PORT1_QUEUE2_TYPE_MASK 0x400 +#define RTL8367C_PORT1_QUEUE1_TYPE_OFFSET 9 +#define RTL8367C_PORT1_QUEUE1_TYPE_MASK 0x200 +#define RTL8367C_PORT1_QUEUE0_TYPE_OFFSET 8 +#define RTL8367C_PORT1_QUEUE0_TYPE_MASK 0x100 +#define RTL8367C_PORT0_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT0_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT0_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT0_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT0_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT0_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT0_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT0_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT0_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT0_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT0_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT0_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT0_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT0_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_PORT0_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_PORT0_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL1 0x0303 +#define RTL8367C_PORT3_QUEUE7_TYPE_OFFSET 15 +#define RTL8367C_PORT3_QUEUE7_TYPE_MASK 0x8000 +#define RTL8367C_PORT3_QUEUE6_TYPE_OFFSET 14 +#define RTL8367C_PORT3_QUEUE6_TYPE_MASK 0x4000 +#define RTL8367C_PORT3_QUEUE5_TYPE_OFFSET 13 +#define RTL8367C_PORT3_QUEUE5_TYPE_MASK 0x2000 +#define RTL8367C_PORT3_QUEUE4_TYPE_OFFSET 12 +#define RTL8367C_PORT3_QUEUE4_TYPE_MASK 0x1000 +#define RTL8367C_PORT3_QUEUE3_TYPE_OFFSET 11 +#define RTL8367C_PORT3_QUEUE3_TYPE_MASK 0x800 +#define RTL8367C_PORT3_QUEUE2_TYPE_OFFSET 10 +#define RTL8367C_PORT3_QUEUE2_TYPE_MASK 0x400 +#define RTL8367C_PORT3_QUEUE1_TYPE_OFFSET 9 +#define RTL8367C_PORT3_QUEUE1_TYPE_MASK 0x200 +#define RTL8367C_PORT3_QUEUE0_TYPE_OFFSET 8 +#define RTL8367C_PORT3_QUEUE0_TYPE_MASK 0x100 +#define RTL8367C_PORT2_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT2_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT2_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT2_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT2_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT2_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT2_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT2_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT2_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT2_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT2_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT2_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT2_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT2_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_PORT2_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_PORT2_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL2 0x0304 +#define RTL8367C_PORT5_QUEUE7_TYPE_OFFSET 15 +#define RTL8367C_PORT5_QUEUE7_TYPE_MASK 0x8000 +#define RTL8367C_PORT5_QUEUE6_TYPE_OFFSET 14 +#define RTL8367C_PORT5_QUEUE6_TYPE_MASK 0x4000 +#define RTL8367C_PORT5_QUEUE5_TYPE_OFFSET 13 +#define RTL8367C_PORT5_QUEUE5_TYPE_MASK 0x2000 +#define RTL8367C_PORT5_QUEUE4_TYPE_OFFSET 12 +#define RTL8367C_PORT5_QUEUE4_TYPE_MASK 0x1000 +#define RTL8367C_PORT5_QUEUE3_TYPE_OFFSET 11 +#define RTL8367C_PORT5_QUEUE3_TYPE_MASK 0x800 +#define RTL8367C_PORT5_QUEUE2_TYPE_OFFSET 10 +#define RTL8367C_PORT5_QUEUE2_TYPE_MASK 0x400 +#define RTL8367C_PORT5_QUEUE1_TYPE_OFFSET 9 +#define RTL8367C_PORT5_QUEUE1_TYPE_MASK 0x200 +#define RTL8367C_PORT5_QUEUE0_TYPE_OFFSET 8 +#define RTL8367C_PORT5_QUEUE0_TYPE_MASK 0x100 +#define RTL8367C_PORT4_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT4_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT4_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT4_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT4_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT4_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT4_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT4_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT4_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT4_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT4_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT4_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT4_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT4_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_PORT4_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_PORT4_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL3 0x0305 +#define RTL8367C_PORT7_QUEUE7_TYPE_OFFSET 15 +#define RTL8367C_PORT7_QUEUE7_TYPE_MASK 0x8000 +#define RTL8367C_PORT7_QUEUE6_TYPE_OFFSET 14 +#define RTL8367C_PORT7_QUEUE6_TYPE_MASK 0x4000 +#define RTL8367C_PORT7_QUEUE5_TYPE_OFFSET 13 +#define RTL8367C_PORT7_QUEUE5_TYPE_MASK 0x2000 +#define RTL8367C_PORT7_QUEUE4_TYPE_OFFSET 12 +#define RTL8367C_PORT7_QUEUE4_TYPE_MASK 0x1000 +#define RTL8367C_PORT7_QUEUE3_TYPE_OFFSET 11 +#define RTL8367C_PORT7_QUEUE3_TYPE_MASK 0x800 +#define RTL8367C_PORT7_QUEUE2_TYPE_OFFSET 10 +#define RTL8367C_PORT7_QUEUE2_TYPE_MASK 0x400 +#define RTL8367C_PORT7_QUEUE1_TYPE_OFFSET 9 +#define RTL8367C_PORT7_QUEUE1_TYPE_MASK 0x200 +#define RTL8367C_PORT7_QUEUE0_TYPE_OFFSET 8 +#define RTL8367C_PORT7_QUEUE0_TYPE_MASK 0x100 +#define RTL8367C_PORT6_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT6_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT6_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT6_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT6_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT6_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT6_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT6_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT6_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT6_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT6_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT6_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT6_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT6_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL3_PORT6_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL4 0x0306 +#define RTL8367C_PORT9_QUEUE7_TYPE_OFFSET 15 +#define RTL8367C_PORT9_QUEUE7_TYPE_MASK 0x8000 +#define RTL8367C_PORT9_QUEUE6_TYPE_OFFSET 14 +#define RTL8367C_PORT9_QUEUE6_TYPE_MASK 0x4000 +#define RTL8367C_PORT9_QUEUE5_TYPE_OFFSET 13 +#define RTL8367C_PORT9_QUEUE5_TYPE_MASK 0x2000 +#define RTL8367C_PORT9_QUEUE4_TYPE_OFFSET 12 +#define RTL8367C_PORT9_QUEUE4_TYPE_MASK 0x1000 +#define RTL8367C_PORT9_QUEUE3_TYPE_OFFSET 11 +#define RTL8367C_PORT9_QUEUE3_TYPE_MASK 0x800 +#define RTL8367C_PORT9_QUEUE2_TYPE_OFFSET 10 +#define RTL8367C_PORT9_QUEUE2_TYPE_MASK 0x400 +#define RTL8367C_PORT9_QUEUE1_TYPE_OFFSET 9 +#define RTL8367C_PORT9_QUEUE1_TYPE_MASK 0x200 +#define RTL8367C_PORT9_QUEUE0_TYPE_OFFSET 8 +#define RTL8367C_PORT9_QUEUE0_TYPE_MASK 0x100 +#define RTL8367C_PORT8_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT8_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT8_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT8_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT8_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT8_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT8_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT8_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT8_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT8_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT8_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT8_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT8_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT8_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_SCHEDULE_QUEUE_TYPE_CTRL4_PORT6_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_QUEUE_TYPE_CTRL5 0x0307 +#define RTL8367C_PORT10_QUEUE7_TYPE_OFFSET 7 +#define RTL8367C_PORT10_QUEUE7_TYPE_MASK 0x80 +#define RTL8367C_PORT10_QUEUE6_TYPE_OFFSET 6 +#define RTL8367C_PORT10_QUEUE6_TYPE_MASK 0x40 +#define RTL8367C_PORT10_QUEUE5_TYPE_OFFSET 5 +#define RTL8367C_PORT10_QUEUE5_TYPE_MASK 0x20 +#define RTL8367C_PORT10_QUEUE4_TYPE_OFFSET 4 +#define RTL8367C_PORT10_QUEUE4_TYPE_MASK 0x10 +#define RTL8367C_PORT10_QUEUE3_TYPE_OFFSET 3 +#define RTL8367C_PORT10_QUEUE3_TYPE_MASK 0x8 +#define RTL8367C_PORT10_QUEUE2_TYPE_OFFSET 2 +#define RTL8367C_PORT10_QUEUE2_TYPE_MASK 0x4 +#define RTL8367C_PORT10_QUEUE1_TYPE_OFFSET 1 +#define RTL8367C_PORT10_QUEUE1_TYPE_MASK 0x2 +#define RTL8367C_PORT10_QUEUE0_TYPE_OFFSET 0 +#define RTL8367C_PORT10_QUEUE0_TYPE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_APR_CTRL0 0x030a +#define RTL8367C_PORT10_APR_ENABLE_OFFSET 10 +#define RTL8367C_PORT10_APR_ENABLE_MASK 0x400 +#define RTL8367C_PORT9_APR_ENABLE_OFFSET 9 +#define RTL8367C_PORT9_APR_ENABLE_MASK 0x200 +#define RTL8367C_PORT8_APR_ENABLE_OFFSET 8 +#define RTL8367C_PORT8_APR_ENABLE_MASK 0x100 +#define RTL8367C_PORT7_APR_ENABLE_OFFSET 7 +#define RTL8367C_PORT7_APR_ENABLE_MASK 0x80 +#define RTL8367C_PORT6_APR_ENABLE_OFFSET 6 +#define RTL8367C_PORT6_APR_ENABLE_MASK 0x40 +#define RTL8367C_PORT5_APR_ENABLE_OFFSET 5 +#define RTL8367C_PORT5_APR_ENABLE_MASK 0x20 +#define RTL8367C_PORT4_APR_ENABLE_OFFSET 4 +#define RTL8367C_PORT4_APR_ENABLE_MASK 0x10 +#define RTL8367C_PORT3_APR_ENABLE_OFFSET 3 +#define RTL8367C_PORT3_APR_ENABLE_MASK 0x8 +#define RTL8367C_PORT2_APR_ENABLE_OFFSET 2 +#define RTL8367C_PORT2_APR_ENABLE_MASK 0x4 +#define RTL8367C_PORT1_APR_ENABLE_OFFSET 1 +#define RTL8367C_PORT1_APR_ENABLE_MASK 0x2 +#define RTL8367C_PORT0_APR_ENABLE_OFFSET 0 +#define RTL8367C_PORT0_APR_ENABLE_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE0_WFQ_WEIGHT 0x030c + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT 0x030d +#define RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT 0x030e +#define RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT 0x030f +#define RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT 0x0310 +#define RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT 0x0311 +#define RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT 0x0312 +#define RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT 0x0313 +#define RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE0_WFQ_WEIGHT 0x0314 + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT 0x0315 +#define RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT 0x0316 +#define RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT 0x0317 +#define RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT 0x0318 +#define RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT 0x0319 +#define RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT 0x031a +#define RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT 0x031b +#define RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE0_WFQ_WEIGHT 0x031c + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT 0x031d +#define RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT 0x031e +#define RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT 0x031f +#define RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT 0x0320 +#define RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT 0x0321 +#define RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT 0x0322 +#define RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT 0x0323 +#define RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE0_WFQ_WEIGHT 0x0324 + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT 0x0325 +#define RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT 0x0326 +#define RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT 0x0327 +#define RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT 0x0328 +#define RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT 0x0329 +#define RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT 0x032a +#define RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT 0x032b +#define RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE0_WFQ_WEIGHT 0x032c + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT 0x032d +#define RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT 0x032e +#define RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT 0x032f +#define RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT 0x0330 +#define RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT 0x0331 +#define RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT 0x0332 +#define RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT 0x0333 +#define RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE0_WFQ_WEIGHT 0x0334 + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT 0x0335 +#define RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT 0x0336 +#define RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT 0x0337 +#define RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT 0x0338 +#define RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT 0x0339 +#define RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT 0x033a +#define RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT 0x033b +#define RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE0_WFQ_WEIGHT 0x033c + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT 0x033d +#define RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT 0x033e +#define RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT 0x033f +#define RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT 0x0340 +#define RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT 0x0341 +#define RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT 0x0342 +#define RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT 0x0343 +#define RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE0_WFQ_WEIGHT 0x0344 + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT 0x0345 +#define RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT 0x0346 +#define RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT 0x0347 +#define RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT 0x0348 +#define RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT 0x0349 +#define RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT 0x034a +#define RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT 0x034b +#define RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE0_WFQ_WEIGHT 0x034c + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT 0x034d +#define RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT 0x034e +#define RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT 0x034f +#define RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT 0x0350 +#define RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT 0x0351 +#define RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT 0x0352 +#define RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT 0x0353 +#define RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE0_WFQ_WEIGHT 0x0354 + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT 0x0355 +#define RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT 0x0356 +#define RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT 0x0357 +#define RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT 0x0358 +#define RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT 0x0359 +#define RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT 0x035a +#define RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT 0x035b +#define RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE0_WFQ_WEIGHT 0x035c + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT 0x035d +#define RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE1_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT 0x035e +#define RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE2_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT 0x035f +#define RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE3_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT 0x0360 +#define RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE4_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT 0x0361 +#define RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE5_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT 0x0362 +#define RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE6_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT 0x0363 +#define RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_QUEUE7_WFQ_WEIGHT_MASK 0x7F + +#define RTL8367C_REG_PORT0_EGRESSBW_CTRL0 0x038c + +#define RTL8367C_REG_PORT0_EGRESSBW_CTRL1 0x038d +#define RTL8367C_PORT0_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT0_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT1_EGRESSBW_CTRL0 0x038e + +#define RTL8367C_REG_PORT1_EGRESSBW_CTRL1 0x038f +#define RTL8367C_PORT1_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT1_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT2_EGRESSBW_CTRL0 0x0390 + +#define RTL8367C_REG_PORT2_EGRESSBW_CTRL1 0x0391 +#define RTL8367C_PORT2_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT2_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT3_EGRESSBW_CTRL0 0x0392 + +#define RTL8367C_REG_PORT3_EGRESSBW_CTRL1 0x0393 +#define RTL8367C_PORT3_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT3_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT4_EGRESSBW_CTRL0 0x0394 + +#define RTL8367C_REG_PORT4_EGRESSBW_CTRL1 0x0395 +#define RTL8367C_PORT4_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT4_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT5_EGRESSBW_CTRL0 0x0396 + +#define RTL8367C_REG_PORT5_EGRESSBW_CTRL1 0x0397 +#define RTL8367C_PORT5_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT5_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT6_EGRESSBW_CTRL0 0x0398 + +#define RTL8367C_REG_PORT6_EGRESSBW_CTRL1 0x0399 +#define RTL8367C_PORT6_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT6_EGRESSBW_CTRL1_MASK 0x7 + +#define RTL8367C_REG_PORT7_EGRESSBW_CTRL0 0x039a + +#define RTL8367C_REG_PORT7_EGRESSBW_CTRL1 0x039b +#define RTL8367C_PORT7_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT7_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT8_EGRESSBW_CTRL0 0x039c + +#define RTL8367C_REG_PORT8_EGRESSBW_CTRL1 0x039d +#define RTL8367C_PORT8_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT8_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_PORT9_EGRESSBW_CTRL0 0x039e + +#define RTL8367C_REG_PORT9_EGRESSBW_CTRL1 0x039f +#define RTL8367C_PORT9_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT9_EGRESSBW_CTRL1_MASK 0x7 + +#define RTL8367C_REG_PORT10_EGRESSBW_CTRL0 0x03a0 + +#define RTL8367C_REG_PORT10_EGRESSBW_CTRL1 0x03a1 +#define RTL8367C_PORT10_EGRESSBW_CTRL1_OFFSET 0 +#define RTL8367C_PORT10_EGRESSBW_CTRL1_MASK 0x1 + +#define RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL0 0x03ac +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT0_APR_METER_CTRL1 0x03ad +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT0_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL0 0x03b0 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT1_APR_METER_CTRL1 0x03b1 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT1_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL0 0x03b4 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT2_APR_METER_CTRL1 0x03b5 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT2_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL0 0x03b8 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT3_APR_METER_CTRL1 0x03b9 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT3_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL0 0x03bc +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT4_APR_METER_CTRL1 0x03bd +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT4_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL0 0x03c0 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT5_APR_METER_CTRL1 0x03c1 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT5_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL0 0x03c4 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT6_APR_METER_CTRL1 0x03c5 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT6_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL0 0x03c8 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT7_APR_METER_CTRL1 0x03c9 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT7_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 0x03ca +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL1 0x03cb +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT8_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL0 0x03cc +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT9_APR_METER_CTRL1 0x03cd +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT9_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL0 0x03ce +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_OFFSET 12 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE4_APR_METER_MASK 0x7000 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_OFFSET 9 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE3_APR_METER_MASK 0xE00 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE2_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE1_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL0_QUEUE0_APR_METER_MASK 0x7 + +#define RTL8367C_REG_SCHEDULE_PORT10_APR_METER_CTRL1 0x03cf +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_OFFSET 6 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE7_APR_METER_MASK 0x1C0 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_OFFSET 3 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE6_APR_METER_MASK 0x38 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_OFFSET 0 +#define RTL8367C_SCHEDULE_PORT10_APR_METER_CTRL1_QUEUE5_APR_METER_MASK 0x7 + +#define RTL8367C_REG_LINE_RATE_1G_L 0x03ec + +#define RTL8367C_REG_LINE_RATE_1G_H 0x03ed +#define RTL8367C_LINE_RATE_1G_H_OFFSET 0 +#define RTL8367C_LINE_RATE_1G_H_MASK 0x1 + +#define RTL8367C_REG_LINE_RATE_100_L 0x03ee + +#define RTL8367C_REG_LINE_RATE_100_H 0x03ef +#define RTL8367C_LINE_RATE_100_H_OFFSET 0 +#define RTL8367C_LINE_RATE_100_H_MASK 0x1 + +#define RTL8367C_REG_LINE_RATE_10_L 0x03f0 + +#define RTL8367C_REG_LINE_RATE_10_H 0x03f1 +#define RTL8367C_LINE_RATE_10_H_OFFSET 0 +#define RTL8367C_LINE_RATE_10_H_MASK 0x1 + +#define RTL8367C_REG_DUMMY_03f2 0x03f2 + +#define RTL8367C_REG_DUMMY_03f3 0x03f3 + +#define RTL8367C_REG_DUMMY_03f4 0x03f4 + +#define RTL8367C_REG_DUMMY_03f5 0x03f5 + +#define RTL8367C_REG_DUMMY_03f6 0x03f6 + +#define RTL8367C_REG_BYPASS_LINE_RATE 0x03f7 +#define RTL8367C_BYPASS_PORT10_CONSTRAINT_OFFSET 5 +#define RTL8367C_BYPASS_PORT10_CONSTRAINT_MASK 0x20 +#define RTL8367C_BYPASS_PORT9_CONSTRAINT_OFFSET 4 +#define RTL8367C_BYPASS_PORT9_CONSTRAINT_MASK 0x10 +#define RTL8367C_BYPASS_PORT8_CONSTRAINT_OFFSET 3 +#define RTL8367C_BYPASS_PORT8_CONSTRAINT_MASK 0x8 +#define RTL8367C_BYPASS_PORT7_CONSTRAINT_OFFSET 2 +#define RTL8367C_BYPASS_PORT7_CONSTRAINT_MASK 0x4 +#define RTL8367C_BYPASS_PORT6_CONSTRAINT_OFFSET 1 +#define RTL8367C_BYPASS_PORT6_CONSTRAINT_MASK 0x2 +#define RTL8367C_BYPASS_PORT5_CONSTRAINT_OFFSET 0 +#define RTL8367C_BYPASS_PORT5_CONSTRAINT_MASK 0x1 + +#define RTL8367C_REG_LINE_RATE_500_H 0x03f8 +#define RTL8367C_LINE_RATE_500_H_OFFSET 0 +#define RTL8367C_LINE_RATE_500_H_MASK 0x7 + +#define RTL8367C_REG_LINE_RATE_500_L 0x03f9 + +#define RTL8367C_REG_LINE_RATE_HSG_H 0x03fa +#define RTL8367C_LINE_RATE_HSG_H_OFFSET 0 +#define RTL8367C_LINE_RATE_HSG_H_MASK 0x7 + +#define RTL8367C_REG_LINE_RATE_HSG_L 0x03fb + +/* (16'h0500)table_reg */ + +#define RTL8367C_REG_TABLE_ACCESS_CTRL 0x0500 +#define RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET 8 +#define RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK 0xF00 +#define RTL8367C_ACCESS_METHOD_OFFSET 4 +#define RTL8367C_ACCESS_METHOD_MASK 0x70 +#define RTL8367C_COMMAND_TYPE_OFFSET 3 +#define RTL8367C_COMMAND_TYPE_MASK 0x8 +#define RTL8367C_TABLE_TYPE_OFFSET 0 +#define RTL8367C_TABLE_TYPE_MASK 0x7 + +#define RTL8367C_REG_TABLE_ACCESS_ADDR 0x0501 +#define RTL8367C_TABLE_ACCESS_ADDR_OFFSET 0 +#define RTL8367C_TABLE_ACCESS_ADDR_MASK 0x1FFF + +#define RTL8367C_REG_TABLE_LUT_ADDR 0x0502 +#define RTL8367C_ADDRESS2_OFFSET 14 +#define RTL8367C_ADDRESS2_MASK 0x4000 +#define RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET 13 +#define RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_MASK 0x2000 +#define RTL8367C_HIT_STATUS_OFFSET 12 +#define RTL8367C_HIT_STATUS_MASK 0x1000 +#define RTL8367C_TABLE_LUT_ADDR_TYPE_OFFSET 11 +#define RTL8367C_TABLE_LUT_ADDR_TYPE_MASK 0x800 +#define RTL8367C_TABLE_LUT_ADDR_ADDRESS_OFFSET 0 +#define RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK 0x7FF + +#define RTL8367C_REG_HSA_HSB_LATCH 0x0503 +#define RTL8367C_LATCH_ALWAYS_OFFSET 15 +#define RTL8367C_LATCH_ALWAYS_MASK 0x8000 +#define RTL8367C_LATCH_FIRST_OFFSET 14 +#define RTL8367C_LATCH_FIRST_MASK 0x4000 +#define RTL8367C_SPA_EN_OFFSET 13 +#define RTL8367C_SPA_EN_MASK 0x2000 +#define RTL8367C_FORWARD_EN_OFFSET 12 +#define RTL8367C_FORWARD_EN_MASK 0x1000 +#define RTL8367C_REASON_EN_OFFSET 11 +#define RTL8367C_REASON_EN_MASK 0x800 +#define RTL8367C_HSA_HSB_LATCH_SPA_OFFSET 8 +#define RTL8367C_HSA_HSB_LATCH_SPA_MASK 0x700 +#define RTL8367C_FORWARD_OFFSET 6 +#define RTL8367C_FORWARD_MASK 0xC0 +#define RTL8367C_REASON_OFFSET 0 +#define RTL8367C_REASON_MASK 0x3F + +#define RTL8367C_REG_HSA_HSB_LATCH2 0x0504 +#define RTL8367C_HSA_HSB_LATCH2_Reserved_OFFSET 1 +#define RTL8367C_HSA_HSB_LATCH2_Reserved_MASK 0xFFFE +#define RTL8367C_SPA2_OFFSET 0 +#define RTL8367C_SPA2_MASK 0x1 + +#define RTL8367C_REG_TABLE_WRITE_DATA0 0x0510 + +#define RTL8367C_REG_TABLE_WRITE_DATA1 0x0511 + +#define RTL8367C_REG_TABLE_WRITE_DATA2 0x0512 + +#define RTL8367C_REG_TABLE_WRITE_DATA3 0x0513 + +#define RTL8367C_REG_TABLE_WRITE_DATA4 0x0514 + +#define RTL8367C_REG_TABLE_WRITE_DATA5 0x0515 + +#define RTL8367C_REG_TABLE_WRITE_DATA6 0x0516 + +#define RTL8367C_REG_TABLE_WRITE_DATA7 0x0517 + +#define RTL8367C_REG_TABLE_WRITE_DATA8 0x0518 + +#define RTL8367C_REG_TABLE_WRITE_DATA9 0x0519 +#define RTL8367C_TABLE_WRITE_DATA9_OFFSET 0 +#define RTL8367C_TABLE_WRITE_DATA9_MASK 0xF + +#define RTL8367C_REG_TABLE_READ_DATA0 0x0520 + +#define RTL8367C_REG_TABLE_READ_DATA1 0x0521 + +#define RTL8367C_REG_TABLE_READ_DATA2 0x0522 + +#define RTL8367C_REG_TABLE_READ_DATA3 0x0523 + +#define RTL8367C_REG_TABLE_READ_DATA4 0x0524 + +#define RTL8367C_REG_TABLE_READ_DATA5 0x0525 + +#define RTL8367C_REG_TABLE_READ_DATA6 0x0526 + +#define RTL8367C_REG_TABLE_READ_DATA7 0x0527 + +#define RTL8367C_REG_TABLE_READ_DATA8 0x0528 + +#define RTL8367C_REG_TABLE_READ_DATA9 0x0529 +#define RTL8367C_TABLE_READ_DATA9_OFFSET 0 +#define RTL8367C_TABLE_READ_DATA9_MASK 0xF + +#define RTL8367C_REG_TBL_DUMMY00 0x0550 + +#define RTL8367C_REG_TBL_DUMMY01 0x0551 + +/* (16'h0600)acl_reg */ + +#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL0 0x0600 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD1_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL0_FIELD0_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL1 0x0601 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD3_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL1_FIELD2_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL2 0x0602 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD5_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL2_FIELD4_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE0_CTRL3 0x0603 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD7_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE0_CTRL3_FIELD6_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL0 0x0604 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD1_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL0_FIELD0_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL1 0x0605 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD3_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL1_FIELD2_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL2 0x0606 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD5_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL2_FIELD4_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE1_CTRL3 0x0607 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD7_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE1_CTRL3_FIELD6_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL0 0x0608 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD1_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL0_FIELD0_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL1 0x0609 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD3_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL1_FIELD2_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL2 0x060a +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD5_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL2_FIELD4_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE2_CTRL3 0x060b +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD7_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE2_CTRL3_FIELD6_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL0 0x060c +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD1_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL0_FIELD0_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL1 0x060d +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD3_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL1_FIELD2_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL2 0x060e +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD5_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL2_FIELD4_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE3_CTRL3 0x060f +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD7_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE3_CTRL3_FIELD6_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL0 0x0610 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD1_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL0_FIELD0_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL1 0x0611 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD3_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL1_FIELD2_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL2 0x0612 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD5_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL2_FIELD4_MASK 0x7F + +#define RTL8367C_REG_ACL_RULE_TEMPLATE4_CTRL3 0x0613 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_OFFSET 8 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD7_MASK 0x7F00 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_OFFSET 0 +#define RTL8367C_ACL_RULE_TEMPLATE4_CTRL3_FIELD6_MASK 0x7F + +#define RTL8367C_REG_ACL_ACTION_CTRL0 0x0614 +#define RTL8367C_OP1_NOT_OFFSET 14 +#define RTL8367C_OP1_NOT_MASK 0x4000 +#define RTL8367C_ACT1_GPIO_OFFSET 13 +#define RTL8367C_ACT1_GPIO_MASK 0x2000 +#define RTL8367C_ACT1_FORWARD_OFFSET 12 +#define RTL8367C_ACT1_FORWARD_MASK 0x1000 +#define RTL8367C_ACT1_POLICING_OFFSET 11 +#define RTL8367C_ACT1_POLICING_MASK 0x800 +#define RTL8367C_ACT1_PRIORITY_OFFSET 10 +#define RTL8367C_ACT1_PRIORITY_MASK 0x400 +#define RTL8367C_ACT1_SVID_OFFSET 9 +#define RTL8367C_ACT1_SVID_MASK 0x200 +#define RTL8367C_ACT1_CVID_OFFSET 8 +#define RTL8367C_ACT1_CVID_MASK 0x100 +#define RTL8367C_OP0_NOT_OFFSET 6 +#define RTL8367C_OP0_NOT_MASK 0x40 +#define RTL8367C_ACT0_GPIO_OFFSET 5 +#define RTL8367C_ACT0_GPIO_MASK 0x20 +#define RTL8367C_ACT0_FORWARD_OFFSET 4 +#define RTL8367C_ACT0_FORWARD_MASK 0x10 +#define RTL8367C_ACT0_POLICING_OFFSET 3 +#define RTL8367C_ACT0_POLICING_MASK 0x8 +#define RTL8367C_ACT0_PRIORITY_OFFSET 2 +#define RTL8367C_ACT0_PRIORITY_MASK 0x4 +#define RTL8367C_ACT0_SVID_OFFSET 1 +#define RTL8367C_ACT0_SVID_MASK 0x2 +#define RTL8367C_ACT0_CVID_OFFSET 0 +#define RTL8367C_ACT0_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL1 0x0615 +#define RTL8367C_OP3_NOT_OFFSET 14 +#define RTL8367C_OP3_NOT_MASK 0x4000 +#define RTL8367C_ACT3_GPIO_OFFSET 13 +#define RTL8367C_ACT3_GPIO_MASK 0x2000 +#define RTL8367C_ACT3_FORWARD_OFFSET 12 +#define RTL8367C_ACT3_FORWARD_MASK 0x1000 +#define RTL8367C_ACT3_POLICING_OFFSET 11 +#define RTL8367C_ACT3_POLICING_MASK 0x800 +#define RTL8367C_ACT3_PRIORITY_OFFSET 10 +#define RTL8367C_ACT3_PRIORITY_MASK 0x400 +#define RTL8367C_ACT3_SVID_OFFSET 9 +#define RTL8367C_ACT3_SVID_MASK 0x200 +#define RTL8367C_ACT3_CVID_OFFSET 8 +#define RTL8367C_ACT3_CVID_MASK 0x100 +#define RTL8367C_OP2_NOT_OFFSET 6 +#define RTL8367C_OP2_NOT_MASK 0x40 +#define RTL8367C_ACT2_GPIO_OFFSET 5 +#define RTL8367C_ACT2_GPIO_MASK 0x20 +#define RTL8367C_ACT2_FORWARD_OFFSET 4 +#define RTL8367C_ACT2_FORWARD_MASK 0x10 +#define RTL8367C_ACT2_POLICING_OFFSET 3 +#define RTL8367C_ACT2_POLICING_MASK 0x8 +#define RTL8367C_ACT2_PRIORITY_OFFSET 2 +#define RTL8367C_ACT2_PRIORITY_MASK 0x4 +#define RTL8367C_ACT2_SVID_OFFSET 1 +#define RTL8367C_ACT2_SVID_MASK 0x2 +#define RTL8367C_ACT2_CVID_OFFSET 0 +#define RTL8367C_ACT2_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL2 0x0616 +#define RTL8367C_OP5_NOT_OFFSET 14 +#define RTL8367C_OP5_NOT_MASK 0x4000 +#define RTL8367C_ACT5_GPIO_OFFSET 13 +#define RTL8367C_ACT5_GPIO_MASK 0x2000 +#define RTL8367C_ACT5_FORWARD_OFFSET 12 +#define RTL8367C_ACT5_FORWARD_MASK 0x1000 +#define RTL8367C_ACT5_POLICING_OFFSET 11 +#define RTL8367C_ACT5_POLICING_MASK 0x800 +#define RTL8367C_ACT5_PRIORITY_OFFSET 10 +#define RTL8367C_ACT5_PRIORITY_MASK 0x400 +#define RTL8367C_ACT5_SVID_OFFSET 9 +#define RTL8367C_ACT5_SVID_MASK 0x200 +#define RTL8367C_ACT5_CVID_OFFSET 8 +#define RTL8367C_ACT5_CVID_MASK 0x100 +#define RTL8367C_OP4_NOT_OFFSET 6 +#define RTL8367C_OP4_NOT_MASK 0x40 +#define RTL8367C_ACT4_GPIO_OFFSET 5 +#define RTL8367C_ACT4_GPIO_MASK 0x20 +#define RTL8367C_ACT4_FORWARD_OFFSET 4 +#define RTL8367C_ACT4_FORWARD_MASK 0x10 +#define RTL8367C_ACT4_POLICING_OFFSET 3 +#define RTL8367C_ACT4_POLICING_MASK 0x8 +#define RTL8367C_ACT4_PRIORITY_OFFSET 2 +#define RTL8367C_ACT4_PRIORITY_MASK 0x4 +#define RTL8367C_ACT4_SVID_OFFSET 1 +#define RTL8367C_ACT4_SVID_MASK 0x2 +#define RTL8367C_ACT4_CVID_OFFSET 0 +#define RTL8367C_ACT4_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL3 0x0617 +#define RTL8367C_OP7_NOT_OFFSET 14 +#define RTL8367C_OP7_NOT_MASK 0x4000 +#define RTL8367C_ACT7_GPIO_OFFSET 13 +#define RTL8367C_ACT7_GPIO_MASK 0x2000 +#define RTL8367C_ACT7_FORWARD_OFFSET 12 +#define RTL8367C_ACT7_FORWARD_MASK 0x1000 +#define RTL8367C_ACT7_POLICING_OFFSET 11 +#define RTL8367C_ACT7_POLICING_MASK 0x800 +#define RTL8367C_ACT7_PRIORITY_OFFSET 10 +#define RTL8367C_ACT7_PRIORITY_MASK 0x400 +#define RTL8367C_ACT7_SVID_OFFSET 9 +#define RTL8367C_ACT7_SVID_MASK 0x200 +#define RTL8367C_ACT7_CVID_OFFSET 8 +#define RTL8367C_ACT7_CVID_MASK 0x100 +#define RTL8367C_OP6_NOT_OFFSET 6 +#define RTL8367C_OP6_NOT_MASK 0x40 +#define RTL8367C_ACT6_GPIO_OFFSET 5 +#define RTL8367C_ACT6_GPIO_MASK 0x20 +#define RTL8367C_ACT6_FORWARD_OFFSET 4 +#define RTL8367C_ACT6_FORWARD_MASK 0x10 +#define RTL8367C_ACT6_POLICING_OFFSET 3 +#define RTL8367C_ACT6_POLICING_MASK 0x8 +#define RTL8367C_ACT6_PRIORITY_OFFSET 2 +#define RTL8367C_ACT6_PRIORITY_MASK 0x4 +#define RTL8367C_ACT6_SVID_OFFSET 1 +#define RTL8367C_ACT6_SVID_MASK 0x2 +#define RTL8367C_ACT6_CVID_OFFSET 0 +#define RTL8367C_ACT6_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL4 0x0618 +#define RTL8367C_OP9_NOT_OFFSET 14 +#define RTL8367C_OP9_NOT_MASK 0x4000 +#define RTL8367C_ACT9_GPIO_OFFSET 13 +#define RTL8367C_ACT9_GPIO_MASK 0x2000 +#define RTL8367C_ACT9_FORWARD_OFFSET 12 +#define RTL8367C_ACT9_FORWARD_MASK 0x1000 +#define RTL8367C_ACT9_POLICING_OFFSET 11 +#define RTL8367C_ACT9_POLICING_MASK 0x800 +#define RTL8367C_ACT9_PRIORITY_OFFSET 10 +#define RTL8367C_ACT9_PRIORITY_MASK 0x400 +#define RTL8367C_ACT9_SVID_OFFSET 9 +#define RTL8367C_ACT9_SVID_MASK 0x200 +#define RTL8367C_ACT9_CVID_OFFSET 8 +#define RTL8367C_ACT9_CVID_MASK 0x100 +#define RTL8367C_OP8_NOT_OFFSET 6 +#define RTL8367C_OP8_NOT_MASK 0x40 +#define RTL8367C_ACT8_GPIO_OFFSET 5 +#define RTL8367C_ACT8_GPIO_MASK 0x20 +#define RTL8367C_ACT8_FORWARD_OFFSET 4 +#define RTL8367C_ACT8_FORWARD_MASK 0x10 +#define RTL8367C_ACT8_POLICING_OFFSET 3 +#define RTL8367C_ACT8_POLICING_MASK 0x8 +#define RTL8367C_ACT8_PRIORITY_OFFSET 2 +#define RTL8367C_ACT8_PRIORITY_MASK 0x4 +#define RTL8367C_ACT8_SVID_OFFSET 1 +#define RTL8367C_ACT8_SVID_MASK 0x2 +#define RTL8367C_ACT8_CVID_OFFSET 0 +#define RTL8367C_ACT8_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL5 0x0619 +#define RTL8367C_OP11_NOT_OFFSET 14 +#define RTL8367C_OP11_NOT_MASK 0x4000 +#define RTL8367C_ACT11_GPIO_OFFSET 13 +#define RTL8367C_ACT11_GPIO_MASK 0x2000 +#define RTL8367C_ACT11_FORWARD_OFFSET 12 +#define RTL8367C_ACT11_FORWARD_MASK 0x1000 +#define RTL8367C_ACT11_POLICING_OFFSET 11 +#define RTL8367C_ACT11_POLICING_MASK 0x800 +#define RTL8367C_ACT11_PRIORITY_OFFSET 10 +#define RTL8367C_ACT11_PRIORITY_MASK 0x400 +#define RTL8367C_ACT11_SVID_OFFSET 9 +#define RTL8367C_ACT11_SVID_MASK 0x200 +#define RTL8367C_ACT11_CVID_OFFSET 8 +#define RTL8367C_ACT11_CVID_MASK 0x100 +#define RTL8367C_OP10_NOT_OFFSET 6 +#define RTL8367C_OP10_NOT_MASK 0x40 +#define RTL8367C_ACT10_GPIO_OFFSET 5 +#define RTL8367C_ACT10_GPIO_MASK 0x20 +#define RTL8367C_ACT10_FORWARD_OFFSET 4 +#define RTL8367C_ACT10_FORWARD_MASK 0x10 +#define RTL8367C_ACT10_POLICING_OFFSET 3 +#define RTL8367C_ACT10_POLICING_MASK 0x8 +#define RTL8367C_ACT10_PRIORITY_OFFSET 2 +#define RTL8367C_ACT10_PRIORITY_MASK 0x4 +#define RTL8367C_ACT10_SVID_OFFSET 1 +#define RTL8367C_ACT10_SVID_MASK 0x2 +#define RTL8367C_ACT10_CVID_OFFSET 0 +#define RTL8367C_ACT10_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL6 0x061a +#define RTL8367C_OP13_NOT_OFFSET 14 +#define RTL8367C_OP13_NOT_MASK 0x4000 +#define RTL8367C_ACT13_GPIO_OFFSET 13 +#define RTL8367C_ACT13_GPIO_MASK 0x2000 +#define RTL8367C_ACT13_FORWARD_OFFSET 12 +#define RTL8367C_ACT13_FORWARD_MASK 0x1000 +#define RTL8367C_ACT13_POLICING_OFFSET 11 +#define RTL8367C_ACT13_POLICING_MASK 0x800 +#define RTL8367C_ACT13_PRIORITY_OFFSET 10 +#define RTL8367C_ACT13_PRIORITY_MASK 0x400 +#define RTL8367C_ACT13_SVID_OFFSET 9 +#define RTL8367C_ACT13_SVID_MASK 0x200 +#define RTL8367C_ACT13_CVID_OFFSET 8 +#define RTL8367C_ACT13_CVID_MASK 0x100 +#define RTL8367C_OP12_NOT_OFFSET 6 +#define RTL8367C_OP12_NOT_MASK 0x40 +#define RTL8367C_ACT12_GPIO_OFFSET 5 +#define RTL8367C_ACT12_GPIO_MASK 0x20 +#define RTL8367C_ACT12_FORWARD_OFFSET 4 +#define RTL8367C_ACT12_FORWARD_MASK 0x10 +#define RTL8367C_ACT12_POLICING_OFFSET 3 +#define RTL8367C_ACT12_POLICING_MASK 0x8 +#define RTL8367C_ACT12_PRIORITY_OFFSET 2 +#define RTL8367C_ACT12_PRIORITY_MASK 0x4 +#define RTL8367C_ACT12_SVID_OFFSET 1 +#define RTL8367C_ACT12_SVID_MASK 0x2 +#define RTL8367C_ACT12_CVID_OFFSET 0 +#define RTL8367C_ACT12_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL7 0x061b +#define RTL8367C_OP15_NOT_OFFSET 14 +#define RTL8367C_OP15_NOT_MASK 0x4000 +#define RTL8367C_ACT15_GPIO_OFFSET 13 +#define RTL8367C_ACT15_GPIO_MASK 0x2000 +#define RTL8367C_ACT15_FORWARD_OFFSET 12 +#define RTL8367C_ACT15_FORWARD_MASK 0x1000 +#define RTL8367C_ACT15_POLICING_OFFSET 11 +#define RTL8367C_ACT15_POLICING_MASK 0x800 +#define RTL8367C_ACT15_PRIORITY_OFFSET 10 +#define RTL8367C_ACT15_PRIORITY_MASK 0x400 +#define RTL8367C_ACT15_SVID_OFFSET 9 +#define RTL8367C_ACT15_SVID_MASK 0x200 +#define RTL8367C_ACT15_CVID_OFFSET 8 +#define RTL8367C_ACT15_CVID_MASK 0x100 +#define RTL8367C_OP14_NOT_OFFSET 6 +#define RTL8367C_OP14_NOT_MASK 0x40 +#define RTL8367C_ACT14_GPIO_OFFSET 5 +#define RTL8367C_ACT14_GPIO_MASK 0x20 +#define RTL8367C_ACT14_FORWARD_OFFSET 4 +#define RTL8367C_ACT14_FORWARD_MASK 0x10 +#define RTL8367C_ACT14_POLICING_OFFSET 3 +#define RTL8367C_ACT14_POLICING_MASK 0x8 +#define RTL8367C_ACT14_PRIORITY_OFFSET 2 +#define RTL8367C_ACT14_PRIORITY_MASK 0x4 +#define RTL8367C_ACT14_SVID_OFFSET 1 +#define RTL8367C_ACT14_SVID_MASK 0x2 +#define RTL8367C_ACT14_CVID_OFFSET 0 +#define RTL8367C_ACT14_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL8 0x061c +#define RTL8367C_OP17_NOT_OFFSET 14 +#define RTL8367C_OP17_NOT_MASK 0x4000 +#define RTL8367C_ACT17_GPIO_OFFSET 13 +#define RTL8367C_ACT17_GPIO_MASK 0x2000 +#define RTL8367C_ACT17_FORWARD_OFFSET 12 +#define RTL8367C_ACT17_FORWARD_MASK 0x1000 +#define RTL8367C_ACT17_POLICING_OFFSET 11 +#define RTL8367C_ACT17_POLICING_MASK 0x800 +#define RTL8367C_ACT17_PRIORITY_OFFSET 10 +#define RTL8367C_ACT17_PRIORITY_MASK 0x400 +#define RTL8367C_ACT17_SVID_OFFSET 9 +#define RTL8367C_ACT17_SVID_MASK 0x200 +#define RTL8367C_ACT17_CVID_OFFSET 8 +#define RTL8367C_ACT17_CVID_MASK 0x100 +#define RTL8367C_OP16_NOT_OFFSET 6 +#define RTL8367C_OP16_NOT_MASK 0x40 +#define RTL8367C_ACT16_GPIO_OFFSET 5 +#define RTL8367C_ACT16_GPIO_MASK 0x20 +#define RTL8367C_ACT16_FORWARD_OFFSET 4 +#define RTL8367C_ACT16_FORWARD_MASK 0x10 +#define RTL8367C_ACT16_POLICING_OFFSET 3 +#define RTL8367C_ACT16_POLICING_MASK 0x8 +#define RTL8367C_ACT16_PRIORITY_OFFSET 2 +#define RTL8367C_ACT16_PRIORITY_MASK 0x4 +#define RTL8367C_ACT16_SVID_OFFSET 1 +#define RTL8367C_ACT16_SVID_MASK 0x2 +#define RTL8367C_ACT16_CVID_OFFSET 0 +#define RTL8367C_ACT16_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL9 0x061d +#define RTL8367C_OP19_NOT_OFFSET 14 +#define RTL8367C_OP19_NOT_MASK 0x4000 +#define RTL8367C_ACT19_GPIO_OFFSET 13 +#define RTL8367C_ACT19_GPIO_MASK 0x2000 +#define RTL8367C_ACT19_FORWARD_OFFSET 12 +#define RTL8367C_ACT19_FORWARD_MASK 0x1000 +#define RTL8367C_ACT19_POLICING_OFFSET 11 +#define RTL8367C_ACT19_POLICING_MASK 0x800 +#define RTL8367C_ACT19_PRIORITY_OFFSET 10 +#define RTL8367C_ACT19_PRIORITY_MASK 0x400 +#define RTL8367C_ACT19_SVID_OFFSET 9 +#define RTL8367C_ACT19_SVID_MASK 0x200 +#define RTL8367C_ACT19_CVID_OFFSET 8 +#define RTL8367C_ACT19_CVID_MASK 0x100 +#define RTL8367C_OP18_NOT_OFFSET 6 +#define RTL8367C_OP18_NOT_MASK 0x40 +#define RTL8367C_ACT18_GPIO_OFFSET 5 +#define RTL8367C_ACT18_GPIO_MASK 0x20 +#define RTL8367C_ACT18_FORWARD_OFFSET 4 +#define RTL8367C_ACT18_FORWARD_MASK 0x10 +#define RTL8367C_ACT18_POLICING_OFFSET 3 +#define RTL8367C_ACT18_POLICING_MASK 0x8 +#define RTL8367C_ACT18_PRIORITY_OFFSET 2 +#define RTL8367C_ACT18_PRIORITY_MASK 0x4 +#define RTL8367C_ACT18_SVID_OFFSET 1 +#define RTL8367C_ACT18_SVID_MASK 0x2 +#define RTL8367C_ACT18_CVID_OFFSET 0 +#define RTL8367C_ACT18_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL10 0x061e +#define RTL8367C_OP21_NOT_OFFSET 14 +#define RTL8367C_OP21_NOT_MASK 0x4000 +#define RTL8367C_ACT21_GPIO_OFFSET 13 +#define RTL8367C_ACT21_GPIO_MASK 0x2000 +#define RTL8367C_ACT21_FORWARD_OFFSET 12 +#define RTL8367C_ACT21_FORWARD_MASK 0x1000 +#define RTL8367C_ACT21_POLICING_OFFSET 11 +#define RTL8367C_ACT21_POLICING_MASK 0x800 +#define RTL8367C_ACT21_PRIORITY_OFFSET 10 +#define RTL8367C_ACT21_PRIORITY_MASK 0x400 +#define RTL8367C_ACT21_SVID_OFFSET 9 +#define RTL8367C_ACT21_SVID_MASK 0x200 +#define RTL8367C_ACT21_CVID_OFFSET 8 +#define RTL8367C_ACT21_CVID_MASK 0x100 +#define RTL8367C_OP20_NOT_OFFSET 6 +#define RTL8367C_OP20_NOT_MASK 0x40 +#define RTL8367C_ACT20_GPIO_OFFSET 5 +#define RTL8367C_ACT20_GPIO_MASK 0x20 +#define RTL8367C_ACT20_FORWARD_OFFSET 4 +#define RTL8367C_ACT20_FORWARD_MASK 0x10 +#define RTL8367C_ACT20_POLICING_OFFSET 3 +#define RTL8367C_ACT20_POLICING_MASK 0x8 +#define RTL8367C_ACT20_PRIORITY_OFFSET 2 +#define RTL8367C_ACT20_PRIORITY_MASK 0x4 +#define RTL8367C_ACT20_SVID_OFFSET 1 +#define RTL8367C_ACT20_SVID_MASK 0x2 +#define RTL8367C_ACT20_CVID_OFFSET 0 +#define RTL8367C_ACT20_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL11 0x061f +#define RTL8367C_OP23_NOT_OFFSET 14 +#define RTL8367C_OP23_NOT_MASK 0x4000 +#define RTL8367C_ACT23_GPIO_OFFSET 13 +#define RTL8367C_ACT23_GPIO_MASK 0x2000 +#define RTL8367C_ACT23_FORWARD_OFFSET 12 +#define RTL8367C_ACT23_FORWARD_MASK 0x1000 +#define RTL8367C_ACT23_POLICING_OFFSET 11 +#define RTL8367C_ACT23_POLICING_MASK 0x800 +#define RTL8367C_ACT23_PRIORITY_OFFSET 10 +#define RTL8367C_ACT23_PRIORITY_MASK 0x400 +#define RTL8367C_ACT23_SVID_OFFSET 9 +#define RTL8367C_ACT23_SVID_MASK 0x200 +#define RTL8367C_ACT23_CVID_OFFSET 8 +#define RTL8367C_ACT23_CVID_MASK 0x100 +#define RTL8367C_OP22_NOT_OFFSET 6 +#define RTL8367C_OP22_NOT_MASK 0x40 +#define RTL8367C_ACT22_GPIO_OFFSET 5 +#define RTL8367C_ACT22_GPIO_MASK 0x20 +#define RTL8367C_ACT22_FORWARD_OFFSET 4 +#define RTL8367C_ACT22_FORWARD_MASK 0x10 +#define RTL8367C_ACT22_POLICING_OFFSET 3 +#define RTL8367C_ACT22_POLICING_MASK 0x8 +#define RTL8367C_ACT22_PRIORITY_OFFSET 2 +#define RTL8367C_ACT22_PRIORITY_MASK 0x4 +#define RTL8367C_ACT22_SVID_OFFSET 1 +#define RTL8367C_ACT22_SVID_MASK 0x2 +#define RTL8367C_ACT22_CVID_OFFSET 0 +#define RTL8367C_ACT22_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL12 0x0620 +#define RTL8367C_OP25_NOT_OFFSET 14 +#define RTL8367C_OP25_NOT_MASK 0x4000 +#define RTL8367C_ACT25_GPIO_OFFSET 13 +#define RTL8367C_ACT25_GPIO_MASK 0x2000 +#define RTL8367C_ACT25_FORWARD_OFFSET 12 +#define RTL8367C_ACT25_FORWARD_MASK 0x1000 +#define RTL8367C_ACT25_POLICING_OFFSET 11 +#define RTL8367C_ACT25_POLICING_MASK 0x800 +#define RTL8367C_ACT25_PRIORITY_OFFSET 10 +#define RTL8367C_ACT25_PRIORITY_MASK 0x400 +#define RTL8367C_ACT25_SVID_OFFSET 9 +#define RTL8367C_ACT25_SVID_MASK 0x200 +#define RTL8367C_ACT25_CVID_OFFSET 8 +#define RTL8367C_ACT25_CVID_MASK 0x100 +#define RTL8367C_OP24_NOT_OFFSET 6 +#define RTL8367C_OP24_NOT_MASK 0x40 +#define RTL8367C_ACT24_GPIO_OFFSET 5 +#define RTL8367C_ACT24_GPIO_MASK 0x20 +#define RTL8367C_ACT24_FORWARD_OFFSET 4 +#define RTL8367C_ACT24_FORWARD_MASK 0x10 +#define RTL8367C_ACT24_POLICING_OFFSET 3 +#define RTL8367C_ACT24_POLICING_MASK 0x8 +#define RTL8367C_ACT24_PRIORITY_OFFSET 2 +#define RTL8367C_ACT24_PRIORITY_MASK 0x4 +#define RTL8367C_ACT24_SVID_OFFSET 1 +#define RTL8367C_ACT24_SVID_MASK 0x2 +#define RTL8367C_ACT24_CVID_OFFSET 0 +#define RTL8367C_ACT24_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL13 0x0621 +#define RTL8367C_OP27_NOT_OFFSET 14 +#define RTL8367C_OP27_NOT_MASK 0x4000 +#define RTL8367C_ACT27_GPIO_OFFSET 13 +#define RTL8367C_ACT27_GPIO_MASK 0x2000 +#define RTL8367C_ACT27_FORWARD_OFFSET 12 +#define RTL8367C_ACT27_FORWARD_MASK 0x1000 +#define RTL8367C_ACT27_POLICING_OFFSET 11 +#define RTL8367C_ACT27_POLICING_MASK 0x800 +#define RTL8367C_ACT27_PRIORITY_OFFSET 10 +#define RTL8367C_ACT27_PRIORITY_MASK 0x400 +#define RTL8367C_ACT27_SVID_OFFSET 9 +#define RTL8367C_ACT27_SVID_MASK 0x200 +#define RTL8367C_ACT27_CVID_OFFSET 8 +#define RTL8367C_ACT27_CVID_MASK 0x100 +#define RTL8367C_OP26_NOT_OFFSET 6 +#define RTL8367C_OP26_NOT_MASK 0x40 +#define RTL8367C_ACT26_GPIO_OFFSET 5 +#define RTL8367C_ACT26_GPIO_MASK 0x20 +#define RTL8367C_ACT26_FORWARD_OFFSET 4 +#define RTL8367C_ACT26_FORWARD_MASK 0x10 +#define RTL8367C_ACT26_POLICING_OFFSET 3 +#define RTL8367C_ACT26_POLICING_MASK 0x8 +#define RTL8367C_ACT26_PRIORITY_OFFSET 2 +#define RTL8367C_ACT26_PRIORITY_MASK 0x4 +#define RTL8367C_ACT26_SVID_OFFSET 1 +#define RTL8367C_ACT26_SVID_MASK 0x2 +#define RTL8367C_ACT26_CVID_OFFSET 0 +#define RTL8367C_ACT26_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL14 0x0622 +#define RTL8367C_OP29_NOT_OFFSET 14 +#define RTL8367C_OP29_NOT_MASK 0x4000 +#define RTL8367C_ACT29_GPIO_OFFSET 13 +#define RTL8367C_ACT29_GPIO_MASK 0x2000 +#define RTL8367C_ACT29_FORWARD_OFFSET 12 +#define RTL8367C_ACT29_FORWARD_MASK 0x1000 +#define RTL8367C_ACT29_POLICING_OFFSET 11 +#define RTL8367C_ACT29_POLICING_MASK 0x800 +#define RTL8367C_ACT29_PRIORITY_OFFSET 10 +#define RTL8367C_ACT29_PRIORITY_MASK 0x400 +#define RTL8367C_ACT29_SVID_OFFSET 9 +#define RTL8367C_ACT29_SVID_MASK 0x200 +#define RTL8367C_ACT29_CVID_OFFSET 8 +#define RTL8367C_ACT29_CVID_MASK 0x100 +#define RTL8367C_OP28_NOT_OFFSET 6 +#define RTL8367C_OP28_NOT_MASK 0x40 +#define RTL8367C_ACT28_GPIO_OFFSET 5 +#define RTL8367C_ACT28_GPIO_MASK 0x20 +#define RTL8367C_ACT28_FORWARD_OFFSET 4 +#define RTL8367C_ACT28_FORWARD_MASK 0x10 +#define RTL8367C_ACT28_POLICING_OFFSET 3 +#define RTL8367C_ACT28_POLICING_MASK 0x8 +#define RTL8367C_ACT28_PRIORITY_OFFSET 2 +#define RTL8367C_ACT28_PRIORITY_MASK 0x4 +#define RTL8367C_ACT28_SVID_OFFSET 1 +#define RTL8367C_ACT28_SVID_MASK 0x2 +#define RTL8367C_ACT28_CVID_OFFSET 0 +#define RTL8367C_ACT28_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL15 0x0623 +#define RTL8367C_OP31_NOT_OFFSET 14 +#define RTL8367C_OP31_NOT_MASK 0x4000 +#define RTL8367C_ACT31_GPIO_OFFSET 13 +#define RTL8367C_ACT31_GPIO_MASK 0x2000 +#define RTL8367C_ACT31_FORWARD_OFFSET 12 +#define RTL8367C_ACT31_FORWARD_MASK 0x1000 +#define RTL8367C_ACT31_POLICING_OFFSET 11 +#define RTL8367C_ACT31_POLICING_MASK 0x800 +#define RTL8367C_ACT31_PRIORITY_OFFSET 10 +#define RTL8367C_ACT31_PRIORITY_MASK 0x400 +#define RTL8367C_ACT31_SVID_OFFSET 9 +#define RTL8367C_ACT31_SVID_MASK 0x200 +#define RTL8367C_ACT31_CVID_OFFSET 8 +#define RTL8367C_ACT31_CVID_MASK 0x100 +#define RTL8367C_OP30_NOT_OFFSET 6 +#define RTL8367C_OP30_NOT_MASK 0x40 +#define RTL8367C_ACT30_GPIO_OFFSET 5 +#define RTL8367C_ACT30_GPIO_MASK 0x20 +#define RTL8367C_ACT30_FORWARD_OFFSET 4 +#define RTL8367C_ACT30_FORWARD_MASK 0x10 +#define RTL8367C_ACT30_POLICING_OFFSET 3 +#define RTL8367C_ACT30_POLICING_MASK 0x8 +#define RTL8367C_ACT30_PRIORITY_OFFSET 2 +#define RTL8367C_ACT30_PRIORITY_MASK 0x4 +#define RTL8367C_ACT30_SVID_OFFSET 1 +#define RTL8367C_ACT30_SVID_MASK 0x2 +#define RTL8367C_ACT30_CVID_OFFSET 0 +#define RTL8367C_ACT30_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL16 0x0624 +#define RTL8367C_OP33_NOT_OFFSET 14 +#define RTL8367C_OP33_NOT_MASK 0x4000 +#define RTL8367C_ACT33_GPIO_OFFSET 13 +#define RTL8367C_ACT33_GPIO_MASK 0x2000 +#define RTL8367C_ACT33_FORWARD_OFFSET 12 +#define RTL8367C_ACT33_FORWARD_MASK 0x1000 +#define RTL8367C_ACT33_POLICING_OFFSET 11 +#define RTL8367C_ACT33_POLICING_MASK 0x800 +#define RTL8367C_ACT33_PRIORITY_OFFSET 10 +#define RTL8367C_ACT33_PRIORITY_MASK 0x400 +#define RTL8367C_ACT33_SVID_OFFSET 9 +#define RTL8367C_ACT33_SVID_MASK 0x200 +#define RTL8367C_ACT33_CVID_OFFSET 8 +#define RTL8367C_ACT33_CVID_MASK 0x100 +#define RTL8367C_OP32_NOT_OFFSET 6 +#define RTL8367C_OP32_NOT_MASK 0x40 +#define RTL8367C_ACT32_GPIO_OFFSET 5 +#define RTL8367C_ACT32_GPIO_MASK 0x20 +#define RTL8367C_ACT32_FORWARD_OFFSET 4 +#define RTL8367C_ACT32_FORWARD_MASK 0x10 +#define RTL8367C_ACT32_POLICING_OFFSET 3 +#define RTL8367C_ACT32_POLICING_MASK 0x8 +#define RTL8367C_ACT32_PRIORITY_OFFSET 2 +#define RTL8367C_ACT32_PRIORITY_MASK 0x4 +#define RTL8367C_ACT32_SVID_OFFSET 1 +#define RTL8367C_ACT32_SVID_MASK 0x2 +#define RTL8367C_ACT32_CVID_OFFSET 0 +#define RTL8367C_ACT32_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL17 0x0625 +#define RTL8367C_OP35_NOT_OFFSET 14 +#define RTL8367C_OP35_NOT_MASK 0x4000 +#define RTL8367C_ACT35_GPIO_OFFSET 13 +#define RTL8367C_ACT35_GPIO_MASK 0x2000 +#define RTL8367C_ACT35_FORWARD_OFFSET 12 +#define RTL8367C_ACT35_FORWARD_MASK 0x1000 +#define RTL8367C_ACT35_POLICING_OFFSET 11 +#define RTL8367C_ACT35_POLICING_MASK 0x800 +#define RTL8367C_ACT35_PRIORITY_OFFSET 10 +#define RTL8367C_ACT35_PRIORITY_MASK 0x400 +#define RTL8367C_ACT35_SVID_OFFSET 9 +#define RTL8367C_ACT35_SVID_MASK 0x200 +#define RTL8367C_ACT35_CVID_OFFSET 8 +#define RTL8367C_ACT35_CVID_MASK 0x100 +#define RTL8367C_OP34_NOT_OFFSET 6 +#define RTL8367C_OP34_NOT_MASK 0x40 +#define RTL8367C_ACT34_GPIO_OFFSET 5 +#define RTL8367C_ACT34_GPIO_MASK 0x20 +#define RTL8367C_ACT34_FORWARD_OFFSET 4 +#define RTL8367C_ACT34_FORWARD_MASK 0x10 +#define RTL8367C_ACT34_POLICING_OFFSET 3 +#define RTL8367C_ACT34_POLICING_MASK 0x8 +#define RTL8367C_ACT34_PRIORITY_OFFSET 2 +#define RTL8367C_ACT34_PRIORITY_MASK 0x4 +#define RTL8367C_ACT34_SVID_OFFSET 1 +#define RTL8367C_ACT34_SVID_MASK 0x2 +#define RTL8367C_ACT34_CVID_OFFSET 0 +#define RTL8367C_ACT34_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL18 0x0626 +#define RTL8367C_OP37_NOT_OFFSET 14 +#define RTL8367C_OP37_NOT_MASK 0x4000 +#define RTL8367C_ACT37_GPIO_OFFSET 13 +#define RTL8367C_ACT37_GPIO_MASK 0x2000 +#define RTL8367C_ACT37_FORWARD_OFFSET 12 +#define RTL8367C_ACT37_FORWARD_MASK 0x1000 +#define RTL8367C_ACT37_POLICING_OFFSET 11 +#define RTL8367C_ACT37_POLICING_MASK 0x800 +#define RTL8367C_ACT37_PRIORITY_OFFSET 10 +#define RTL8367C_ACT37_PRIORITY_MASK 0x400 +#define RTL8367C_ACT37_SVID_OFFSET 9 +#define RTL8367C_ACT37_SVID_MASK 0x200 +#define RTL8367C_ACT37_CVID_OFFSET 8 +#define RTL8367C_ACT37_CVID_MASK 0x100 +#define RTL8367C_OP36_NOT_OFFSET 6 +#define RTL8367C_OP36_NOT_MASK 0x40 +#define RTL8367C_ACT36_GPIO_OFFSET 5 +#define RTL8367C_ACT36_GPIO_MASK 0x20 +#define RTL8367C_ACT36_FORWARD_OFFSET 4 +#define RTL8367C_ACT36_FORWARD_MASK 0x10 +#define RTL8367C_ACT36_POLICING_OFFSET 3 +#define RTL8367C_ACT36_POLICING_MASK 0x8 +#define RTL8367C_ACT36_PRIORITY_OFFSET 2 +#define RTL8367C_ACT36_PRIORITY_MASK 0x4 +#define RTL8367C_ACT36_SVID_OFFSET 1 +#define RTL8367C_ACT36_SVID_MASK 0x2 +#define RTL8367C_ACT36_CVID_OFFSET 0 +#define RTL8367C_ACT36_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL19 0x0627 +#define RTL8367C_OP39_NOT_OFFSET 14 +#define RTL8367C_OP39_NOT_MASK 0x4000 +#define RTL8367C_ACT39_GPIO_OFFSET 13 +#define RTL8367C_ACT39_GPIO_MASK 0x2000 +#define RTL8367C_ACT39_FORWARD_OFFSET 12 +#define RTL8367C_ACT39_FORWARD_MASK 0x1000 +#define RTL8367C_ACT39_POLICING_OFFSET 11 +#define RTL8367C_ACT39_POLICING_MASK 0x800 +#define RTL8367C_ACT39_PRIORITY_OFFSET 10 +#define RTL8367C_ACT39_PRIORITY_MASK 0x400 +#define RTL8367C_ACT39_SVID_OFFSET 9 +#define RTL8367C_ACT39_SVID_MASK 0x200 +#define RTL8367C_ACT39_CVID_OFFSET 8 +#define RTL8367C_ACT39_CVID_MASK 0x100 +#define RTL8367C_OP38_NOT_OFFSET 6 +#define RTL8367C_OP38_NOT_MASK 0x40 +#define RTL8367C_ACT38_GPIO_OFFSET 5 +#define RTL8367C_ACT38_GPIO_MASK 0x20 +#define RTL8367C_ACT38_FORWARD_OFFSET 4 +#define RTL8367C_ACT38_FORWARD_MASK 0x10 +#define RTL8367C_ACT38_POLICING_OFFSET 3 +#define RTL8367C_ACT38_POLICING_MASK 0x8 +#define RTL8367C_ACT38_PRIORITY_OFFSET 2 +#define RTL8367C_ACT38_PRIORITY_MASK 0x4 +#define RTL8367C_ACT38_SVID_OFFSET 1 +#define RTL8367C_ACT38_SVID_MASK 0x2 +#define RTL8367C_ACT38_CVID_OFFSET 0 +#define RTL8367C_ACT38_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL20 0x0628 +#define RTL8367C_OP41_NOT_OFFSET 14 +#define RTL8367C_OP41_NOT_MASK 0x4000 +#define RTL8367C_ACT41_GPIO_OFFSET 13 +#define RTL8367C_ACT41_GPIO_MASK 0x2000 +#define RTL8367C_ACT41_FORWARD_OFFSET 12 +#define RTL8367C_ACT41_FORWARD_MASK 0x1000 +#define RTL8367C_ACT41_POLICING_OFFSET 11 +#define RTL8367C_ACT41_POLICING_MASK 0x800 +#define RTL8367C_ACT41_PRIORITY_OFFSET 10 +#define RTL8367C_ACT41_PRIORITY_MASK 0x400 +#define RTL8367C_ACT41_SVID_OFFSET 9 +#define RTL8367C_ACT41_SVID_MASK 0x200 +#define RTL8367C_ACT41_CVID_OFFSET 8 +#define RTL8367C_ACT41_CVID_MASK 0x100 +#define RTL8367C_OP40_NOT_OFFSET 6 +#define RTL8367C_OP40_NOT_MASK 0x40 +#define RTL8367C_ACT40_GPIO_OFFSET 5 +#define RTL8367C_ACT40_GPIO_MASK 0x20 +#define RTL8367C_ACT40_FORWARD_OFFSET 4 +#define RTL8367C_ACT40_FORWARD_MASK 0x10 +#define RTL8367C_ACT40_POLICING_OFFSET 3 +#define RTL8367C_ACT40_POLICING_MASK 0x8 +#define RTL8367C_ACT40_PRIORITY_OFFSET 2 +#define RTL8367C_ACT40_PRIORITY_MASK 0x4 +#define RTL8367C_ACT40_SVID_OFFSET 1 +#define RTL8367C_ACT40_SVID_MASK 0x2 +#define RTL8367C_ACT40_CVID_OFFSET 0 +#define RTL8367C_ACT40_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL21 0x0629 +#define RTL8367C_OP43_NOT_OFFSET 14 +#define RTL8367C_OP43_NOT_MASK 0x4000 +#define RTL8367C_ACT43_GPIO_OFFSET 13 +#define RTL8367C_ACT43_GPIO_MASK 0x2000 +#define RTL8367C_ACT43_FORWARD_OFFSET 12 +#define RTL8367C_ACT43_FORWARD_MASK 0x1000 +#define RTL8367C_ACT43_POLICING_OFFSET 11 +#define RTL8367C_ACT43_POLICING_MASK 0x800 +#define RTL8367C_ACT43_PRIORITY_OFFSET 10 +#define RTL8367C_ACT43_PRIORITY_MASK 0x400 +#define RTL8367C_ACT43_SVID_OFFSET 9 +#define RTL8367C_ACT43_SVID_MASK 0x200 +#define RTL8367C_ACT43_CVID_OFFSET 8 +#define RTL8367C_ACT43_CVID_MASK 0x100 +#define RTL8367C_OP42_NOT_OFFSET 6 +#define RTL8367C_OP42_NOT_MASK 0x40 +#define RTL8367C_ACT42_GPIO_OFFSET 5 +#define RTL8367C_ACT42_GPIO_MASK 0x20 +#define RTL8367C_ACT42_FORWARD_OFFSET 4 +#define RTL8367C_ACT42_FORWARD_MASK 0x10 +#define RTL8367C_ACT42_POLICING_OFFSET 3 +#define RTL8367C_ACT42_POLICING_MASK 0x8 +#define RTL8367C_ACT42_PRIORITY_OFFSET 2 +#define RTL8367C_ACT42_PRIORITY_MASK 0x4 +#define RTL8367C_ACT42_SVID_OFFSET 1 +#define RTL8367C_ACT42_SVID_MASK 0x2 +#define RTL8367C_ACT42_CVID_OFFSET 0 +#define RTL8367C_ACT42_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL22 0x062a +#define RTL8367C_OP45_NOT_OFFSET 14 +#define RTL8367C_OP45_NOT_MASK 0x4000 +#define RTL8367C_ACT45_GPIO_OFFSET 13 +#define RTL8367C_ACT45_GPIO_MASK 0x2000 +#define RTL8367C_ACT45_FORWARD_OFFSET 12 +#define RTL8367C_ACT45_FORWARD_MASK 0x1000 +#define RTL8367C_ACT45_POLICING_OFFSET 11 +#define RTL8367C_ACT45_POLICING_MASK 0x800 +#define RTL8367C_ACT45_PRIORITY_OFFSET 10 +#define RTL8367C_ACT45_PRIORITY_MASK 0x400 +#define RTL8367C_ACT45_SVID_OFFSET 9 +#define RTL8367C_ACT45_SVID_MASK 0x200 +#define RTL8367C_ACT45_CVID_OFFSET 8 +#define RTL8367C_ACT45_CVID_MASK 0x100 +#define RTL8367C_OP44_NOT_OFFSET 6 +#define RTL8367C_OP44_NOT_MASK 0x40 +#define RTL8367C_ACT44_GPIO_OFFSET 5 +#define RTL8367C_ACT44_GPIO_MASK 0x20 +#define RTL8367C_ACT44_FORWARD_OFFSET 4 +#define RTL8367C_ACT44_FORWARD_MASK 0x10 +#define RTL8367C_ACT44_POLICING_OFFSET 3 +#define RTL8367C_ACT44_POLICING_MASK 0x8 +#define RTL8367C_ACT44_PRIORITY_OFFSET 2 +#define RTL8367C_ACT44_PRIORITY_MASK 0x4 +#define RTL8367C_ACT44_SVID_OFFSET 1 +#define RTL8367C_ACT44_SVID_MASK 0x2 +#define RTL8367C_ACT44_CVID_OFFSET 0 +#define RTL8367C_ACT44_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL23 0x062b +#define RTL8367C_OP47_NOT_OFFSET 14 +#define RTL8367C_OP47_NOT_MASK 0x4000 +#define RTL8367C_ACT47_GPIO_OFFSET 13 +#define RTL8367C_ACT47_GPIO_MASK 0x2000 +#define RTL8367C_ACT47_FORWARD_OFFSET 12 +#define RTL8367C_ACT47_FORWARD_MASK 0x1000 +#define RTL8367C_ACT47_POLICING_OFFSET 11 +#define RTL8367C_ACT47_POLICING_MASK 0x800 +#define RTL8367C_ACT47_PRIORITY_OFFSET 10 +#define RTL8367C_ACT47_PRIORITY_MASK 0x400 +#define RTL8367C_ACT47_SVID_OFFSET 9 +#define RTL8367C_ACT47_SVID_MASK 0x200 +#define RTL8367C_ACT47_CVID_OFFSET 8 +#define RTL8367C_ACT47_CVID_MASK 0x100 +#define RTL8367C_OP46_NOT_OFFSET 6 +#define RTL8367C_OP46_NOT_MASK 0x40 +#define RTL8367C_ACT46_GPIO_OFFSET 5 +#define RTL8367C_ACT46_GPIO_MASK 0x20 +#define RTL8367C_ACT46_FORWARD_OFFSET 4 +#define RTL8367C_ACT46_FORWARD_MASK 0x10 +#define RTL8367C_ACT46_POLICING_OFFSET 3 +#define RTL8367C_ACT46_POLICING_MASK 0x8 +#define RTL8367C_ACT46_PRIORITY_OFFSET 2 +#define RTL8367C_ACT46_PRIORITY_MASK 0x4 +#define RTL8367C_ACT46_SVID_OFFSET 1 +#define RTL8367C_ACT46_SVID_MASK 0x2 +#define RTL8367C_ACT46_CVID_OFFSET 0 +#define RTL8367C_ACT46_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL24 0x062c +#define RTL8367C_OP49_NOT_OFFSET 14 +#define RTL8367C_OP49_NOT_MASK 0x4000 +#define RTL8367C_ACT49_GPIO_OFFSET 13 +#define RTL8367C_ACT49_GPIO_MASK 0x2000 +#define RTL8367C_ACT49_FORWARD_OFFSET 12 +#define RTL8367C_ACT49_FORWARD_MASK 0x1000 +#define RTL8367C_ACT49_POLICING_OFFSET 11 +#define RTL8367C_ACT49_POLICING_MASK 0x800 +#define RTL8367C_ACT49_PRIORITY_OFFSET 10 +#define RTL8367C_ACT49_PRIORITY_MASK 0x400 +#define RTL8367C_ACT49_SVID_OFFSET 9 +#define RTL8367C_ACT49_SVID_MASK 0x200 +#define RTL8367C_ACT49_CVID_OFFSET 8 +#define RTL8367C_ACT49_CVID_MASK 0x100 +#define RTL8367C_OP48_NOT_OFFSET 6 +#define RTL8367C_OP48_NOT_MASK 0x40 +#define RTL8367C_ACT48_GPIO_OFFSET 5 +#define RTL8367C_ACT48_GPIO_MASK 0x20 +#define RTL8367C_ACT48_FORWARD_OFFSET 4 +#define RTL8367C_ACT48_FORWARD_MASK 0x10 +#define RTL8367C_ACT48_POLICING_OFFSET 3 +#define RTL8367C_ACT48_POLICING_MASK 0x8 +#define RTL8367C_ACT48_PRIORITY_OFFSET 2 +#define RTL8367C_ACT48_PRIORITY_MASK 0x4 +#define RTL8367C_ACT48_SVID_OFFSET 1 +#define RTL8367C_ACT48_SVID_MASK 0x2 +#define RTL8367C_ACT48_CVID_OFFSET 0 +#define RTL8367C_ACT48_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL25 0x062d +#define RTL8367C_OP51_NOT_OFFSET 14 +#define RTL8367C_OP51_NOT_MASK 0x4000 +#define RTL8367C_ACT51_GPIO_OFFSET 13 +#define RTL8367C_ACT51_GPIO_MASK 0x2000 +#define RTL8367C_ACT51_FORWARD_OFFSET 12 +#define RTL8367C_ACT51_FORWARD_MASK 0x1000 +#define RTL8367C_ACT51_POLICING_OFFSET 11 +#define RTL8367C_ACT51_POLICING_MASK 0x800 +#define RTL8367C_ACT51_PRIORITY_OFFSET 10 +#define RTL8367C_ACT51_PRIORITY_MASK 0x400 +#define RTL8367C_ACT51_SVID_OFFSET 9 +#define RTL8367C_ACT51_SVID_MASK 0x200 +#define RTL8367C_ACT51_CVID_OFFSET 8 +#define RTL8367C_ACT51_CVID_MASK 0x100 +#define RTL8367C_OP50_NOT_OFFSET 6 +#define RTL8367C_OP50_NOT_MASK 0x40 +#define RTL8367C_ACT50_GPIO_OFFSET 5 +#define RTL8367C_ACT50_GPIO_MASK 0x20 +#define RTL8367C_ACT50_FORWARD_OFFSET 4 +#define RTL8367C_ACT50_FORWARD_MASK 0x10 +#define RTL8367C_ACT50_POLICING_OFFSET 3 +#define RTL8367C_ACT50_POLICING_MASK 0x8 +#define RTL8367C_ACT50_PRIORITY_OFFSET 2 +#define RTL8367C_ACT50_PRIORITY_MASK 0x4 +#define RTL8367C_ACT50_SVID_OFFSET 1 +#define RTL8367C_ACT50_SVID_MASK 0x2 +#define RTL8367C_ACT50_CVID_OFFSET 0 +#define RTL8367C_ACT50_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL26 0x062e +#define RTL8367C_OP53_NOT_OFFSET 14 +#define RTL8367C_OP53_NOT_MASK 0x4000 +#define RTL8367C_ACT53_GPIO_OFFSET 13 +#define RTL8367C_ACT53_GPIO_MASK 0x2000 +#define RTL8367C_ACT53_FORWARD_OFFSET 12 +#define RTL8367C_ACT53_FORWARD_MASK 0x1000 +#define RTL8367C_ACT53_POLICING_OFFSET 11 +#define RTL8367C_ACT53_POLICING_MASK 0x800 +#define RTL8367C_ACT53_PRIORITY_OFFSET 10 +#define RTL8367C_ACT53_PRIORITY_MASK 0x400 +#define RTL8367C_ACT53_SVID_OFFSET 9 +#define RTL8367C_ACT53_SVID_MASK 0x200 +#define RTL8367C_ACT53_CVID_OFFSET 8 +#define RTL8367C_ACT53_CVID_MASK 0x100 +#define RTL8367C_OP52_NOT_OFFSET 6 +#define RTL8367C_OP52_NOT_MASK 0x40 +#define RTL8367C_ACT52_GPIO_OFFSET 5 +#define RTL8367C_ACT52_GPIO_MASK 0x20 +#define RTL8367C_ACT52_FORWARD_OFFSET 4 +#define RTL8367C_ACT52_FORWARD_MASK 0x10 +#define RTL8367C_ACT52_POLICING_OFFSET 3 +#define RTL8367C_ACT52_POLICING_MASK 0x8 +#define RTL8367C_ACT52_PRIORITY_OFFSET 2 +#define RTL8367C_ACT52_PRIORITY_MASK 0x4 +#define RTL8367C_ACT52_SVID_OFFSET 1 +#define RTL8367C_ACT52_SVID_MASK 0x2 +#define RTL8367C_ACT52_CVID_OFFSET 0 +#define RTL8367C_ACT52_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL27 0x062f +#define RTL8367C_OP55_NOT_OFFSET 14 +#define RTL8367C_OP55_NOT_MASK 0x4000 +#define RTL8367C_ACT55_GPIO_OFFSET 13 +#define RTL8367C_ACT55_GPIO_MASK 0x2000 +#define RTL8367C_ACT55_FORWARD_OFFSET 12 +#define RTL8367C_ACT55_FORWARD_MASK 0x1000 +#define RTL8367C_ACT55_POLICING_OFFSET 11 +#define RTL8367C_ACT55_POLICING_MASK 0x800 +#define RTL8367C_ACT55_PRIORITY_OFFSET 10 +#define RTL8367C_ACT55_PRIORITY_MASK 0x400 +#define RTL8367C_ACT55_SVID_OFFSET 9 +#define RTL8367C_ACT55_SVID_MASK 0x200 +#define RTL8367C_ACT55_CVID_OFFSET 8 +#define RTL8367C_ACT55_CVID_MASK 0x100 +#define RTL8367C_OP54_NOT_OFFSET 6 +#define RTL8367C_OP54_NOT_MASK 0x40 +#define RTL8367C_ACT54_GPIO_OFFSET 5 +#define RTL8367C_ACT54_GPIO_MASK 0x20 +#define RTL8367C_ACT54_FORWARD_OFFSET 4 +#define RTL8367C_ACT54_FORWARD_MASK 0x10 +#define RTL8367C_ACT54_POLICING_OFFSET 3 +#define RTL8367C_ACT54_POLICING_MASK 0x8 +#define RTL8367C_ACT54_PRIORITY_OFFSET 2 +#define RTL8367C_ACT54_PRIORITY_MASK 0x4 +#define RTL8367C_ACT54_SVID_OFFSET 1 +#define RTL8367C_ACT54_SVID_MASK 0x2 +#define RTL8367C_ACT54_CVID_OFFSET 0 +#define RTL8367C_ACT54_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL28 0x0630 +#define RTL8367C_OP57_NOT_OFFSET 14 +#define RTL8367C_OP57_NOT_MASK 0x4000 +#define RTL8367C_ACT57_GPIO_OFFSET 13 +#define RTL8367C_ACT57_GPIO_MASK 0x2000 +#define RTL8367C_ACT57_FORWARD_OFFSET 12 +#define RTL8367C_ACT57_FORWARD_MASK 0x1000 +#define RTL8367C_ACT57_POLICING_OFFSET 11 +#define RTL8367C_ACT57_POLICING_MASK 0x800 +#define RTL8367C_ACT57_PRIORITY_OFFSET 10 +#define RTL8367C_ACT57_PRIORITY_MASK 0x400 +#define RTL8367C_ACT57_SVID_OFFSET 9 +#define RTL8367C_ACT57_SVID_MASK 0x200 +#define RTL8367C_ACT57_CVID_OFFSET 8 +#define RTL8367C_ACT57_CVID_MASK 0x100 +#define RTL8367C_OP56_NOT_OFFSET 6 +#define RTL8367C_OP56_NOT_MASK 0x40 +#define RTL8367C_ACT56_GPIO_OFFSET 5 +#define RTL8367C_ACT56_GPIO_MASK 0x20 +#define RTL8367C_ACT56_FORWARD_OFFSET 4 +#define RTL8367C_ACT56_FORWARD_MASK 0x10 +#define RTL8367C_ACT56_POLICING_OFFSET 3 +#define RTL8367C_ACT56_POLICING_MASK 0x8 +#define RTL8367C_ACT56_PRIORITY_OFFSET 2 +#define RTL8367C_ACT56_PRIORITY_MASK 0x4 +#define RTL8367C_ACT56_SVID_OFFSET 1 +#define RTL8367C_ACT56_SVID_MASK 0x2 +#define RTL8367C_ACT56_CVID_OFFSET 0 +#define RTL8367C_ACT56_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL29 0x0631 +#define RTL8367C_OP59_NOT_OFFSET 14 +#define RTL8367C_OP59_NOT_MASK 0x4000 +#define RTL8367C_ACT59_GPIO_OFFSET 13 +#define RTL8367C_ACT59_GPIO_MASK 0x2000 +#define RTL8367C_ACT59_FORWARD_OFFSET 12 +#define RTL8367C_ACT59_FORWARD_MASK 0x1000 +#define RTL8367C_ACT59_POLICING_OFFSET 11 +#define RTL8367C_ACT59_POLICING_MASK 0x800 +#define RTL8367C_ACT59_PRIORITY_OFFSET 10 +#define RTL8367C_ACT59_PRIORITY_MASK 0x400 +#define RTL8367C_ACT59_SVID_OFFSET 9 +#define RTL8367C_ACT59_SVID_MASK 0x200 +#define RTL8367C_ACT59_CVID_OFFSET 8 +#define RTL8367C_ACT59_CVID_MASK 0x100 +#define RTL8367C_OP58_NOT_OFFSET 6 +#define RTL8367C_OP58_NOT_MASK 0x40 +#define RTL8367C_ACT58_GPIO_OFFSET 5 +#define RTL8367C_ACT58_GPIO_MASK 0x20 +#define RTL8367C_ACT58_FORWARD_OFFSET 4 +#define RTL8367C_ACT58_FORWARD_MASK 0x10 +#define RTL8367C_ACT58_POLICING_OFFSET 3 +#define RTL8367C_ACT58_POLICING_MASK 0x8 +#define RTL8367C_ACT58_PRIORITY_OFFSET 2 +#define RTL8367C_ACT58_PRIORITY_MASK 0x4 +#define RTL8367C_ACT58_SVID_OFFSET 1 +#define RTL8367C_ACT58_SVID_MASK 0x2 +#define RTL8367C_ACT58_CVID_OFFSET 0 +#define RTL8367C_ACT58_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL30 0x0632 +#define RTL8367C_OP61_NOT_OFFSET 14 +#define RTL8367C_OP61_NOT_MASK 0x4000 +#define RTL8367C_ACT61_GPIO_OFFSET 13 +#define RTL8367C_ACT61_GPIO_MASK 0x2000 +#define RTL8367C_ACT61_FORWARD_OFFSET 12 +#define RTL8367C_ACT61_FORWARD_MASK 0x1000 +#define RTL8367C_ACT61_POLICING_OFFSET 11 +#define RTL8367C_ACT61_POLICING_MASK 0x800 +#define RTL8367C_ACT61_PRIORITY_OFFSET 10 +#define RTL8367C_ACT61_PRIORITY_MASK 0x400 +#define RTL8367C_ACT61_SVID_OFFSET 9 +#define RTL8367C_ACT61_SVID_MASK 0x200 +#define RTL8367C_ACT61_CVID_OFFSET 8 +#define RTL8367C_ACT61_CVID_MASK 0x100 +#define RTL8367C_OP60_NOT_OFFSET 6 +#define RTL8367C_OP60_NOT_MASK 0x40 +#define RTL8367C_ACT60_GPIO_OFFSET 5 +#define RTL8367C_ACT60_GPIO_MASK 0x20 +#define RTL8367C_ACT60_FORWARD_OFFSET 4 +#define RTL8367C_ACT60_FORWARD_MASK 0x10 +#define RTL8367C_ACT60_POLICING_OFFSET 3 +#define RTL8367C_ACT60_POLICING_MASK 0x8 +#define RTL8367C_ACT60_PRIORITY_OFFSET 2 +#define RTL8367C_ACT60_PRIORITY_MASK 0x4 +#define RTL8367C_ACT60_SVID_OFFSET 1 +#define RTL8367C_ACT60_SVID_MASK 0x2 +#define RTL8367C_ACT60_CVID_OFFSET 0 +#define RTL8367C_ACT60_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL31 0x0633 +#define RTL8367C_OP63_NOT_OFFSET 14 +#define RTL8367C_OP63_NOT_MASK 0x4000 +#define RTL8367C_ACT63_GPIO_OFFSET 13 +#define RTL8367C_ACT63_GPIO_MASK 0x2000 +#define RTL8367C_ACT63_FORWARD_OFFSET 12 +#define RTL8367C_ACT63_FORWARD_MASK 0x1000 +#define RTL8367C_ACT63_POLICING_OFFSET 11 +#define RTL8367C_ACT63_POLICING_MASK 0x800 +#define RTL8367C_ACT63_PRIORITY_OFFSET 10 +#define RTL8367C_ACT63_PRIORITY_MASK 0x400 +#define RTL8367C_ACT63_SVID_OFFSET 9 +#define RTL8367C_ACT63_SVID_MASK 0x200 +#define RTL8367C_ACT63_CVID_OFFSET 8 +#define RTL8367C_ACT63_CVID_MASK 0x100 +#define RTL8367C_OP62_NOT_OFFSET 6 +#define RTL8367C_OP62_NOT_MASK 0x40 +#define RTL8367C_ACT62_GPIO_OFFSET 5 +#define RTL8367C_ACT62_GPIO_MASK 0x20 +#define RTL8367C_ACT62_FORWARD_OFFSET 4 +#define RTL8367C_ACT62_FORWARD_MASK 0x10 +#define RTL8367C_ACT62_POLICING_OFFSET 3 +#define RTL8367C_ACT62_POLICING_MASK 0x8 +#define RTL8367C_ACT62_PRIORITY_OFFSET 2 +#define RTL8367C_ACT62_PRIORITY_MASK 0x4 +#define RTL8367C_ACT62_SVID_OFFSET 1 +#define RTL8367C_ACT62_SVID_MASK 0x2 +#define RTL8367C_ACT62_CVID_OFFSET 0 +#define RTL8367C_ACT62_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 0x0635 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 0x0636 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 0x0637 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL0 0x0638 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL1 0x0639 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY1_CTRL2 0x063a +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY1_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL0 0x063b + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL1 0x063c + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY2_CTRL2 0x063d +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY2_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL0 0x063e + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL1 0x063f + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY3_CTRL2 0x0640 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY3_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL0 0x0641 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL1 0x0642 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY4_CTRL2 0x0643 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY4_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL0 0x0644 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL1 0x0645 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY5_CTRL2 0x0646 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY5_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL0 0x0647 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL1 0x0648 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY6_CTRL2 0x0649 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY6_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL0 0x064a + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL1 0x064b + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY7_CTRL2 0x064c +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY7_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL0 0x064d + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL1 0x064e + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY8_CTRL2 0x064f +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY8_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL0 0x0650 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL1 0x0651 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY9_CTRL2 0x0652 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY9_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL0 0x0653 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL1 0x0654 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY10_CTRL2 0x0655 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY10_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL0 0x0656 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL1 0x0657 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY11_CTRL2 0x0658 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY11_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL0 0x0659 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL1 0x065a + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY12_CTRL2 0x065b +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY12_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL0 0x065c + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL1 0x065d + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY13_CTRL2 0x065e +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY13_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL0 0x065f + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL1 0x0660 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY14_CTRL2 0x0661 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY14_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL0 0x0662 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL1 0x0663 + +#define RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY15_CTRL2 0x0664 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_OFFSET 0 +#define RTL8367C_ACL_SDPORT_RANGE_ENTRY15_CTRL2_MASK 0x3 + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 0x0665 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 0x0666 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL0 0x0667 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY1_CTRL1 0x0668 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY1_CTRL1_CHECK1_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL0 0x0669 +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY2_CTRL1 0x066a +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY2_CTRL1_CHECK2_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL0 0x066b +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY3_CTRL1 0x066c +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY3_CTRL1_CHECK3_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL0 0x066d +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY4_CTRL1 0x066e +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY4_CTRL1_CHECK4_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL0 0x066f +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY5_CTRL1 0x0670 +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY5_CTRL1_CHECK5_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL0 0x0671 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY6_CTRL1 0x0672 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY6_CTRL1_CHECK6_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL0 0x0673 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY7_CTRL1 0x0674 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY7_CTRL1_CHECK7_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL0 0x0675 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY8_CTRL1 0x0676 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY8_CTRL1_CHECK8_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL0 0x0677 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY9_CTRL1 0x0678 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY9_CTRL1_CHECK9_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL0 0x0679 +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY10_CTRL1 0x067a +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY10_CTRL1_CHECK10_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL0 0x067b +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY11_CTRL1 0x067c +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY11_CTRL1_CHECK11_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL0 0x067d +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY12_CTRL1 0x067e +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY12_CTRL1_CHECK12_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL0 0x067f +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY13_CTRL1 0x0680 +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY13_CTRL1_CHECK13_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL0 0x0681 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY14_CTRL1 0x0682 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY14_CTRL1_CHECK14_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL0 0x0683 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL0_MASK 0xFFF + +#define RTL8367C_REG_ACL_VID_RANGE_ENTRY15_CTRL1 0x0684 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_OFFSET 12 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_TYPE_MASK 0x3000 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_OFFSET 0 +#define RTL8367C_ACL_VID_RANGE_ENTRY15_CTRL1_CHECK15_HIGH_MASK 0xFFF + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 0x0685 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 0x0686 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 0x0687 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 0x0688 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 0x0689 +#define RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL0 0x068a + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL1 0x068b + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL2 0x068c + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL3 0x068d + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY1_CTRL4 0x068e +#define RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY1_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL0 0x068f + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL1 0x0690 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL2 0x0691 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL3 0x0692 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY2_CTRL4 0x0693 +#define RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY2_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL0 0x0694 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL1 0x0695 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL2 0x0696 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL3 0x0697 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY3_CTRL4 0x0698 +#define RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY3_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL0 0x0699 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL1 0x069a + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL2 0x069b + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL3 0x069c + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY4_CTRL4 0x069d +#define RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY4_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL0 0x069e + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL1 0x069f + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL2 0x06a0 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL3 0x06a1 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY5_CTRL4 0x06a2 +#define RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY5_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL0 0x06a3 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL1 0x06a4 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL2 0x06a5 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL3 0x06a6 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY6_CTRL4 0x06a7 +#define RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY6_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL0 0x06a8 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL1 0x06a9 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL2 0x06aa + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL3 0x06ab + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY7_CTRL4 0x06ac +#define RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY7_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL0 0x06ad + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL1 0x06ae + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL2 0x06af + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL3 0x06b0 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY8_CTRL4 0x06b1 +#define RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY8_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL0 0x06b2 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL1 0x06b3 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL2 0x06b4 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL3 0x06b5 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY9_CTRL4 0x06b6 +#define RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY9_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL0 0x06b7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL1 0x06b8 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL2 0x06b9 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL3 0x06ba + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY10_CTRL4 0x06bb +#define RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY10_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL0 0x06bc + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL1 0x06bd + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL2 0x06be + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL3 0x06bf + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY11_CTRL4 0x06c0 +#define RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY11_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL0 0x06c1 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL1 0x06c2 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL2 0x06c3 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL3 0x06c4 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY12_CTRL4 0x06c5 +#define RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY12_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL0 0x06c6 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL1 0x06c7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL2 0x06c8 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL3 0x06c9 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY13_CTRL4 0x06ca +#define RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY13_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL0 0x06cb + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL1 0x06cc + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL2 0x06cd + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL3 0x06ce + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY14_CTRL4 0x06cf +#define RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY14_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL0 0x06d0 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL1 0x06d1 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL2 0x06d2 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL3 0x06d3 + +#define RTL8367C_REG_ACL_IP_RANGE_ENTRY15_CTRL4 0x06d4 +#define RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_OFFSET 0 +#define RTL8367C_ACL_IP_RANGE_ENTRY15_CTRL4_MASK 0x7 + +#define RTL8367C_REG_ACL_ENABLE 0x06d5 +#define RTL8367C_PORT10_ENABLE_OFFSET 10 +#define RTL8367C_PORT10_ENABLE_MASK 0x400 +#define RTL8367C_PORT9_ENABLE_OFFSET 9 +#define RTL8367C_PORT9_ENABLE_MASK 0x200 +#define RTL8367C_PORT8_ENABLE_OFFSET 8 +#define RTL8367C_PORT8_ENABLE_MASK 0x100 +#define RTL8367C_PORT7_ENABLE_OFFSET 7 +#define RTL8367C_PORT7_ENABLE_MASK 0x80 +#define RTL8367C_PORT6_ENABLE_OFFSET 6 +#define RTL8367C_PORT6_ENABLE_MASK 0x40 +#define RTL8367C_PORT5_ENABLE_OFFSET 5 +#define RTL8367C_PORT5_ENABLE_MASK 0x20 +#define RTL8367C_PORT4_ENABLE_OFFSET 4 +#define RTL8367C_PORT4_ENABLE_MASK 0x10 +#define RTL8367C_PORT3_ENABLE_OFFSET 3 +#define RTL8367C_PORT3_ENABLE_MASK 0x8 +#define RTL8367C_PORT2_ENABLE_OFFSET 2 +#define RTL8367C_PORT2_ENABLE_MASK 0x4 +#define RTL8367C_PORT1_ENABLE_OFFSET 1 +#define RTL8367C_PORT1_ENABLE_MASK 0x2 +#define RTL8367C_PORT0_ENABLE_OFFSET 0 +#define RTL8367C_PORT0_ENABLE_MASK 0x1 + +#define RTL8367C_REG_ACL_UNMATCH_PERMIT 0x06d6 +#define RTL8367C_PORT10_PERMIT_OFFSET 10 +#define RTL8367C_PORT10_PERMIT_MASK 0x400 +#define RTL8367C_PORT9_PERMIT_OFFSET 9 +#define RTL8367C_PORT9_PERMIT_MASK 0x200 +#define RTL8367C_PORT8_PERMIT_OFFSET 8 +#define RTL8367C_PORT8_PERMIT_MASK 0x100 +#define RTL8367C_PORT7_PERMIT_OFFSET 7 +#define RTL8367C_PORT7_PERMIT_MASK 0x80 +#define RTL8367C_PORT6_PERMIT_OFFSET 6 +#define RTL8367C_PORT6_PERMIT_MASK 0x40 +#define RTL8367C_PORT5_PERMIT_OFFSET 5 +#define RTL8367C_PORT5_PERMIT_MASK 0x20 +#define RTL8367C_PORT4_PERMIT_OFFSET 4 +#define RTL8367C_PORT4_PERMIT_MASK 0x10 +#define RTL8367C_PORT3_PERMIT_OFFSET 3 +#define RTL8367C_PORT3_PERMIT_MASK 0x8 +#define RTL8367C_PORT2_PERMIT_OFFSET 2 +#define RTL8367C_PORT2_PERMIT_MASK 0x4 +#define RTL8367C_PORT1_PERMIT_OFFSET 1 +#define RTL8367C_PORT1_PERMIT_MASK 0x2 +#define RTL8367C_PORT0_PERMIT_OFFSET 0 +#define RTL8367C_PORT0_PERMIT_MASK 0x1 + +#define RTL8367C_REG_ACL_GPIO_POLARITY 0x06d7 +#define RTL8367C_ACL_GPIO_POLARITY_OFFSET 0 +#define RTL8367C_ACL_GPIO_POLARITY_MASK 0x1 + +#define RTL8367C_REG_ACL_LOG_CNT_TYPE 0x06d8 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_OFFSET 15 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER15_TYPE_MASK 0x8000 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_OFFSET 14 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER14_TYPE_MASK 0x4000 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_OFFSET 13 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER13_TYPE_MASK 0x2000 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_OFFSET 12 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER12_TYPE_MASK 0x1000 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_OFFSET 11 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER11_TYPE_MASK 0x800 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_OFFSET 10 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER10_TYPE_MASK 0x400 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_OFFSET 9 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER9_TYPE_MASK 0x200 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_OFFSET 8 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER8_TYPE_MASK 0x100 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_OFFSET 7 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER7_TYPE_MASK 0x80 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_OFFSET 6 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER6_TYPE_MASK 0x40 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_OFFSET 5 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER5_TYPE_MASK 0x20 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_OFFSET 4 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER4_TYPE_MASK 0x10 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_OFFSET 3 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER3_TYPE_MASK 0x8 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_OFFSET 2 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER2_TYPE_MASK 0x4 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_OFFSET 1 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER1_TYPE_MASK 0x2 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_OFFSET 0 +#define RTL8367C_ACL_LOG_CNT_TYPE_COUNTER0_TYPE_MASK 0x1 + +#define RTL8367C_REG_ACL_RESET_CFG 0x06d9 +#define RTL8367C_ACL_RESET_CFG_OFFSET 0 +#define RTL8367C_ACL_RESET_CFG_MASK 0x1 + +#define RTL8367C_REG_ACL_DUMMY00 0x06E0 + +#define RTL8367C_REG_ACL_DUMMY01 0x06E1 + +#define RTL8367C_REG_ACL_DUMMY02 0x06E2 + +#define RTL8367C_REG_ACL_DUMMY03 0x06E3 + +#define RTL8367C_REG_ACL_DUMMY04 0x06E4 + +#define RTL8367C_REG_ACL_DUMMY05 0x06E5 + +#define RTL8367C_REG_ACL_DUMMY06 0x06E6 + +#define RTL8367C_REG_ACL_DUMMY07 0x06E7 + +#define RTL8367C_REG_ACL_REASON_01 0x06E8 +#define RTL8367C_ACL_ACT_1_OFFSET 8 +#define RTL8367C_ACL_ACT_1_MASK 0xFF00 +#define RTL8367C_ACL_ACT_0_OFFSET 0 +#define RTL8367C_ACL_ACT_0_MASK 0xFF + +#define RTL8367C_REG_ACL_REASON_23 0x06E9 +#define RTL8367C_ACL_ACT_3_OFFSET 8 +#define RTL8367C_ACL_ACT_3_MASK 0xFF00 +#define RTL8367C_ACL_ACT_2_OFFSET 0 +#define RTL8367C_ACL_ACT_2_MASK 0xFF + +#define RTL8367C_REG_ACL_REASON_45 0x06EA +#define RTL8367C_ACL_ACT_5_OFFSET 8 +#define RTL8367C_ACL_ACT_5_MASK 0xFF00 +#define RTL8367C_ACL_ACT_4_OFFSET 0 +#define RTL8367C_ACL_ACT_4_MASK 0xFF + +#define RTL8367C_REG_ACL_ACCESS_MODE 0x06EB +#define RTL8367C_ACL_ACCESS_MODE_OFFSET 0 +#define RTL8367C_ACL_ACCESS_MODE_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL32 0x06F0 +#define RTL8367C_OP65_NOT_OFFSET 14 +#define RTL8367C_OP65_NOT_MASK 0x4000 +#define RTL8367C_ACT65_GPIO_OFFSET 13 +#define RTL8367C_ACT65_GPIO_MASK 0x2000 +#define RTL8367C_ACT65_FORWARD_OFFSET 12 +#define RTL8367C_ACT65_FORWARD_MASK 0x1000 +#define RTL8367C_ACT65_POLICING_OFFSET 11 +#define RTL8367C_ACT65_POLICING_MASK 0x800 +#define RTL8367C_ACT65_PRIORITY_OFFSET 10 +#define RTL8367C_ACT65_PRIORITY_MASK 0x400 +#define RTL8367C_ACT65_SVID_OFFSET 9 +#define RTL8367C_ACT65_SVID_MASK 0x200 +#define RTL8367C_ACT65_CVID_OFFSET 8 +#define RTL8367C_ACT65_CVID_MASK 0x100 +#define RTL8367C_OP64_NOT_OFFSET 6 +#define RTL8367C_OP64_NOT_MASK 0x40 +#define RTL8367C_ACT64_GPIO_OFFSET 5 +#define RTL8367C_ACT64_GPIO_MASK 0x20 +#define RTL8367C_ACT64_FORWARD_OFFSET 4 +#define RTL8367C_ACT64_FORWARD_MASK 0x10 +#define RTL8367C_ACT64_POLICING_OFFSET 3 +#define RTL8367C_ACT64_POLICING_MASK 0x8 +#define RTL8367C_ACT64_PRIORITY_OFFSET 2 +#define RTL8367C_ACT64_PRIORITY_MASK 0x4 +#define RTL8367C_ACT64_SVID_OFFSET 1 +#define RTL8367C_ACT64_SVID_MASK 0x2 +#define RTL8367C_ACT64_CVID_OFFSET 0 +#define RTL8367C_ACT64_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL33 0x06F1 +#define RTL8367C_OP67_NOT_OFFSET 14 +#define RTL8367C_OP67_NOT_MASK 0x4000 +#define RTL8367C_ACT67_GPIO_OFFSET 13 +#define RTL8367C_ACT67_GPIO_MASK 0x2000 +#define RTL8367C_ACT67_FORWARD_OFFSET 12 +#define RTL8367C_ACT67_FORWARD_MASK 0x1000 +#define RTL8367C_ACT67_POLICING_OFFSET 11 +#define RTL8367C_ACT67_POLICING_MASK 0x800 +#define RTL8367C_ACT67_PRIORITY_OFFSET 10 +#define RTL8367C_ACT67_PRIORITY_MASK 0x400 +#define RTL8367C_ACT67_SVID_OFFSET 9 +#define RTL8367C_ACT67_SVID_MASK 0x200 +#define RTL8367C_ACT67_CVID_OFFSET 8 +#define RTL8367C_ACT67_CVID_MASK 0x100 +#define RTL8367C_OP66_NOT_OFFSET 6 +#define RTL8367C_OP66_NOT_MASK 0x40 +#define RTL8367C_ACT66_GPIO_OFFSET 5 +#define RTL8367C_ACT66_GPIO_MASK 0x20 +#define RTL8367C_ACT66_FORWARD_OFFSET 4 +#define RTL8367C_ACT66_FORWARD_MASK 0x10 +#define RTL8367C_ACT66_POLICING_OFFSET 3 +#define RTL8367C_ACT66_POLICING_MASK 0x8 +#define RTL8367C_ACT66_PRIORITY_OFFSET 2 +#define RTL8367C_ACT66_PRIORITY_MASK 0x4 +#define RTL8367C_ACT66_SVID_OFFSET 1 +#define RTL8367C_ACT66_SVID_MASK 0x2 +#define RTL8367C_ACT66_CVID_OFFSET 0 +#define RTL8367C_ACT66_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL34 0x06F2 +#define RTL8367C_OP69_NOT_OFFSET 14 +#define RTL8367C_OP69_NOT_MASK 0x4000 +#define RTL8367C_ACT69_GPIO_OFFSET 13 +#define RTL8367C_ACT69_GPIO_MASK 0x2000 +#define RTL8367C_ACT69_FORWARD_OFFSET 12 +#define RTL8367C_ACT69_FORWARD_MASK 0x1000 +#define RTL8367C_ACT69_POLICING_OFFSET 11 +#define RTL8367C_ACT69_POLICING_MASK 0x800 +#define RTL8367C_ACT69_PRIORITY_OFFSET 10 +#define RTL8367C_ACT69_PRIORITY_MASK 0x400 +#define RTL8367C_ACT69_SVID_OFFSET 9 +#define RTL8367C_ACT69_SVID_MASK 0x200 +#define RTL8367C_ACT69_CVID_OFFSET 8 +#define RTL8367C_ACT69_CVID_MASK 0x100 +#define RTL8367C_OP68_NOT_OFFSET 6 +#define RTL8367C_OP68_NOT_MASK 0x40 +#define RTL8367C_ACT68_GPIO_OFFSET 5 +#define RTL8367C_ACT68_GPIO_MASK 0x20 +#define RTL8367C_ACT68_FORWARD_OFFSET 4 +#define RTL8367C_ACT68_FORWARD_MASK 0x10 +#define RTL8367C_ACT68_POLICING_OFFSET 3 +#define RTL8367C_ACT68_POLICING_MASK 0x8 +#define RTL8367C_ACT68_PRIORITY_OFFSET 2 +#define RTL8367C_ACT68_PRIORITY_MASK 0x4 +#define RTL8367C_ACT68_SVID_OFFSET 1 +#define RTL8367C_ACT68_SVID_MASK 0x2 +#define RTL8367C_ACT68_CVID_OFFSET 0 +#define RTL8367C_ACT68_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL35 0x06F3 +#define RTL8367C_OP71_NOT_OFFSET 14 +#define RTL8367C_OP71_NOT_MASK 0x4000 +#define RTL8367C_ACT71_GPIO_OFFSET 13 +#define RTL8367C_ACT71_GPIO_MASK 0x2000 +#define RTL8367C_ACT71_FORWARD_OFFSET 12 +#define RTL8367C_ACT71_FORWARD_MASK 0x1000 +#define RTL8367C_ACT71_POLICING_OFFSET 11 +#define RTL8367C_ACT71_POLICING_MASK 0x800 +#define RTL8367C_ACT71_PRIORITY_OFFSET 10 +#define RTL8367C_ACT71_PRIORITY_MASK 0x400 +#define RTL8367C_ACT71_SVID_OFFSET 9 +#define RTL8367C_ACT71_SVID_MASK 0x200 +#define RTL8367C_ACT71_CVID_OFFSET 8 +#define RTL8367C_ACT71_CVID_MASK 0x100 +#define RTL8367C_OP70_NOT_OFFSET 6 +#define RTL8367C_OP70_NOT_MASK 0x40 +#define RTL8367C_ACT70_GPIO_OFFSET 5 +#define RTL8367C_ACT70_GPIO_MASK 0x20 +#define RTL8367C_ACT70_FORWARD_OFFSET 4 +#define RTL8367C_ACT70_FORWARD_MASK 0x10 +#define RTL8367C_ACT70_POLICING_OFFSET 3 +#define RTL8367C_ACT70_POLICING_MASK 0x8 +#define RTL8367C_ACT70_PRIORITY_OFFSET 2 +#define RTL8367C_ACT70_PRIORITY_MASK 0x4 +#define RTL8367C_ACT70_SVID_OFFSET 1 +#define RTL8367C_ACT70_SVID_MASK 0x2 +#define RTL8367C_ACT70_CVID_OFFSET 0 +#define RTL8367C_ACT70_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL36 0x06F4 +#define RTL8367C_OP73_NOT_OFFSET 14 +#define RTL8367C_OP73_NOT_MASK 0x4000 +#define RTL8367C_ACT73_GPIO_OFFSET 13 +#define RTL8367C_ACT73_GPIO_MASK 0x2000 +#define RTL8367C_ACT73_FORWARD_OFFSET 12 +#define RTL8367C_ACT73_FORWARD_MASK 0x1000 +#define RTL8367C_ACT73_POLICING_OFFSET 11 +#define RTL8367C_ACT73_POLICING_MASK 0x800 +#define RTL8367C_ACT73_PRIORITY_OFFSET 10 +#define RTL8367C_ACT73_PRIORITY_MASK 0x400 +#define RTL8367C_ACT73_SVID_OFFSET 9 +#define RTL8367C_ACT73_SVID_MASK 0x200 +#define RTL8367C_ACT73_CVID_OFFSET 8 +#define RTL8367C_ACT73_CVID_MASK 0x100 +#define RTL8367C_OP72_NOT_OFFSET 6 +#define RTL8367C_OP72_NOT_MASK 0x40 +#define RTL8367C_ACT72_GPIO_OFFSET 5 +#define RTL8367C_ACT72_GPIO_MASK 0x20 +#define RTL8367C_ACT72_FORWARD_OFFSET 4 +#define RTL8367C_ACT72_FORWARD_MASK 0x10 +#define RTL8367C_ACT72_POLICING_OFFSET 3 +#define RTL8367C_ACT72_POLICING_MASK 0x8 +#define RTL8367C_ACT72_PRIORITY_OFFSET 2 +#define RTL8367C_ACT72_PRIORITY_MASK 0x4 +#define RTL8367C_ACT72_SVID_OFFSET 1 +#define RTL8367C_ACT72_SVID_MASK 0x2 +#define RTL8367C_ACT72_CVID_OFFSET 0 +#define RTL8367C_ACT72_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL37 0x06F5 +#define RTL8367C_OP75_NOT_OFFSET 14 +#define RTL8367C_OP75_NOT_MASK 0x4000 +#define RTL8367C_ACT75_GPIO_OFFSET 13 +#define RTL8367C_ACT75_GPIO_MASK 0x2000 +#define RTL8367C_ACT75_FORWARD_OFFSET 12 +#define RTL8367C_ACT75_FORWARD_MASK 0x1000 +#define RTL8367C_ACT75_POLICING_OFFSET 11 +#define RTL8367C_ACT75_POLICING_MASK 0x800 +#define RTL8367C_ACT75_PRIORITY_OFFSET 10 +#define RTL8367C_ACT75_PRIORITY_MASK 0x400 +#define RTL8367C_ACT75_SVID_OFFSET 9 +#define RTL8367C_ACT75_SVID_MASK 0x200 +#define RTL8367C_ACT75_CVID_OFFSET 8 +#define RTL8367C_ACT75_CVID_MASK 0x100 +#define RTL8367C_OP74_NOT_OFFSET 6 +#define RTL8367C_OP74_NOT_MASK 0x40 +#define RTL8367C_ACT74_GPIO_OFFSET 5 +#define RTL8367C_ACT74_GPIO_MASK 0x20 +#define RTL8367C_ACT74_FORWARD_OFFSET 4 +#define RTL8367C_ACT74_FORWARD_MASK 0x10 +#define RTL8367C_ACT74_POLICING_OFFSET 3 +#define RTL8367C_ACT74_POLICING_MASK 0x8 +#define RTL8367C_ACT74_PRIORITY_OFFSET 2 +#define RTL8367C_ACT74_PRIORITY_MASK 0x4 +#define RTL8367C_ACT74_SVID_OFFSET 1 +#define RTL8367C_ACT74_SVID_MASK 0x2 +#define RTL8367C_ACT74_CVID_OFFSET 0 +#define RTL8367C_ACT74_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL38 0x06F6 +#define RTL8367C_OP77_NOT_OFFSET 14 +#define RTL8367C_OP77_NOT_MASK 0x4000 +#define RTL8367C_ACT77_GPIO_OFFSET 13 +#define RTL8367C_ACT77_GPIO_MASK 0x2000 +#define RTL8367C_ACT77_FORWARD_OFFSET 12 +#define RTL8367C_ACT77_FORWARD_MASK 0x1000 +#define RTL8367C_ACT77_POLICING_OFFSET 11 +#define RTL8367C_ACT77_POLICING_MASK 0x800 +#define RTL8367C_ACT77_PRIORITY_OFFSET 10 +#define RTL8367C_ACT77_PRIORITY_MASK 0x400 +#define RTL8367C_ACT77_SVID_OFFSET 9 +#define RTL8367C_ACT77_SVID_MASK 0x200 +#define RTL8367C_ACT77_CVID_OFFSET 8 +#define RTL8367C_ACT77_CVID_MASK 0x100 +#define RTL8367C_OP76_NOT_OFFSET 6 +#define RTL8367C_OP76_NOT_MASK 0x40 +#define RTL8367C_ACT76_GPIO_OFFSET 5 +#define RTL8367C_ACT76_GPIO_MASK 0x20 +#define RTL8367C_ACT76_FORWARD_OFFSET 4 +#define RTL8367C_ACT76_FORWARD_MASK 0x10 +#define RTL8367C_ACT76_POLICING_OFFSET 3 +#define RTL8367C_ACT76_POLICING_MASK 0x8 +#define RTL8367C_ACT76_PRIORITY_OFFSET 2 +#define RTL8367C_ACT76_PRIORITY_MASK 0x4 +#define RTL8367C_ACT76_SVID_OFFSET 1 +#define RTL8367C_ACT76_SVID_MASK 0x2 +#define RTL8367C_ACT76_CVID_OFFSET 0 +#define RTL8367C_ACT76_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL39 0x06F7 +#define RTL8367C_OP79_NOT_OFFSET 14 +#define RTL8367C_OP79_NOT_MASK 0x4000 +#define RTL8367C_ACT79_GPIO_OFFSET 13 +#define RTL8367C_ACT79_GPIO_MASK 0x2000 +#define RTL8367C_ACT79_FORWARD_OFFSET 12 +#define RTL8367C_ACT79_FORWARD_MASK 0x1000 +#define RTL8367C_ACT79_POLICING_OFFSET 11 +#define RTL8367C_ACT79_POLICING_MASK 0x800 +#define RTL8367C_ACT79_PRIORITY_OFFSET 10 +#define RTL8367C_ACT79_PRIORITY_MASK 0x400 +#define RTL8367C_ACT79_SVID_OFFSET 9 +#define RTL8367C_ACT79_SVID_MASK 0x200 +#define RTL8367C_ACT79_CVID_OFFSET 8 +#define RTL8367C_ACT79_CVID_MASK 0x100 +#define RTL8367C_OP78_NOT_OFFSET 6 +#define RTL8367C_OP78_NOT_MASK 0x40 +#define RTL8367C_ACT78_GPIO_OFFSET 5 +#define RTL8367C_ACT78_GPIO_MASK 0x20 +#define RTL8367C_ACT78_FORWARD_OFFSET 4 +#define RTL8367C_ACT78_FORWARD_MASK 0x10 +#define RTL8367C_ACT78_POLICING_OFFSET 3 +#define RTL8367C_ACT78_POLICING_MASK 0x8 +#define RTL8367C_ACT78_PRIORITY_OFFSET 2 +#define RTL8367C_ACT78_PRIORITY_MASK 0x4 +#define RTL8367C_ACT78_SVID_OFFSET 1 +#define RTL8367C_ACT78_SVID_MASK 0x2 +#define RTL8367C_ACT78_CVID_OFFSET 0 +#define RTL8367C_ACT78_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL40 0x06F8 +#define RTL8367C_OP81_NOT_OFFSET 14 +#define RTL8367C_OP81_NOT_MASK 0x4000 +#define RTL8367C_ACT81_GPIO_OFFSET 13 +#define RTL8367C_ACT81_GPIO_MASK 0x2000 +#define RTL8367C_ACT81_FORWARD_OFFSET 12 +#define RTL8367C_ACT81_FORWARD_MASK 0x1000 +#define RTL8367C_ACT81_POLICING_OFFSET 11 +#define RTL8367C_ACT81_POLICING_MASK 0x800 +#define RTL8367C_ACT81_PRIORITY_OFFSET 10 +#define RTL8367C_ACT81_PRIORITY_MASK 0x400 +#define RTL8367C_ACT81_SVID_OFFSET 9 +#define RTL8367C_ACT81_SVID_MASK 0x200 +#define RTL8367C_ACT81_CVID_OFFSET 8 +#define RTL8367C_ACT81_CVID_MASK 0x100 +#define RTL8367C_OP80_NOT_OFFSET 6 +#define RTL8367C_OP80_NOT_MASK 0x40 +#define RTL8367C_ACT80_GPIO_OFFSET 5 +#define RTL8367C_ACT80_GPIO_MASK 0x20 +#define RTL8367C_ACT80_FORWARD_OFFSET 4 +#define RTL8367C_ACT80_FORWARD_MASK 0x10 +#define RTL8367C_ACT80_POLICING_OFFSET 3 +#define RTL8367C_ACT80_POLICING_MASK 0x8 +#define RTL8367C_ACT80_PRIORITY_OFFSET 2 +#define RTL8367C_ACT80_PRIORITY_MASK 0x4 +#define RTL8367C_ACT80_SVID_OFFSET 1 +#define RTL8367C_ACT80_SVID_MASK 0x2 +#define RTL8367C_ACT80_CVID_OFFSET 0 +#define RTL8367C_ACT80_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL41 0x06F9 +#define RTL8367C_OP83_NOT_OFFSET 14 +#define RTL8367C_OP83_NOT_MASK 0x4000 +#define RTL8367C_ACT83_GPIO_OFFSET 13 +#define RTL8367C_ACT83_GPIO_MASK 0x2000 +#define RTL8367C_ACT83_FORWARD_OFFSET 12 +#define RTL8367C_ACT83_FORWARD_MASK 0x1000 +#define RTL8367C_ACT83_POLICING_OFFSET 11 +#define RTL8367C_ACT83_POLICING_MASK 0x800 +#define RTL8367C_ACT83_PRIORITY_OFFSET 10 +#define RTL8367C_ACT83_PRIORITY_MASK 0x400 +#define RTL8367C_ACT83_SVID_OFFSET 9 +#define RTL8367C_ACT83_SVID_MASK 0x200 +#define RTL8367C_ACT83_CVID_OFFSET 8 +#define RTL8367C_ACT83_CVID_MASK 0x100 +#define RTL8367C_OP82_NOT_OFFSET 6 +#define RTL8367C_OP82_NOT_MASK 0x40 +#define RTL8367C_ACT82_GPIO_OFFSET 5 +#define RTL8367C_ACT82_GPIO_MASK 0x20 +#define RTL8367C_ACT82_FORWARD_OFFSET 4 +#define RTL8367C_ACT82_FORWARD_MASK 0x10 +#define RTL8367C_ACT82_POLICING_OFFSET 3 +#define RTL8367C_ACT82_POLICING_MASK 0x8 +#define RTL8367C_ACT82_PRIORITY_OFFSET 2 +#define RTL8367C_ACT82_PRIORITY_MASK 0x4 +#define RTL8367C_ACT82_SVID_OFFSET 1 +#define RTL8367C_ACT82_SVID_MASK 0x2 +#define RTL8367C_ACT82_CVID_OFFSET 0 +#define RTL8367C_ACT82_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL42 0x06FA +#define RTL8367C_OP85_NOT_OFFSET 14 +#define RTL8367C_OP85_NOT_MASK 0x4000 +#define RTL8367C_ACT85_GPIO_OFFSET 13 +#define RTL8367C_ACT85_GPIO_MASK 0x2000 +#define RTL8367C_ACT85_FORWARD_OFFSET 12 +#define RTL8367C_ACT85_FORWARD_MASK 0x1000 +#define RTL8367C_ACT85_POLICING_OFFSET 11 +#define RTL8367C_ACT85_POLICING_MASK 0x800 +#define RTL8367C_ACT85_PRIORITY_OFFSET 10 +#define RTL8367C_ACT85_PRIORITY_MASK 0x400 +#define RTL8367C_ACT85_SVID_OFFSET 9 +#define RTL8367C_ACT85_SVID_MASK 0x200 +#define RTL8367C_ACT85_CVID_OFFSET 8 +#define RTL8367C_ACT85_CVID_MASK 0x100 +#define RTL8367C_OP84_NOT_OFFSET 6 +#define RTL8367C_OP84_NOT_MASK 0x40 +#define RTL8367C_ACT84_GPIO_OFFSET 5 +#define RTL8367C_ACT84_GPIO_MASK 0x20 +#define RTL8367C_ACT84_FORWARD_OFFSET 4 +#define RTL8367C_ACT84_FORWARD_MASK 0x10 +#define RTL8367C_ACT84_POLICING_OFFSET 3 +#define RTL8367C_ACT84_POLICING_MASK 0x8 +#define RTL8367C_ACT84_PRIORITY_OFFSET 2 +#define RTL8367C_ACT84_PRIORITY_MASK 0x4 +#define RTL8367C_ACT84_SVID_OFFSET 1 +#define RTL8367C_ACT84_SVID_MASK 0x2 +#define RTL8367C_ACT84_CVID_OFFSET 0 +#define RTL8367C_ACT84_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL43 0x06FB +#define RTL8367C_OP87_NOT_OFFSET 14 +#define RTL8367C_OP87_NOT_MASK 0x4000 +#define RTL8367C_ACT87_GPIO_OFFSET 13 +#define RTL8367C_ACT87_GPIO_MASK 0x2000 +#define RTL8367C_ACT87_FORWARD_OFFSET 12 +#define RTL8367C_ACT87_FORWARD_MASK 0x1000 +#define RTL8367C_ACT87_POLICING_OFFSET 11 +#define RTL8367C_ACT87_POLICING_MASK 0x800 +#define RTL8367C_ACT87_PRIORITY_OFFSET 10 +#define RTL8367C_ACT87_PRIORITY_MASK 0x400 +#define RTL8367C_ACT87_SVID_OFFSET 9 +#define RTL8367C_ACT87_SVID_MASK 0x200 +#define RTL8367C_ACT87_CVID_OFFSET 8 +#define RTL8367C_ACT87_CVID_MASK 0x100 +#define RTL8367C_OP86_NOT_OFFSET 6 +#define RTL8367C_OP86_NOT_MASK 0x40 +#define RTL8367C_ACT86_GPIO_OFFSET 5 +#define RTL8367C_ACT86_GPIO_MASK 0x20 +#define RTL8367C_ACT86_FORWARD_OFFSET 4 +#define RTL8367C_ACT86_FORWARD_MASK 0x10 +#define RTL8367C_ACT86_POLICING_OFFSET 3 +#define RTL8367C_ACT86_POLICING_MASK 0x8 +#define RTL8367C_ACT86_PRIORITY_OFFSET 2 +#define RTL8367C_ACT86_PRIORITY_MASK 0x4 +#define RTL8367C_ACT86_SVID_OFFSET 1 +#define RTL8367C_ACT86_SVID_MASK 0x2 +#define RTL8367C_ACT86_CVID_OFFSET 0 +#define RTL8367C_ACT86_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL44 0x06FC +#define RTL8367C_OP89_NOT_OFFSET 14 +#define RTL8367C_OP89_NOT_MASK 0x4000 +#define RTL8367C_ACT89_GPIO_OFFSET 13 +#define RTL8367C_ACT89_GPIO_MASK 0x2000 +#define RTL8367C_ACT89_FORWARD_OFFSET 12 +#define RTL8367C_ACT89_FORWARD_MASK 0x1000 +#define RTL8367C_ACT89_POLICING_OFFSET 11 +#define RTL8367C_ACT89_POLICING_MASK 0x800 +#define RTL8367C_ACT89_PRIORITY_OFFSET 10 +#define RTL8367C_ACT89_PRIORITY_MASK 0x400 +#define RTL8367C_ACT89_SVID_OFFSET 9 +#define RTL8367C_ACT89_SVID_MASK 0x200 +#define RTL8367C_ACT89_CVID_OFFSET 8 +#define RTL8367C_ACT89_CVID_MASK 0x100 +#define RTL8367C_OP88_NOT_OFFSET 6 +#define RTL8367C_OP88_NOT_MASK 0x40 +#define RTL8367C_ACT88_GPIO_OFFSET 5 +#define RTL8367C_ACT88_GPIO_MASK 0x20 +#define RTL8367C_ACT88_FORWARD_OFFSET 4 +#define RTL8367C_ACT88_FORWARD_MASK 0x10 +#define RTL8367C_ACT88_POLICING_OFFSET 3 +#define RTL8367C_ACT88_POLICING_MASK 0x8 +#define RTL8367C_ACT88_PRIORITY_OFFSET 2 +#define RTL8367C_ACT88_PRIORITY_MASK 0x4 +#define RTL8367C_ACT88_SVID_OFFSET 1 +#define RTL8367C_ACT88_SVID_MASK 0x2 +#define RTL8367C_ACT88_CVID_OFFSET 0 +#define RTL8367C_ACT88_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL45 0x06FD +#define RTL8367C_OP91_NOT_OFFSET 14 +#define RTL8367C_OP91_NOT_MASK 0x4000 +#define RTL8367C_ACT91_GPIO_OFFSET 13 +#define RTL8367C_ACT91_GPIO_MASK 0x2000 +#define RTL8367C_ACT91_FORWARD_OFFSET 12 +#define RTL8367C_ACT91_FORWARD_MASK 0x1000 +#define RTL8367C_ACT91_POLICING_OFFSET 11 +#define RTL8367C_ACT91_POLICING_MASK 0x800 +#define RTL8367C_ACT91_PRIORITY_OFFSET 10 +#define RTL8367C_ACT91_PRIORITY_MASK 0x400 +#define RTL8367C_ACT91_SVID_OFFSET 9 +#define RTL8367C_ACT91_SVID_MASK 0x200 +#define RTL8367C_ACT91_CVID_OFFSET 8 +#define RTL8367C_ACT91_CVID_MASK 0x100 +#define RTL8367C_OP90_NOT_OFFSET 6 +#define RTL8367C_OP90_NOT_MASK 0x40 +#define RTL8367C_ACT90_GPIO_OFFSET 5 +#define RTL8367C_ACT90_GPIO_MASK 0x20 +#define RTL8367C_ACT90_FORWARD_OFFSET 4 +#define RTL8367C_ACT90_FORWARD_MASK 0x10 +#define RTL8367C_ACT90_POLICING_OFFSET 3 +#define RTL8367C_ACT90_POLICING_MASK 0x8 +#define RTL8367C_ACT90_PRIORITY_OFFSET 2 +#define RTL8367C_ACT90_PRIORITY_MASK 0x4 +#define RTL8367C_ACT90_SVID_OFFSET 1 +#define RTL8367C_ACT90_SVID_MASK 0x2 +#define RTL8367C_ACT90_CVID_OFFSET 0 +#define RTL8367C_ACT90_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL46 0x06FE +#define RTL8367C_OP93_NOT_OFFSET 14 +#define RTL8367C_OP93_NOT_MASK 0x4000 +#define RTL8367C_ACT93_GPIO_OFFSET 13 +#define RTL8367C_ACT93_GPIO_MASK 0x2000 +#define RTL8367C_ACT93_FORWARD_OFFSET 12 +#define RTL8367C_ACT93_FORWARD_MASK 0x1000 +#define RTL8367C_ACT93_POLICING_OFFSET 11 +#define RTL8367C_ACT93_POLICING_MASK 0x800 +#define RTL8367C_ACT93_PRIORITY_OFFSET 10 +#define RTL8367C_ACT93_PRIORITY_MASK 0x400 +#define RTL8367C_ACT93_SVID_OFFSET 9 +#define RTL8367C_ACT93_SVID_MASK 0x200 +#define RTL8367C_ACT93_CVID_OFFSET 8 +#define RTL8367C_ACT93_CVID_MASK 0x100 +#define RTL8367C_OP92_NOT_OFFSET 6 +#define RTL8367C_OP92_NOT_MASK 0x40 +#define RTL8367C_ACT92_GPIO_OFFSET 5 +#define RTL8367C_ACT92_GPIO_MASK 0x20 +#define RTL8367C_ACT92_FORWARD_OFFSET 4 +#define RTL8367C_ACT92_FORWARD_MASK 0x10 +#define RTL8367C_ACT92_POLICING_OFFSET 3 +#define RTL8367C_ACT92_POLICING_MASK 0x8 +#define RTL8367C_ACT92_PRIORITY_OFFSET 2 +#define RTL8367C_ACT92_PRIORITY_MASK 0x4 +#define RTL8367C_ACT92_SVID_OFFSET 1 +#define RTL8367C_ACT92_SVID_MASK 0x2 +#define RTL8367C_ACT92_CVID_OFFSET 0 +#define RTL8367C_ACT92_CVID_MASK 0x1 + +#define RTL8367C_REG_ACL_ACTION_CTRL47 0x06FF +#define RTL8367C_OP95_NOT_OFFSET 14 +#define RTL8367C_OP95_NOT_MASK 0x4000 +#define RTL8367C_ACT95_GPIO_OFFSET 13 +#define RTL8367C_ACT95_GPIO_MASK 0x2000 +#define RTL8367C_ACT95_FORWARD_OFFSET 12 +#define RTL8367C_ACT95_FORWARD_MASK 0x1000 +#define RTL8367C_ACT95_POLICING_OFFSET 11 +#define RTL8367C_ACT95_POLICING_MASK 0x800 +#define RTL8367C_ACT95_PRIORITY_OFFSET 10 +#define RTL8367C_ACT95_PRIORITY_MASK 0x400 +#define RTL8367C_ACT95_SVID_OFFSET 9 +#define RTL8367C_ACT95_SVID_MASK 0x200 +#define RTL8367C_ACT95_CVID_OFFSET 8 +#define RTL8367C_ACT95_CVID_MASK 0x100 +#define RTL8367C_OP94_NOT_OFFSET 6 +#define RTL8367C_OP94_NOT_MASK 0x40 +#define RTL8367C_ACT94_GPIO_OFFSET 5 +#define RTL8367C_ACT94_GPIO_MASK 0x20 +#define RTL8367C_ACT94_FORWARD_OFFSET 4 +#define RTL8367C_ACT94_FORWARD_MASK 0x10 +#define RTL8367C_ACT94_POLICING_OFFSET 3 +#define RTL8367C_ACT94_POLICING_MASK 0x8 +#define RTL8367C_ACT94_PRIORITY_OFFSET 2 +#define RTL8367C_ACT94_PRIORITY_MASK 0x4 +#define RTL8367C_ACT94_SVID_OFFSET 1 +#define RTL8367C_ACT94_SVID_MASK 0x2 +#define RTL8367C_ACT94_CVID_OFFSET 0 +#define RTL8367C_ACT94_CVID_MASK 0x1 + +/* (16'h0700)cvlan_reg */ + +#define RTL8367C_REG_VLAN_PVID_CTRL0 0x0700 +#define RTL8367C_PORT1_VIDX_OFFSET 8 +#define RTL8367C_PORT1_VIDX_MASK 0x1F00 +#define RTL8367C_PORT0_VIDX_OFFSET 0 +#define RTL8367C_PORT0_VIDX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PVID_CTRL1 0x0701 +#define RTL8367C_PORT3_VIDX_OFFSET 8 +#define RTL8367C_PORT3_VIDX_MASK 0x1F00 +#define RTL8367C_PORT2_VIDX_OFFSET 0 +#define RTL8367C_PORT2_VIDX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PVID_CTRL2 0x0702 +#define RTL8367C_PORT5_VIDX_OFFSET 8 +#define RTL8367C_PORT5_VIDX_MASK 0x1F00 +#define RTL8367C_PORT4_VIDX_OFFSET 0 +#define RTL8367C_PORT4_VIDX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PVID_CTRL3 0x0703 +#define RTL8367C_PORT7_VIDX_OFFSET 8 +#define RTL8367C_PORT7_VIDX_MASK 0x1F00 +#define RTL8367C_PORT6_VIDX_OFFSET 0 +#define RTL8367C_PORT6_VIDX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PVID_CTRL4 0x0704 +#define RTL8367C_PORT9_VIDX_OFFSET 8 +#define RTL8367C_PORT9_VIDX_MASK 0x1F00 +#define RTL8367C_PORT8_VIDX_OFFSET 0 +#define RTL8367C_PORT8_VIDX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PVID_CTRL5 0x0705 +#define RTL8367C_VLAN_PVID_CTRL5_OFFSET 0 +#define RTL8367C_VLAN_PVID_CTRL5_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB0_VALID 0x0708 +#define RTL8367C_VLAN_PPB0_VALID_VALID_EXT_OFFSET 8 +#define RTL8367C_VLAN_PPB0_VALID_VALID_EXT_MASK 0x700 +#define RTL8367C_VLAN_PPB0_VALID_VALID_OFFSET 0 +#define RTL8367C_VLAN_PPB0_VALID_VALID_MASK 0xFF + +#define RTL8367C_REG_VLAN_PPB0_CTRL0 0x0709 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT2_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT1_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB0_CTRL0_PORT0_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB0_CTRL1 0x070a +#define RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB0_CTRL1_PORT5_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB0_CTRL1_PORT4_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB0_CTRL1_PORT3_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB0_CTRL2 0x070b +#define RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_OFFSET 10 +#define RTL8367C_VLAN_PPB0_CTRL2_FRAME_TYPE_MASK 0xC00 +#define RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB0_CTRL2_PORT7_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB0_CTRL2_PORT6_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB0_CTRL4 0x070c +#define RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB0_CTRL3 0x070f + +#define RTL8367C_REG_VLAN_PPB1_VALID 0x0710 +#define RTL8367C_VLAN_PPB1_VALID_VALID_EXT_OFFSET 8 +#define RTL8367C_VLAN_PPB1_VALID_VALID_EXT_MASK 0x700 +#define RTL8367C_VLAN_PPB1_VALID_VALID_OFFSET 0 +#define RTL8367C_VLAN_PPB1_VALID_VALID_MASK 0xFF + +#define RTL8367C_REG_VLAN_PPB1_CTRL0 0x0711 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT2_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT1_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB1_CTRL0_PORT0_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB1_CTRL1 0x0712 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT5_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT4_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB1_CTRL1_PORT3_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB1_CTRL2 0x0713 +#define RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_OFFSET 10 +#define RTL8367C_VLAN_PPB1_CTRL2_FRAME_TYPE_MASK 0xC00 +#define RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB1_CTRL2_PORT7_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB1_CTRL2_PORT6_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB1_CTRL4 0x0714 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT10_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT9_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB1_CTRL4_PORT8_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB1_CTRL3 0x0717 + +#define RTL8367C_REG_VLAN_PPB2_VALID 0x0718 +#define RTL8367C_VLAN_PPB2_VALID_VALID_EXT_OFFSET 8 +#define RTL8367C_VLAN_PPB2_VALID_VALID_EXT_MASK 0x700 +#define RTL8367C_VLAN_PPB2_VALID_VALID_OFFSET 0 +#define RTL8367C_VLAN_PPB2_VALID_VALID_MASK 0xFF + +#define RTL8367C_REG_VLAN_PPB2_CTRL0 0x0719 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT2_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT1_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB2_CTRL0_PORT0_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB2_CTRL1 0x071a +#define RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB2_CTRL1_PORT5_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB2_CTRL1_PORT4_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB2_CTRL1_PORT3_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB2_CTRL2 0x071b +#define RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_OFFSET 10 +#define RTL8367C_VLAN_PPB2_CTRL2_FRAME_TYPE_MASK 0xC00 +#define RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB2_CTRL2_PORT7_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB2_CTRL2_PORT6_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB2_CTRL4 0x071c +#define RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB2_CTRL4_PORT10_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB2_CTRL4_PORT9_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB2_CTRL4_PORT8_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB2_CTRL3 0x071f + +#define RTL8367C_REG_VLAN_PPB3_VALID 0x0720 +#define RTL8367C_VLAN_PPB3_VALID_VALID_EXT_OFFSET 8 +#define RTL8367C_VLAN_PPB3_VALID_VALID_EXT_MASK 0x700 +#define RTL8367C_VLAN_PPB3_VALID_VALID_OFFSET 0 +#define RTL8367C_VLAN_PPB3_VALID_VALID_MASK 0xFF + +#define RTL8367C_REG_VLAN_PPB3_CTRL0 0x0721 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT2_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT1_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB3_CTRL0_PORT0_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB3_CTRL1 0x0722 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT5_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT4_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB3_CTRL1_PORT3_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB3_CTRL2 0x0723 +#define RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_OFFSET 10 +#define RTL8367C_VLAN_PPB3_CTRL2_FRAME_TYPE_MASK 0xC00 +#define RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB3_CTRL2_PORT7_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB3_CTRL2_PORT6_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB3_CTRL4 0x0724 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_OFFSET 10 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT10_INDEX_MASK 0x7C00 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_OFFSET 5 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT9_INDEX_MASK 0x3E0 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_OFFSET 0 +#define RTL8367C_VLAN_PPB3_CTRL4_PORT8_INDEX_MASK 0x1F + +#define RTL8367C_REG_VLAN_PPB3_CTRL3 0x0727 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL0 0x0728 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL1 0x0729 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL2 0x072a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION0_CTRL3 0x072b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION0_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL0 0x072c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL1 0x072d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL2 0x072e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION1_CTRL3 0x072f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION1_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL0 0x0730 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL1 0x0731 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL2 0x0732 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION2_CTRL3 0x0733 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION2_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL0 0x0734 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL1 0x0735 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL2 0x0736 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION3_CTRL3 0x0737 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION3_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL0 0x0738 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL1 0x0739 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL2 0x073a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION4_CTRL3 0x073b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION4_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL0 0x073c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL1 0x073d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL2 0x073e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION5_CTRL3 0x073f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION5_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL0 0x0740 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL1 0x0741 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL2 0x0742 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION6_CTRL3 0x0743 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION6_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL0 0x0744 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL1 0x0745 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL2 0x0746 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION7_CTRL3 0x0747 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION7_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL0 0x0748 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL1 0x0749 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL2 0x074a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION8_CTRL3 0x074b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION8_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL0 0x074c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL1 0x074d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL2 0x074e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION9_CTRL3 0x074f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION9_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL0 0x0750 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL1 0x0751 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL2 0x0752 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION10_CTRL3 0x0753 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION10_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL0 0x0754 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL1 0x0755 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL2 0x0756 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION11_CTRL3 0x0757 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION11_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL0 0x0758 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL1 0x0759 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL2 0x075a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION12_CTRL3 0x075b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION12_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL0 0x075c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL1 0x075d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL2 0x075e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION13_CTRL3 0x075f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION13_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL0 0x0760 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL1 0x0761 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL2 0x0762 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION14_CTRL3 0x0763 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION14_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL0 0x0764 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL1 0x0765 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL2 0x0766 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION15_CTRL3 0x0767 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION15_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL0 0x0768 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL1 0x0769 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL2 0x076a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION16_CTRL3 0x076b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION16_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL0 0x076c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL1 0x076d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL2 0x076e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION17_CTRL3 0x076f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION17_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL0 0x0770 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL1 0x0771 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL2 0x0772 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION18_CTRL3 0x0773 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION18_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL0 0x0774 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL1 0x0775 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL2 0x0776 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION19_CTRL3 0x0777 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION19_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL0 0x0778 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL1 0x0779 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL2 0x077a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION20_CTRL3 0x077b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION20_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL0 0x077c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL1 0x077d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL2 0x077e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION21_CTRL3 0x077f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION21_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL0 0x0780 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL1 0x0781 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL2 0x0782 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION22_CTRL3 0x0783 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION22_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL0 0x0784 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL1 0x0785 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL2 0x0786 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION23_CTRL3 0x0787 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION23_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL0 0x0788 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL1 0x0789 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL2 0x078a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION24_CTRL3 0x078b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION24_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL0 0x078c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL1 0x078d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL2 0x078e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION25_CTRL3 0x078f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION25_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL0 0x0790 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL1 0x0791 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL2 0x0792 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION26_CTRL3 0x0793 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION26_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL0 0x0794 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL1 0x0795 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL2 0x0796 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION27_CTRL3 0x0797 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION27_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL0 0x0798 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL1 0x0799 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL2 0x079a +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION28_CTRL3 0x079b +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION28_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL0 0x079c +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL1 0x079d +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL2 0x079e +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION29_CTRL3 0x079f +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION29_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL0 0x07a0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL1 0x07a1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL2 0x07a2 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION30_CTRL3 0x07a3 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION30_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL0 0x07a4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_OFFSET 8 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_EXT_MASK 0x700 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL0_MBR_MASK 0xFF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL1 0x07a5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL1_MASK 0xF + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL2 0x07a6 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_OFFSET 10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_EXT_MASK 0x400 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_OFFSET 5 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_METERIDX_MASK 0x3E0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_OFFSET 4 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_ENVLANPOL_MASK 0x10 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_OFFSET 1 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPRI_MASK 0xE +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL2_VBPEN_MASK 0x1 + +#define RTL8367C_REG_VLAN_MEMBER_CONFIGURATION31_CTRL3 0x07a7 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_MEMBER_CONFIGURATION31_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_VLAN_CTRL 0x07a8 +#define RTL8367C_VLAN_CTRL_OFFSET 0 +#define RTL8367C_VLAN_CTRL_MASK 0x1 + +#define RTL8367C_REG_VLAN_INGRESS 0x07a9 +#define RTL8367C_VLAN_INGRESS_OFFSET 0 +#define RTL8367C_VLAN_INGRESS_MASK 0x7FF + +#define RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL0 0x07aa +#define RTL8367C_PORT7_FRAME_TYPE_OFFSET 14 +#define RTL8367C_PORT7_FRAME_TYPE_MASK 0xC000 +#define RTL8367C_PORT6_FRAME_TYPE_OFFSET 12 +#define RTL8367C_PORT6_FRAME_TYPE_MASK 0x3000 +#define RTL8367C_PORT5_FRAME_TYPE_OFFSET 10 +#define RTL8367C_PORT5_FRAME_TYPE_MASK 0xC00 +#define RTL8367C_PORT4_FRAME_TYPE_OFFSET 8 +#define RTL8367C_PORT4_FRAME_TYPE_MASK 0x300 +#define RTL8367C_PORT3_FRAME_TYPE_OFFSET 6 +#define RTL8367C_PORT3_FRAME_TYPE_MASK 0xC0 +#define RTL8367C_PORT2_FRAME_TYPE_OFFSET 4 +#define RTL8367C_PORT2_FRAME_TYPE_MASK 0x30 +#define RTL8367C_PORT1_FRAME_TYPE_OFFSET 2 +#define RTL8367C_PORT1_FRAME_TYPE_MASK 0xC +#define RTL8367C_PORT0_FRAME_TYPE_OFFSET 0 +#define RTL8367C_PORT0_FRAME_TYPE_MASK 0x3 + +#define RTL8367C_REG_VLAN_ACCEPT_FRAME_TYPE_CTRL1 0x07ab +#define RTL8367C_PORT10_FRAME_TYPE_OFFSET 4 +#define RTL8367C_PORT10_FRAME_TYPE_MASK 0x30 +#define RTL8367C_PORT9_FRAME_TYPE_OFFSET 2 +#define RTL8367C_PORT9_FRAME_TYPE_MASK 0xC +#define RTL8367C_PORT8_FRAME_TYPE_OFFSET 0 +#define RTL8367C_PORT8_FRAME_TYPE_MASK 0x3 + +#define RTL8367C_REG_PORT_PBFIDEN 0x07ac +#define RTL8367C_PORT_PBFIDEN_OFFSET 0 +#define RTL8367C_PORT_PBFIDEN_MASK 0x7FF + +#define RTL8367C_REG_PORT0_PBFID 0x07ad +#define RTL8367C_PORT0_PBFID_OFFSET 0 +#define RTL8367C_PORT0_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT1_PBFID 0x07ae +#define RTL8367C_PORT1_PBFID_OFFSET 0 +#define RTL8367C_PORT1_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT2_PBFID 0x07af +#define RTL8367C_PORT2_PBFID_OFFSET 0 +#define RTL8367C_PORT2_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT3_PBFID 0x07b0 +#define RTL8367C_PORT3_PBFID_OFFSET 0 +#define RTL8367C_PORT3_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT4_PBFID 0x07b1 +#define RTL8367C_PORT4_PBFID_OFFSET 0 +#define RTL8367C_PORT4_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT5_PBFID 0x07b2 +#define RTL8367C_PORT5_PBFID_OFFSET 0 +#define RTL8367C_PORT5_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT6_PBFID 0x07b3 +#define RTL8367C_PORT6_PBFID_OFFSET 0 +#define RTL8367C_PORT6_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT7_PBFID 0x07b4 +#define RTL8367C_PORT7_PBFID_OFFSET 0 +#define RTL8367C_PORT7_PBFID_MASK 0xF + +#define RTL8367C_REG_VLAN_EXT_CTRL 0x07b5 +#define RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET 2 +#define RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_MASK 0x4 +#define RTL8367C_VLAN_VID4095_TYPE_OFFSET 1 +#define RTL8367C_VLAN_VID4095_TYPE_MASK 0x2 +#define RTL8367C_VLAN_VID0_TYPE_OFFSET 0 +#define RTL8367C_VLAN_VID0_TYPE_MASK 0x1 + +#define RTL8367C_REG_VLAN_EXT_CTRL2 0x07b6 +#define RTL8367C_VLAN_EXT_CTRL2_OFFSET 0 +#define RTL8367C_VLAN_EXT_CTRL2_MASK 0x1 + +#define RTL8367C_REG_PORT8_PBFID 0x07b7 +#define RTL8367C_PORT8_PBFID_OFFSET 0 +#define RTL8367C_PORT8_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT9_PBFID 0x07b8 +#define RTL8367C_PORT9_PBFID_OFFSET 0 +#define RTL8367C_PORT9_PBFID_MASK 0xF + +#define RTL8367C_REG_PORT10_PBFID 0x07b9 +#define RTL8367C_PORT10_PBFID_OFFSET 0 +#define RTL8367C_PORT10_PBFID_MASK 0xF + +#define RTL8367C_REG_CVLAN_DUMMY00 0x07E0 + +#define RTL8367C_REG_CVLAN_DUMMY01 0x07E1 + +#define RTL8367C_REG_CVLAN_DUMMY02 0x07E2 + +#define RTL8367C_REG_CVLAN_DUMMY03 0x07E3 + +#define RTL8367C_REG_CVLAN_DUMMY04 0x07E4 + +#define RTL8367C_REG_CVLAN_DUMMY05 0x07E5 + +#define RTL8367C_REG_CVLAN_DUMMY06 0x07E6 + +#define RTL8367C_REG_CVLAN_DUMMY07 0x07E7 + +#define RTL8367C_REG_CVLAN_DUMMY08 0x07E8 + +#define RTL8367C_REG_CVLAN_DUMMY09 0x07E9 + +#define RTL8367C_REG_CVLAN_DUMMY10 0x07EA + +#define RTL8367C_REG_CVLAN_DUMMY11 0x07EB + +#define RTL8367C_REG_CVLAN_DUMMY12 0x07EC + +#define RTL8367C_REG_CVLAN_DUMMY13 0x07ED + +#define RTL8367C_REG_CVLAN_DUMMY14 0x07EE + +#define RTL8367C_REG_CVLAN_DUMMY15 0x07EF + +/* (16'h0800)dpm_reg */ + +#define RTL8367C_REG_RMA_CTRL00 0x0800 +#define RTL8367C_RMA_CTRL00_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL00_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL00_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_TRAP_PRIORITY_OFFSET 3 +#define RTL8367C_TRAP_PRIORITY_MASK 0x38 +#define RTL8367C_RMA_CTRL00_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL00_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL00_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL00_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL00_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL00_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL01 0x0801 +#define RTL8367C_RMA_CTRL01_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL01_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL01_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL01_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL01_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL01_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL01_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL01_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL01_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL02 0x0802 +#define RTL8367C_RMA_CTRL02_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL02_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL02_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL02_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL02_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL02_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL02_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL02_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL02_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL03 0x0803 +#define RTL8367C_RMA_CTRL03_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL03_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL03_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL03_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL03_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL03_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL03_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL03_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL03_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL04 0x0804 +#define RTL8367C_RMA_CTRL04_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL04_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL04_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL04_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL04_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL04_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL04_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL04_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL04_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL08 0x0808 +#define RTL8367C_RMA_CTRL08_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL08_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL08_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL08_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL08_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL08_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL08_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL08_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL08_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL0D 0x080d +#define RTL8367C_RMA_CTRL0D_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL0D_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL0D_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL0D_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL0D_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL0D_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL0D_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL0D_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL0E 0x080e +#define RTL8367C_RMA_CTRL0E_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL0E_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL0E_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL0E_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL0E_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL0E_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL0E_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL0E_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL10 0x0810 +#define RTL8367C_RMA_CTRL10_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL10_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL10_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL10_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL10_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL10_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL10_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL10_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL10_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL11 0x0811 +#define RTL8367C_RMA_CTRL11_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL11_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL11_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL11_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL11_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL11_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL11_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL11_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL11_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL12 0x0812 +#define RTL8367C_RMA_CTRL12_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL12_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL12_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL12_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL12_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL12_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL12_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL12_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL12_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL13 0x0813 +#define RTL8367C_RMA_CTRL13_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL13_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL13_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL13_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL13_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL13_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL13_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL13_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL13_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL18 0x0818 +#define RTL8367C_RMA_CTRL18_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL18_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL18_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL18_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL18_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL18_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL18_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL18_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL18_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL1A 0x081a +#define RTL8367C_RMA_CTRL1A_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL1A_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL1A_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL1A_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL1A_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL1A_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL1A_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL1A_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL20 0x0820 +#define RTL8367C_RMA_CTRL20_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL20_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL20_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL20_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL20_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL20_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL20_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL20_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL20_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL21 0x0821 +#define RTL8367C_RMA_CTRL21_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL21_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL21_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL21_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL21_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL21_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL21_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL21_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL21_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL22 0x0822 +#define RTL8367C_RMA_CTRL22_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL22_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL22_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL22_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL22_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL22_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL22_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL22_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL22_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL_CDP 0x0830 +#define RTL8367C_RMA_CTRL_CDP_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL_CDP_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL_CDP_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL_CDP_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL_CDP_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL_CDP_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL_CSSTP 0x0831 +#define RTL8367C_RMA_CTRL_CSSTP_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL_CSSTP_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL_CSSTP_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL_CSSTP_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL_CSSTP_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL_CSSTP_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_CTRL_LLDP 0x0832 +#define RTL8367C_RMA_CTRL_LLDP_OPERATION_OFFSET 7 +#define RTL8367C_RMA_CTRL_LLDP_OPERATION_MASK 0x180 +#define RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_OFFSET 6 +#define RTL8367C_RMA_CTRL_LLDP_DISCARD_STORM_FILTER_MASK 0x40 +#define RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_OFFSET 2 +#define RTL8367C_RMA_CTRL_LLDP_KEEP_FORMAT_MASK 0x4 +#define RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_RMA_CTRL_LLDP_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_RMA_CTRL_LLDP_PORTISO_LEAKY_MASK 0x1 + +#define RTL8367C_REG_RMA_LLDP_EN 0x0833 +#define RTL8367C_RMA_LLDP_EN_OFFSET 0 +#define RTL8367C_RMA_LLDP_EN_MASK 0x1 + +#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL0 0x0851 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL1 0x0852 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PORTBASED_PRIORITY_CTRL2 0x0853 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL0 0x0855 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL1 0x0856 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM0_CTRL2 0x0857 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM0_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL0 0x0859 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL1 0x085a +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM1_CTRL2 0x085b +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM1_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL0 0x085d +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL1 0x085e +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM2_CTRL2 0x085f +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM2_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL0 0x0861 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL1 0x0862 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_VLAN_PPB_PRIORITY_ITEM3_CTRL2 0x0863 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_VLAN_PPB_PRIORITY_ITEM3_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL0 0x0865 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_OFFSET 12 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY3_MASK 0x7000 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_OFFSET 8 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY2_MASK 0x700 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_OFFSET 4 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY1_MASK 0x70 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_OFFSET 0 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL0_PRIORITY0_MASK 0x7 + +#define RTL8367C_REG_QOS_1Q_PRIORITY_REMAPPING_CTRL1 0x0866 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_OFFSET 12 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY7_MASK 0x7000 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_OFFSET 8 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY6_MASK 0x700 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_OFFSET 4 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY5_MASK 0x70 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_OFFSET 0 +#define RTL8367C_QOS_1Q_PRIORITY_REMAPPING_CTRL1_PRIORITY4_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL0 0x0867 +#define RTL8367C_DSCP3_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP3_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP2_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP2_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP1_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP1_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP0_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL1 0x0868 +#define RTL8367C_DSCP7_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP7_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP6_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP6_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP5_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP5_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP4_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL2 0x0869 +#define RTL8367C_DSCP11_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP11_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP10_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP10_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP9_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP9_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP8_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL3 0x086a +#define RTL8367C_DSCP15_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP15_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP14_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP14_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP13_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP13_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP12_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP12_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL4 0x086b +#define RTL8367C_DSCP19_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP19_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP18_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP18_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP17_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP17_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP16_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP16_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL5 0x086c +#define RTL8367C_DSCP23_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP23_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP22_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP22_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP21_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP21_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP20_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP20_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL6 0x086d +#define RTL8367C_DSCP27_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP27_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP26_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP26_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP25_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP25_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP24_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP24_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL7 0x086e +#define RTL8367C_DSCP31_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP31_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP30_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP30_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP29_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP29_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP28_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP28_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL8 0x086f +#define RTL8367C_DSCP35_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP35_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP34_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP34_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP33_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP33_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP32_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP32_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL9 0x0870 +#define RTL8367C_DSCP39_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP39_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP38_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP38_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP37_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP37_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP36_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP36_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL10 0x0871 +#define RTL8367C_DSCP43_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP43_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP42_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP42_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP41_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP41_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP40_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP40_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL11 0x0872 +#define RTL8367C_DSCP47_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP47_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP46_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP46_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP45_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP45_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP44_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP44_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL12 0x0873 +#define RTL8367C_DSCP51_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP51_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP50_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP50_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP49_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP49_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP48_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP48_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL13 0x0874 +#define RTL8367C_DSCP55_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP55_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP54_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP54_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP53_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP53_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP52_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP52_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL14 0x0875 +#define RTL8367C_DSCP59_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP59_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP58_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP58_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP57_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP57_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP56_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP56_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_DSCP_TO_PRIORITY_CTRL15 0x0876 +#define RTL8367C_DSCP63_PRIORITY_OFFSET 12 +#define RTL8367C_DSCP63_PRIORITY_MASK 0x7000 +#define RTL8367C_DSCP62_PRIORITY_OFFSET 8 +#define RTL8367C_DSCP62_PRIORITY_MASK 0x700 +#define RTL8367C_DSCP61_PRIORITY_OFFSET 4 +#define RTL8367C_DSCP61_PRIORITY_MASK 0x70 +#define RTL8367C_DSCP60_PRIORITY_OFFSET 0 +#define RTL8367C_DSCP60_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL0 0x0877 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_OFFSET 12 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT3_PRIORITY_MASK 0x7000 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_OFFSET 8 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT2_PRIORITY_MASK 0x700 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_OFFSET 4 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT1_PRIORITY_MASK 0x70 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_OFFSET 0 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL0_PORT0_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL1 0x0878 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_OFFSET 12 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT7_PRIORITY_MASK 0x7000 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_OFFSET 8 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT6_PRIORITY_MASK 0x700 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_OFFSET 4 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT5_PRIORITY_MASK 0x70 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_OFFSET 0 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL1_PORT4_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_DUMMY0879 0x0879 +#define RTL8367C_DUMMY0879_OFFSET 0 +#define RTL8367C_DUMMY0879_MASK 0x1 + +#define RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2 0x087a +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_OFFSET 8 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT10_PRIORITY_MASK 0x700 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_OFFSET 4 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT9_PRIORITY_MASK 0x70 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_OFFSET 0 +#define RTL8367C_QOS_PORTBASED_PRIORITY_CTRL2_PORT8_PRIORITY_MASK 0x7 + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL0 0x087b +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_ACL_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL0_QOS_PORT_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL1 0x087c +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DOT1Q_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL1_QOS_DSCP_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL2 0x087d +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_CVLAN_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL2_QOS_SVLAN_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_CTRL3 0x087e +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_SA_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_CTRL3_QOS_LUTFWD_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0 0x087f +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_OFFSET 12 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY3_MASK 0x7000 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_OFFSET 8 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY2_MASK 0x700 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_OFFSET 4 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY1_MASK 0x70 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_OFFSET 0 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL0_PRIORITY0_MASK 0x7 + +#define RTL8367C_REG_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1 0x0880 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_OFFSET 12 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY7_MASK 0x7000 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_OFFSET 8 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY6_MASK 0x700 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_OFFSET 4 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY5_MASK 0x70 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_OFFSET 0 +#define RTL8367C_QOS_PRIORITY_REMAPPING_IN_CPU_CTRL1_PRIORITY4_MASK 0x7 + +#define RTL8367C_REG_QOS_TRAP_PRIORITY0 0x0881 +#define RTL8367C_UNKNOWN_MC_PRIORTY_OFFSET 12 +#define RTL8367C_UNKNOWN_MC_PRIORTY_MASK 0x7000 +#define RTL8367C_SVLAN_PRIOIRTY_OFFSET 8 +#define RTL8367C_SVLAN_PRIOIRTY_MASK 0x700 +#define RTL8367C_OAM_PRIOIRTY_OFFSET 4 +#define RTL8367C_OAM_PRIOIRTY_MASK 0x70 +#define RTL8367C_DOT1X_PRIORTY_OFFSET 0 +#define RTL8367C_DOT1X_PRIORTY_MASK 0x7 + +#define RTL8367C_REG_QOS_TRAP_PRIORITY1 0x0882 +#define RTL8367C_DW8051_TRAP_PRI_OFFSET 4 +#define RTL8367C_DW8051_TRAP_PRI_MASK 0x70 +#define RTL8367C_EEELLDP_TRAP_PRI_OFFSET 0 +#define RTL8367C_EEELLDP_TRAP_PRI_MASK 0x7 + +#define RTL8367C_REG_MAX_LENGTH_CFG 0x0883 +#define RTL8367C_MAX_LENGTH_GIGA_OFFSET 8 +#define RTL8367C_MAX_LENGTH_GIGA_MASK 0xFF00 +#define RTL8367C_MAX_LENGTH_10_100M_OFFSET 0 +#define RTL8367C_MAX_LENGTH_10_100M_MASK 0xFF + +#define RTL8367C_REG_MAX_LEN_RX_TX 0x0884 +#define RTL8367C_MAX_LEN_RX_TX_OFFSET 0 +#define RTL8367C_MAX_LEN_RX_TX_MASK 0x3 + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0 0x0885 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_ACL_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL0_QOS_PORT_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1 0x0886 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DOT1Q_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL1_QOS_DSCP_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2 0x0887 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_CVLAN_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL2_QOS_SVLAN_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3 0x0888 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_OFFSET 8 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_SA_WEIGHT_MASK 0xFF00 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_CTRL3_QOS_LUTFWD_WEIGHT_MASK 0xFF + +#define RTL8367C_REG_QOS_INTERNAL_PRIORITY_DECISION_IDX 0x0889 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_OFFSET 0 +#define RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_MASK 0x7FF + +#define RTL8367C_REG_MAX_LENGTH_CFG_EXT 0x088a +#define RTL8367C_MAX_LENGTH_GIGA_EXT_OFFSET 3 +#define RTL8367C_MAX_LENGTH_GIGA_EXT_MASK 0x38 +#define RTL8367C_MAX_LENGTH_10_100M_EXT_OFFSET 0 +#define RTL8367C_MAX_LENGTH_10_100M_EXT_MASK 0x7 + +#define RTL8367C_REG_MAX_LEN_RX_TX_CFG0 0x088c +#define RTL8367C_MAX_LEN_RX_TX_CFG0_OFFSET 0 +#define RTL8367C_MAX_LEN_RX_TX_CFG0_MASK 0x3FFF + +#define RTL8367C_REG_MAX_LEN_RX_TX_CFG1 0x088d +#define RTL8367C_MAX_LEN_RX_TX_CFG1_OFFSET 0 +#define RTL8367C_MAX_LEN_RX_TX_CFG1_MASK 0x3FFF + +#define RTL8367C_REG_UNDA_FLOODING_PMSK 0x0890 +#define RTL8367C_UNDA_FLOODING_PMSK_OFFSET 0 +#define RTL8367C_UNDA_FLOODING_PMSK_MASK 0x7FF + +#define RTL8367C_REG_UNMCAST_FLOADING_PMSK 0x0891 +#define RTL8367C_UNMCAST_FLOADING_PMSK_OFFSET 0 +#define RTL8367C_UNMCAST_FLOADING_PMSK_MASK 0x7FF + +#define RTL8367C_REG_BCAST_FLOADING_PMSK 0x0892 +#define RTL8367C_BCAST_FLOADING_PMSK_OFFSET 0 +#define RTL8367C_BCAST_FLOADING_PMSK_MASK 0x7FF + +#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2 0x08a0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_OFFSET 14 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH7_MASK 0xC000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_OFFSET 12 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH6_MASK 0x3000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_OFFSET 10 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH5_MASK 0xC00 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_OFFSET 8 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH4_MASK 0x300 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_OFFSET 6 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH3_MASK 0xC0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_OFFSET 4 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH2_MASK 0x30 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_OFFSET 2 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH1_MASK 0xC +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_OFFSET 0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK 0x3 + +#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3 0x08a1 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_OFFSET 14 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH15_MASK 0xC000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_OFFSET 12 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH14_MASK 0x3000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_OFFSET 10 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH13_MASK 0xC00 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_OFFSET 8 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH12_MASK 0x300 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_OFFSET 6 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH11_MASK 0xC0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_OFFSET 4 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH10_MASK 0x30 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_OFFSET 2 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH9_MASK 0xC +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_OFFSET 0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK 0x3 + +#define RTL8367C_REG_PORT_ISOLATION_PORT0_MASK 0x08a2 +#define RTL8367C_PORT_ISOLATION_PORT0_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT0_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT1_MASK 0x08a3 +#define RTL8367C_PORT_ISOLATION_PORT1_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT1_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT2_MASK 0x08a4 +#define RTL8367C_PORT_ISOLATION_PORT2_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT2_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT3_MASK 0x08a5 +#define RTL8367C_PORT_ISOLATION_PORT3_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT3_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT4_MASK 0x08a6 +#define RTL8367C_PORT_ISOLATION_PORT4_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT4_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT5_MASK 0x08a7 +#define RTL8367C_PORT_ISOLATION_PORT5_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT5_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT6_MASK 0x08a8 +#define RTL8367C_PORT_ISOLATION_PORT6_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT6_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT7_MASK 0x08a9 +#define RTL8367C_PORT_ISOLATION_PORT7_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT7_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT8_MASK 0x08aa +#define RTL8367C_PORT_ISOLATION_PORT8_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT8_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT9_MASK 0x08ab +#define RTL8367C_PORT_ISOLATION_PORT9_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT9_MASK_MASK 0x7FF + +#define RTL8367C_REG_PORT_ISOLATION_PORT10_MASK 0x08ac +#define RTL8367C_PORT_ISOLATION_PORT10_MASK_OFFSET 0 +#define RTL8367C_PORT_ISOLATION_PORT10_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_CTRL 0x08b4 +#define RTL8367C_FORCE_CTRL_OFFSET 0 +#define RTL8367C_FORCE_CTRL_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT0_MASK 0x08b5 +#define RTL8367C_FORCE_PORT0_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT0_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT1_MASK 0x08b6 +#define RTL8367C_FORCE_PORT1_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT1_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT2_MASK 0x08b7 +#define RTL8367C_FORCE_PORT2_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT2_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT3_MASK 0x08b8 +#define RTL8367C_FORCE_PORT3_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT3_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT4_MASK 0x08b9 +#define RTL8367C_FORCE_PORT4_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT4_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT5_MASK 0x08ba +#define RTL8367C_FORCE_PORT5_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT5_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT6_MASK 0x08bb +#define RTL8367C_FORCE_PORT6_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT6_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT7_MASK 0x08bc +#define RTL8367C_FORCE_PORT7_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT7_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT8_MASK 0x08bd +#define RTL8367C_FORCE_PORT8_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT8_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT9_MASK 0x08be +#define RTL8367C_FORCE_PORT9_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT9_MASK_MASK 0x7FF + +#define RTL8367C_REG_FORCE_PORT10_MASK 0x08bf +#define RTL8367C_FORCE_PORT10_MASK_OFFSET 0 +#define RTL8367C_FORCE_PORT10_MASK_MASK 0x7FF + +#define RTL8367C_REG_SOURCE_PORT_PERMIT 0x08c5 +#define RTL8367C_SOURCE_PORT_PERMIT_OFFSET 0 +#define RTL8367C_SOURCE_PORT_PERMIT_MASK 0x7FF + +#define RTL8367C_REG_IPMCAST_VLAN_LEAKY 0x08c6 +#define RTL8367C_IPMCAST_VLAN_LEAKY_OFFSET 0 +#define RTL8367C_IPMCAST_VLAN_LEAKY_MASK 0x7FF + +#define RTL8367C_REG_IPMCAST_PORTISO_LEAKY 0x08c7 +#define RTL8367C_IPMCAST_PORTISO_LEAKY_OFFSET 0 +#define RTL8367C_IPMCAST_PORTISO_LEAKY_MASK 0x7FF + +#define RTL8367C_REG_PORT_SECURITY_CTRL 0x08c8 +#define RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_OFFSET 6 +#define RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK 0xC0 +#define RTL8367C_LUT_LEARN_OVER_ACT_OFFSET 4 +#define RTL8367C_LUT_LEARN_OVER_ACT_MASK 0x30 +#define RTL8367C_UNMATCHED_SA_BEHAVE_OFFSET 2 +#define RTL8367C_UNMATCHED_SA_BEHAVE_MASK 0xC +#define RTL8367C_UNKNOWN_SA_BEHAVE_OFFSET 0 +#define RTL8367C_UNKNOWN_SA_BEHAVE_MASK 0x3 + +#define RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL0 0x08c9 +#define RTL8367C_PORT7_UNKNOWN_IP4_MCAST_OFFSET 14 +#define RTL8367C_PORT7_UNKNOWN_IP4_MCAST_MASK 0xC000 +#define RTL8367C_PORT6_UNKNOWN_IP4_MCAST_OFFSET 12 +#define RTL8367C_PORT6_UNKNOWN_IP4_MCAST_MASK 0x3000 +#define RTL8367C_PORT5_UNKNOWN_IP4_MCAST_OFFSET 10 +#define RTL8367C_PORT5_UNKNOWN_IP4_MCAST_MASK 0xC00 +#define RTL8367C_PORT4_UNKNOWN_IP4_MCAST_OFFSET 8 +#define RTL8367C_PORT4_UNKNOWN_IP4_MCAST_MASK 0x300 +#define RTL8367C_PORT3_UNKNOWN_IP4_MCAST_OFFSET 6 +#define RTL8367C_PORT3_UNKNOWN_IP4_MCAST_MASK 0xC0 +#define RTL8367C_PORT2_UNKNOWN_IP4_MCAST_OFFSET 4 +#define RTL8367C_PORT2_UNKNOWN_IP4_MCAST_MASK 0x30 +#define RTL8367C_PORT1_UNKNOWN_IP4_MCAST_OFFSET 2 +#define RTL8367C_PORT1_UNKNOWN_IP4_MCAST_MASK 0xC +#define RTL8367C_PORT0_UNKNOWN_IP4_MCAST_OFFSET 0 +#define RTL8367C_PORT0_UNKNOWN_IP4_MCAST_MASK 0x3 + +#define RTL8367C_REG_UNKNOWN_IPV4_MULTICAST_CTRL1 0x08ca +#define RTL8367C_PORT10_UNKNOWN_IP4_MCAST_OFFSET 4 +#define RTL8367C_PORT10_UNKNOWN_IP4_MCAST_MASK 0x30 +#define RTL8367C_PORT9_UNKNOWN_IP4_MCAST_OFFSET 2 +#define RTL8367C_PORT9_UNKNOWN_IP4_MCAST_MASK 0xC +#define RTL8367C_PORT8_UNKNOWN_IP4_MCAST_OFFSET 0 +#define RTL8367C_PORT8_UNKNOWN_IP4_MCAST_MASK 0x3 + +#define RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL0 0x08cb +#define RTL8367C_PORT7_UNKNOWN_IP6_MCAST_OFFSET 14 +#define RTL8367C_PORT7_UNKNOWN_IP6_MCAST_MASK 0xC000 +#define RTL8367C_PORT6_UNKNOWN_IP6_MCAST_OFFSET 12 +#define RTL8367C_PORT6_UNKNOWN_IP6_MCAST_MASK 0x3000 +#define RTL8367C_PORT5_UNKNOWN_IP6_MCAST_OFFSET 10 +#define RTL8367C_PORT5_UNKNOWN_IP6_MCAST_MASK 0xC00 +#define RTL8367C_PORT4_UNKNOWN_IP6_MCAST_OFFSET 8 +#define RTL8367C_PORT4_UNKNOWN_IP6_MCAST_MASK 0x300 +#define RTL8367C_PORT3_UNKNOWN_IP6_MCAST_OFFSET 6 +#define RTL8367C_PORT3_UNKNOWN_IP6_MCAST_MASK 0xC0 +#define RTL8367C_PORT2_UNKNOWN_IP6_MCAST_OFFSET 4 +#define RTL8367C_PORT2_UNKNOWN_IP6_MCAST_MASK 0x30 +#define RTL8367C_PORT1_UNKNOWN_IP6_MCAST_OFFSET 2 +#define RTL8367C_PORT1_UNKNOWN_IP6_MCAST_MASK 0xC +#define RTL8367C_PORT0_UNKNOWN_IP6_MCAST_OFFSET 0 +#define RTL8367C_PORT0_UNKNOWN_IP6_MCAST_MASK 0x3 + +#define RTL8367C_REG_UNKNOWN_IPV6_MULTICAST_CTRL1 0x08cc +#define RTL8367C_PORT10_UNKNOWN_IP6_MCAST_OFFSET 4 +#define RTL8367C_PORT10_UNKNOWN_IP6_MCAST_MASK 0x30 +#define RTL8367C_PORT9_UNKNOWN_IP6_MCAST_OFFSET 2 +#define RTL8367C_PORT9_UNKNOWN_IP6_MCAST_MASK 0xC +#define RTL8367C_PORT8_UNKNOWN_IP6_MCAST_OFFSET 0 +#define RTL8367C_PORT8_UNKNOWN_IP6_MCAST_MASK 0x3 + +#define RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL0 0x08cd +#define RTL8367C_PORT7_UNKNOWN_L2_MCAST_OFFSET 14 +#define RTL8367C_PORT7_UNKNOWN_L2_MCAST_MASK 0xC000 +#define RTL8367C_PORT6_UNKNOWN_L2_MCAST_OFFSET 12 +#define RTL8367C_PORT6_UNKNOWN_L2_MCAST_MASK 0x3000 +#define RTL8367C_PORT5_UNKNOWN_L2_MCAST_OFFSET 10 +#define RTL8367C_PORT5_UNKNOWN_L2_MCAST_MASK 0xC00 +#define RTL8367C_PORT4_UNKNOWN_L2_MCAST_OFFSET 8 +#define RTL8367C_PORT4_UNKNOWN_L2_MCAST_MASK 0x300 +#define RTL8367C_PORT3_UNKNOWN_L2_MCAST_OFFSET 6 +#define RTL8367C_PORT3_UNKNOWN_L2_MCAST_MASK 0xC0 +#define RTL8367C_PORT2_UNKNOWN_L2_MCAST_OFFSET 4 +#define RTL8367C_PORT2_UNKNOWN_L2_MCAST_MASK 0x30 +#define RTL8367C_PORT1_UNKNOWN_L2_MCAST_OFFSET 2 +#define RTL8367C_PORT1_UNKNOWN_L2_MCAST_MASK 0xC +#define RTL8367C_PORT0_UNKNOWN_L2_MCAST_OFFSET 0 +#define RTL8367C_PORT0_UNKNOWN_L2_MCAST_MASK 0x3 + +#define RTL8367C_REG_PORT_TRUNK_DROP_CTRL 0x08ce +#define RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET 0 +#define RTL8367C_PORT_TRUNK_DROP_CTRL_MASK 0x1 + +#define RTL8367C_REG_PORT_TRUNK_CTRL 0x08cf +#define RTL8367C_PORT_TRUNK_DUMB_OFFSET 8 +#define RTL8367C_PORT_TRUNK_DUMB_MASK 0x100 +#define RTL8367C_PORT_TRUNK_FLOOD_OFFSET 7 +#define RTL8367C_PORT_TRUNK_FLOOD_MASK 0x80 +#define RTL8367C_DPORT_HASH_OFFSET 6 +#define RTL8367C_DPORT_HASH_MASK 0x40 +#define RTL8367C_SPORT_HASH_OFFSET 5 +#define RTL8367C_SPORT_HASH_MASK 0x20 +#define RTL8367C_DIP_HASH_OFFSET 4 +#define RTL8367C_DIP_HASH_MASK 0x10 +#define RTL8367C_SIP_HASH_OFFSET 3 +#define RTL8367C_SIP_HASH_MASK 0x8 +#define RTL8367C_DMAC_HASH_OFFSET 2 +#define RTL8367C_DMAC_HASH_MASK 0x4 +#define RTL8367C_SMAC_HASH_OFFSET 1 +#define RTL8367C_SMAC_HASH_MASK 0x2 +#define RTL8367C_SPA_HASH_OFFSET 0 +#define RTL8367C_SPA_HASH_MASK 0x1 + +#define RTL8367C_REG_PORT_TRUNK_GROUP_MASK 0x08d0 +#define RTL8367C_PORT_TRUNK_GROUP2_MASK_OFFSET 8 +#define RTL8367C_PORT_TRUNK_GROUP2_MASK_MASK 0x300 +#define RTL8367C_PORT_TRUNK_GROUP1_MASK_OFFSET 4 +#define RTL8367C_PORT_TRUNK_GROUP1_MASK_MASK 0xF0 +#define RTL8367C_PORT_TRUNK_GROUP0_MASK_OFFSET 0 +#define RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK 0xF + +#define RTL8367C_REG_PORT_TRUNK_FLOWCTRL 0x08d1 +#define RTL8367C_EN_FLOWCTRL_TG2_OFFSET 2 +#define RTL8367C_EN_FLOWCTRL_TG2_MASK 0x4 +#define RTL8367C_EN_FLOWCTRL_TG1_OFFSET 1 +#define RTL8367C_EN_FLOWCTRL_TG1_MASK 0x2 +#define RTL8367C_EN_FLOWCTRL_TG0_OFFSET 0 +#define RTL8367C_EN_FLOWCTRL_TG0_MASK 0x1 + +#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0 0x08d2 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_OFFSET 14 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH7_MASK 0xC000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_OFFSET 12 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH6_MASK 0x3000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_OFFSET 10 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH5_MASK 0xC00 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_OFFSET 8 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH4_MASK 0x300 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_OFFSET 6 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH3_MASK 0xC0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_OFFSET 4 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH2_MASK 0x30 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_OFFSET 2 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH1_MASK 0xC +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_OFFSET 0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK 0x3 + +#define RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1 0x08d3 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_OFFSET 14 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH15_MASK 0xC000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_OFFSET 12 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH14_MASK 0x3000 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_OFFSET 10 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH13_MASK 0xC00 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_OFFSET 8 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH12_MASK 0x300 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_OFFSET 6 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH11_MASK 0xC0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_OFFSET 4 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH10_MASK 0x30 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_OFFSET 2 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH9_MASK 0xC +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_OFFSET 0 +#define RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK 0x3 + +#define RTL8367C_REG_DOS_CFG 0x08d4 +#define RTL8367C_DROP_ICMPFRAGMENT_OFFSET 9 +#define RTL8367C_DROP_ICMPFRAGMENT_MASK 0x200 +#define RTL8367C_DROP_TCPFRAGERROR_OFFSET 8 +#define RTL8367C_DROP_TCPFRAGERROR_MASK 0x100 +#define RTL8367C_DROP_TCPSHORTHDR_OFFSET 7 +#define RTL8367C_DROP_TCPSHORTHDR_MASK 0x80 +#define RTL8367C_DROP_SYN1024_OFFSET 6 +#define RTL8367C_DROP_SYN1024_MASK 0x40 +#define RTL8367C_DROP_NULLSCAN_OFFSET 5 +#define RTL8367C_DROP_NULLSCAN_MASK 0x20 +#define RTL8367C_DROP_XMASCAN_OFFSET 4 +#define RTL8367C_DROP_XMASCAN_MASK 0x10 +#define RTL8367C_DROP_SYNFINSCAN_OFFSET 3 +#define RTL8367C_DROP_SYNFINSCAN_MASK 0x8 +#define RTL8367C_DROP_BLATATTACKS_OFFSET 2 +#define RTL8367C_DROP_BLATATTACKS_MASK 0x4 +#define RTL8367C_DROP_LANDATTACKS_OFFSET 1 +#define RTL8367C_DROP_LANDATTACKS_MASK 0x2 +#define RTL8367C_DROP_DAEQSA_OFFSET 0 +#define RTL8367C_DROP_DAEQSA_MASK 0x1 + +#define RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1 0x08d5 +#define RTL8367C_PORT10_UNKNOWN_L2_MCAST_OFFSET 4 +#define RTL8367C_PORT10_UNKNOWN_L2_MCAST_MASK 0x30 +#define RTL8367C_PORT9_UNKNOWN_L2_MCAST_OFFSET 2 +#define RTL8367C_PORT9_UNKNOWN_L2_MCAST_MASK 0xC +#define RTL8367C_PORT8_UNKNOWN_L2_MCAST_OFFSET 0 +#define RTL8367C_PORT8_UNKNOWN_L2_MCAST_MASK 0x3 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4 0x08d6 +#define RTL8367C_PORT9_VLAN_KEEP_MASK_OFFSET 8 +#define RTL8367C_PORT9_VLAN_KEEP_MASK_MASK 0xFF00 +#define RTL8367C_PORT8_VLAN_KEEP_MASK_OFFSET 0 +#define RTL8367C_PORT8_VLAN_KEEP_MASK_MASK 0xFF + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5 0x08d7 +#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK 0xFF + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT 0x08d8 +#define RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_OFFSET 3 +#define RTL8367C_PORT1_VLAN_KEEP_MASK_EXT_MASK 0x38 +#define RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_OFFSET 0 +#define RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1_EXT 0x08d9 +#define RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_OFFSET 3 +#define RTL8367C_PORT3_VLAN_KEEP_MASK_EXT_MASK 0x38 +#define RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_OFFSET 0 +#define RTL8367C_PORT2_VLAN_KEEP_MASK_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2_EXT 0x08da +#define RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_OFFSET 3 +#define RTL8367C_PORT5_VLAN_KEEP_MASK_EXT_MASK 0x38 +#define RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_OFFSET 0 +#define RTL8367C_PORT4_VLAN_KEEP_MASK_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3_EXT 0x08db +#define RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_OFFSET 3 +#define RTL8367C_PORT7_VLAN_KEEP_MASK_EXT_MASK 0x38 +#define RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_OFFSET 0 +#define RTL8367C_PORT6_VLAN_KEEP_MASK_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT 0x08dc +#define RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_OFFSET 3 +#define RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK 0x38 +#define RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_OFFSET 0 +#define RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT 0x08dd +#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK 0x7 + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL10 0x08de +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL10_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL10_MASK 0x7FF + +#define RTL8367C_REG_FPGA_VER_CEN 0x08e0 + +#define RTL8367C_REG_FPGA_TIME_CEN 0x08e1 + +#define RTL8367C_REG_FPGA_DATE_CEN 0x08e2 + +#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL0 0x0900 +#define RTL8367C_PORT3_NUMBER_OFFSET 12 +#define RTL8367C_PORT3_NUMBER_MASK 0x7000 +#define RTL8367C_PORT2_NUMBER_OFFSET 8 +#define RTL8367C_PORT2_NUMBER_MASK 0x700 +#define RTL8367C_PORT1_NUMBER_OFFSET 4 +#define RTL8367C_PORT1_NUMBER_MASK 0x70 +#define RTL8367C_PORT0_NUMBER_OFFSET 0 +#define RTL8367C_PORT0_NUMBER_MASK 0x7 + +#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL1 0x0901 +#define RTL8367C_PORT7_NUMBER_OFFSET 12 +#define RTL8367C_PORT7_NUMBER_MASK 0x7000 +#define RTL8367C_PORT6_NUMBER_OFFSET 8 +#define RTL8367C_PORT6_NUMBER_MASK 0x700 +#define RTL8367C_PORT5_NUMBER_OFFSET 4 +#define RTL8367C_PORT5_NUMBER_MASK 0x70 +#define RTL8367C_PORT4_NUMBER_OFFSET 0 +#define RTL8367C_PORT4_NUMBER_MASK 0x7 + +#define RTL8367C_REG_QOS_PORT_QUEUE_NUMBER_CTRL2 0x0902 +#define RTL8367C_PORT10_NUMBER_OFFSET 8 +#define RTL8367C_PORT10_NUMBER_MASK 0x700 +#define RTL8367C_PORT9_NUMBER_OFFSET 4 +#define RTL8367C_PORT9_NUMBER_MASK 0x70 +#define RTL8367C_PORT8_NUMBER_OFFSET 0 +#define RTL8367C_PORT8_NUMBER_MASK 0x7 + +#define RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL0 0x0904 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_1Q_PRIORITY_TO_QID_CTRL1 0x0905 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_1Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL0 0x0906 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_2Q_PRIORITY_TO_QID_CTRL1 0x0907 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_2Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL0 0x0908 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_3Q_PRIORITY_TO_QID_CTRL1 0x0909 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_3Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL0 0x090a +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_4Q_PRIORITY_TO_QID_CTRL1 0x090b +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_4Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL0 0x090c +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_5Q_PRIORITY_TO_QID_CTRL1 0x090d +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_5Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL0 0x090e +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_6Q_PRIORITY_TO_QID_CTRL1 0x090f +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_6Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL0 0x0910 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_7Q_PRIORITY_TO_QID_CTRL1 0x0911 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_7Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL0 0x0912 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_OFFSET 12 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY3_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_OFFSET 8 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY2_TO_QID_MASK 0x700 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_OFFSET 4 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY1_TO_QID_MASK 0x70 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_OFFSET 0 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL0_PRIORITY0_TO_QID_MASK 0x7 + +#define RTL8367C_REG_QOS_8Q_PRIORITY_TO_QID_CTRL1 0x0913 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_OFFSET 12 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY7_TO_QID_MASK 0x7000 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_OFFSET 8 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY6_TO_QID_MASK 0x700 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_OFFSET 4 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY5_TO_QID_MASK 0x70 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_OFFSET 0 +#define RTL8367C_QOS_8Q_PRIORITY_TO_QID_CTRL1_PRIORITY4_TO_QID_MASK 0x7 + +#define RTL8367C_REG_HIGHPRI_INDICATOR 0x0915 +#define RTL8367C_PORT10_INDICATOR_OFFSET 10 +#define RTL8367C_PORT10_INDICATOR_MASK 0x400 +#define RTL8367C_PORT9_INDICATOR_OFFSET 9 +#define RTL8367C_PORT9_INDICATOR_MASK 0x200 +#define RTL8367C_PORT8_INDICATOR_OFFSET 8 +#define RTL8367C_PORT8_INDICATOR_MASK 0x100 +#define RTL8367C_PORT7_INDICATOR_OFFSET 7 +#define RTL8367C_PORT7_INDICATOR_MASK 0x80 +#define RTL8367C_PORT6_INDICATOR_OFFSET 6 +#define RTL8367C_PORT6_INDICATOR_MASK 0x40 +#define RTL8367C_PORT5_INDICATOR_OFFSET 5 +#define RTL8367C_PORT5_INDICATOR_MASK 0x20 +#define RTL8367C_PORT4_INDICATOR_OFFSET 4 +#define RTL8367C_PORT4_INDICATOR_MASK 0x10 +#define RTL8367C_PORT3_INDICATOR_OFFSET 3 +#define RTL8367C_PORT3_INDICATOR_MASK 0x8 +#define RTL8367C_PORT2_INDICATOR_OFFSET 2 +#define RTL8367C_PORT2_INDICATOR_MASK 0x4 +#define RTL8367C_PORT1_INDICATOR_OFFSET 1 +#define RTL8367C_PORT1_INDICATOR_MASK 0x2 +#define RTL8367C_PORT0_INDICATOR_OFFSET 0 +#define RTL8367C_PORT0_INDICATOR_MASK 0x1 + +#define RTL8367C_REG_HIGHPRI_CFG 0x0916 +#define RTL8367C_HIGHPRI_CFG_OFFSET 0 +#define RTL8367C_HIGHPRI_CFG_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL0 0x0917 +#define RTL8367C_PORT1_DEBUG_INFO_OFFSET 8 +#define RTL8367C_PORT1_DEBUG_INFO_MASK 0xFF00 +#define RTL8367C_PORT0_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT0_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL1 0x0918 +#define RTL8367C_PORT3_DEBUG_INFO_OFFSET 8 +#define RTL8367C_PORT3_DEBUG_INFO_MASK 0xFF00 +#define RTL8367C_PORT2_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT2_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL2 0x0919 +#define RTL8367C_PORT5_DEBUG_INFO_OFFSET 8 +#define RTL8367C_PORT5_DEBUG_INFO_MASK 0xFF00 +#define RTL8367C_PORT4_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT4_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL3 0x091a +#define RTL8367C_PORT7_DEBUG_INFO_OFFSET 8 +#define RTL8367C_PORT7_DEBUG_INFO_MASK 0xFF00 +#define RTL8367C_PORT6_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT6_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL4 0x091b +#define RTL8367C_PORT9_DEBUG_INFO_OFFSET 8 +#define RTL8367C_PORT9_DEBUG_INFO_MASK 0xFF00 +#define RTL8367C_PORT8_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT8_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL5 0x091c +#define RTL8367C_PORT10_DEBUG_INFO_OFFSET 0 +#define RTL8367C_PORT10_DEBUG_INFO_MASK 0xFF + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL6 0x091d +#define RTL8367C_PORT7_DEBUG_INDICATOR_OFFSET 14 +#define RTL8367C_PORT7_DEBUG_INDICATOR_MASK 0xC000 +#define RTL8367C_PORT6_DEBUG_INDICATOR_OFFSET 12 +#define RTL8367C_PORT6_DEBUG_INDICATOR_MASK 0x3000 +#define RTL8367C_PORT5_DEBUG_INDICATOR_OFFSET 10 +#define RTL8367C_PORT5_DEBUG_INDICATOR_MASK 0xC00 +#define RTL8367C_PORT4_DEBUG_INDICATOR_OFFSET 8 +#define RTL8367C_PORT4_DEBUG_INDICATOR_MASK 0x300 +#define RTL8367C_PORT3_DEBUG_INDICATOR_OFFSET 6 +#define RTL8367C_PORT3_DEBUG_INDICATOR_MASK 0xC0 +#define RTL8367C_PORT2_DEBUG_INDICATOR_OFFSET 4 +#define RTL8367C_PORT2_DEBUG_INDICATOR_MASK 0x30 +#define RTL8367C_PORT1_DEBUG_INDICATOR_OFFSET 2 +#define RTL8367C_PORT1_DEBUG_INDICATOR_MASK 0xC +#define RTL8367C_PORT0_DEBUG_INDICATOR_OFFSET 0 +#define RTL8367C_PORT0_DEBUG_INDICATOR_MASK 0x3 + +#define RTL8367C_REG_PORT_DEBUG_INFO_CTRL7 0x091e +#define RTL8367C_PORT10_DEBUG_INDICATOR_OFFSET 4 +#define RTL8367C_PORT10_DEBUG_INDICATOR_MASK 0x30 +#define RTL8367C_PORT9_DEBUG_INDICATOR_OFFSET 2 +#define RTL8367C_PORT9_DEBUG_INDICATOR_MASK 0xC +#define RTL8367C_PORT8_DEBUG_INDICATOR_OFFSET 0 +#define RTL8367C_PORT8_DEBUG_INDICATOR_MASK 0x3 + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL0 0x0930 +#define RTL8367C_PORT1_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT1_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT0_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT0_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL1 0x0931 +#define RTL8367C_PORT3_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT3_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT2_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT2_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL2 0x0932 +#define RTL8367C_PORT5_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT5_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT4_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT4_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL3 0x0933 +#define RTL8367C_PORT7_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT7_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT6_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT6_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL4 0x0934 +#define RTL8367C_PORT9_QUEUE_MASK_OFFSET 8 +#define RTL8367C_PORT9_QUEUE_MASK_MASK 0xFF00 +#define RTL8367C_PORT8_QUEUE_MASK_OFFSET 0 +#define RTL8367C_PORT8_QUEUE_MASK_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5 0x0935 +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_OFFSET 0 +#define RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_CTRL5_MASK 0xFF + +#define RTL8367C_REG_FLOWCRTL_EGRESS_PORT_ENABLE 0x0938 +#define RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_OFFSET 0 +#define RTL8367C_FLOWCRTL_EGRESS_PORT_ENABLE_MASK 0xFF + +#define RTL8367C_REG_EAV_CTRL 0x0939 +#define RTL8367C_EAV_TRAP_CPU_OFFSET 1 +#define RTL8367C_EAV_TRAP_CPU_MASK 0x2 +#define RTL8367C_EAV_TRAP_8051_OFFSET 0 +#define RTL8367C_EAV_TRAP_8051_MASK 0x1 + +#define RTL8367C_REG_UNTAG_DSCP_PRI_CFG 0x093a +#define RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET 0 +#define RTL8367C_UNTAG_DSCP_PRI_CFG_MASK 0x1 + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 0x093b +#define RTL8367C_PORT1_VLAN_KEEP_MASK_OFFSET 8 +#define RTL8367C_PORT1_VLAN_KEEP_MASK_MASK 0xFF00 +#define RTL8367C_PORT0_VLAN_KEEP_MASK_OFFSET 0 +#define RTL8367C_PORT0_VLAN_KEEP_MASK_MASK 0xFF + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL1 0x093c +#define RTL8367C_PORT3_VLAN_KEEP_MASK_OFFSET 8 +#define RTL8367C_PORT3_VLAN_KEEP_MASK_MASK 0xFF00 +#define RTL8367C_PORT2_VLAN_KEEP_MASK_OFFSET 0 +#define RTL8367C_PORT2_VLAN_KEEP_MASK_MASK 0xFF + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL2 0x093d +#define RTL8367C_PORT5_VLAN_KEEP_MASK_OFFSET 8 +#define RTL8367C_PORT5_VLAN_KEEP_MASK_MASK 0xFF00 +#define RTL8367C_PORT4_VLAN_KEEP_MASK_OFFSET 0 +#define RTL8367C_PORT4_VLAN_KEEP_MASK_MASK 0xFF + +#define RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL3 0x093e +#define RTL8367C_PORT7_VLAN_KEEP_MASK_OFFSET 8 +#define RTL8367C_PORT7_VLAN_KEEP_MASK_MASK 0xFF00 +#define RTL8367C_PORT6_VLAN_KEEP_MASK_OFFSET 0 +#define RTL8367C_PORT6_VLAN_KEEP_MASK_MASK 0xFF + +#define RTL8367C_REG_VLAN_TRANSPARENT_EN_CFG 0x093f +#define RTL8367C_VLAN_TRANSPARENT_EN_CFG_OFFSET 0 +#define RTL8367C_VLAN_TRANSPARENT_EN_CFG_MASK 0x1 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY0_H 0x0940 +#define RTL8367C_IPMC_GROUP_ENTRY0_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY0_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY0_L 0x0941 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY1_H 0x0942 +#define RTL8367C_IPMC_GROUP_ENTRY1_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY1_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY1_L 0x0943 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY2_H 0x0944 +#define RTL8367C_IPMC_GROUP_ENTRY2_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY2_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY2_L 0x0945 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY3_H 0x0946 +#define RTL8367C_IPMC_GROUP_ENTRY3_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY3_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY3_L 0x0947 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY4_H 0x0948 +#define RTL8367C_IPMC_GROUP_ENTRY4_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY4_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY4_L 0x0949 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY5_H 0x094a +#define RTL8367C_IPMC_GROUP_ENTRY5_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY5_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY5_L 0x094b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY6_H 0x094c +#define RTL8367C_IPMC_GROUP_ENTRY6_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY6_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY6_L 0x094d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY7_H 0x094e +#define RTL8367C_IPMC_GROUP_ENTRY7_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY7_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY7_L 0x094f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY8_H 0x0950 +#define RTL8367C_IPMC_GROUP_ENTRY8_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY8_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY8_L 0x0951 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY9_H 0x0952 +#define RTL8367C_IPMC_GROUP_ENTRY9_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY9_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY9_L 0x0953 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY10_H 0x0954 +#define RTL8367C_IPMC_GROUP_ENTRY10_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY10_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY10_L 0x0955 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY11_H 0x0956 +#define RTL8367C_IPMC_GROUP_ENTRY11_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY11_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY11_L 0x0957 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY12_H 0x0958 +#define RTL8367C_IPMC_GROUP_ENTRY12_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY12_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY12_L 0x0959 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY13_H 0x095a +#define RTL8367C_IPMC_GROUP_ENTRY13_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY13_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY13_L 0x095b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY14_H 0x095c +#define RTL8367C_IPMC_GROUP_ENTRY14_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY14_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY14_L 0x095d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY15_H 0x095e +#define RTL8367C_IPMC_GROUP_ENTRY15_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY15_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY15_L 0x095f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY16_H 0x0960 +#define RTL8367C_IPMC_GROUP_ENTRY16_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY16_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY16_L 0x0961 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY17_H 0x0962 +#define RTL8367C_IPMC_GROUP_ENTRY17_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY17_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY17_L 0x0963 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY18_H 0x0964 +#define RTL8367C_IPMC_GROUP_ENTRY18_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY18_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY18_L 0x0965 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY19_H 0x0966 +#define RTL8367C_IPMC_GROUP_ENTRY19_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY19_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY19_L 0x0967 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY20_H 0x0968 +#define RTL8367C_IPMC_GROUP_ENTRY20_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY20_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY20_L 0x0969 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY21_H 0x096a +#define RTL8367C_IPMC_GROUP_ENTRY21_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY21_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY21_L 0x096b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY22_H 0x096c +#define RTL8367C_IPMC_GROUP_ENTRY22_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY22_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY22_L 0x096d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY23_H 0x096e +#define RTL8367C_IPMC_GROUP_ENTRY23_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY23_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY23_L 0x096f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY24_H 0x0970 +#define RTL8367C_IPMC_GROUP_ENTRY24_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY24_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY24_L 0x0971 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY25_H 0x0972 +#define RTL8367C_IPMC_GROUP_ENTRY25_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY25_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY25_L 0x0973 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY26_H 0x0974 +#define RTL8367C_IPMC_GROUP_ENTRY26_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY26_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY26_L 0x0975 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY27_H 0x0976 +#define RTL8367C_IPMC_GROUP_ENTRY27_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY27_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY27_L 0x0977 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY28_H 0x0978 +#define RTL8367C_IPMC_GROUP_ENTRY28_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY28_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY28_L 0x0979 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY29_H 0x097a +#define RTL8367C_IPMC_GROUP_ENTRY29_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY29_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY29_L 0x097b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY30_H 0x097c +#define RTL8367C_IPMC_GROUP_ENTRY30_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY30_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY30_L 0x097d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY31_H 0x097e +#define RTL8367C_IPMC_GROUP_ENTRY31_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY31_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY31_L 0x097f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY32_H 0x0980 +#define RTL8367C_IPMC_GROUP_ENTRY32_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY32_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY32_L 0x0981 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY33_H 0x0982 +#define RTL8367C_IPMC_GROUP_ENTRY33_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY33_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY33_L 0x0983 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY34_H 0x0984 +#define RTL8367C_IPMC_GROUP_ENTRY34_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY34_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY34_L 0x0985 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY35_H 0x0986 +#define RTL8367C_IPMC_GROUP_ENTRY35_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY35_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY35_L 0x0987 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY36_H 0x0988 +#define RTL8367C_IPMC_GROUP_ENTRY36_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY36_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY36_L 0x0989 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY37_H 0x098a +#define RTL8367C_IPMC_GROUP_ENTRY37_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY37_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY37_L 0x098b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY38_H 0x098c +#define RTL8367C_IPMC_GROUP_ENTRY38_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY38_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY38_L 0x098d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY39_H 0x098e +#define RTL8367C_IPMC_GROUP_ENTRY39_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY39_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY39_L 0x098f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY40_H 0x0990 +#define RTL8367C_IPMC_GROUP_ENTRY40_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY40_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY40_L 0x0991 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY41_H 0x0992 +#define RTL8367C_IPMC_GROUP_ENTRY41_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY41_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY41_L 0x0993 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY42_H 0x0994 +#define RTL8367C_IPMC_GROUP_ENTRY42_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY42_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY42_L 0x0995 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY43_H 0x0996 +#define RTL8367C_IPMC_GROUP_ENTRY43_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY43_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY43_L 0x0997 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY44_H 0x0998 +#define RTL8367C_IPMC_GROUP_ENTRY44_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY44_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY44_L 0x0999 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY45_H 0x099a +#define RTL8367C_IPMC_GROUP_ENTRY45_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY45_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY45_L 0x099b + +#define RTL8367C_REG_IPMC_GROUP_ENTRY46_H 0x099c +#define RTL8367C_IPMC_GROUP_ENTRY46_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY46_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY46_L 0x099d + +#define RTL8367C_REG_IPMC_GROUP_ENTRY47_H 0x099e +#define RTL8367C_IPMC_GROUP_ENTRY47_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY47_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY47_L 0x099f + +#define RTL8367C_REG_IPMC_GROUP_ENTRY48_H 0x09a0 +#define RTL8367C_IPMC_GROUP_ENTRY48_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY48_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY48_L 0x09a1 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY49_H 0x09a2 +#define RTL8367C_IPMC_GROUP_ENTRY49_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY49_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY49_L 0x09a3 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY50_H 0x09a4 +#define RTL8367C_IPMC_GROUP_ENTRY50_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY50_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY50_L 0x09a5 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY51_H 0x09a6 +#define RTL8367C_IPMC_GROUP_ENTRY51_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY51_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY51_L 0x09a7 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY52_H 0x09a8 +#define RTL8367C_IPMC_GROUP_ENTRY52_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY52_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY52_L 0x09a9 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY53_H 0x09aa +#define RTL8367C_IPMC_GROUP_ENTRY53_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY53_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY53_L 0x09ab + +#define RTL8367C_REG_IPMC_GROUP_ENTRY54_H 0x09ac +#define RTL8367C_IPMC_GROUP_ENTRY54_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY54_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY54_L 0x09ad + +#define RTL8367C_REG_IPMC_GROUP_ENTRY55_H 0x09ae +#define RTL8367C_IPMC_GROUP_ENTRY55_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY55_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY55_L 0x09af + +#define RTL8367C_REG_IPMC_GROUP_ENTRY56_H 0x09b0 +#define RTL8367C_IPMC_GROUP_ENTRY56_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY56_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY56_L 0x09b1 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY57_H 0x09b2 +#define RTL8367C_IPMC_GROUP_ENTRY57_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY57_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY57_L 0x09b3 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY58_H 0x09b4 +#define RTL8367C_IPMC_GROUP_ENTRY58_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY58_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY58_L 0x09b5 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY59_H 0x09b6 +#define RTL8367C_IPMC_GROUP_ENTRY59_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY59_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY59_L 0x09b7 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY60_H 0x09b8 +#define RTL8367C_IPMC_GROUP_ENTRY60_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY60_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY60_L 0x09b9 + +#define RTL8367C_REG_IPMC_GROUP_ENTRY61_H 0x09ba +#define RTL8367C_IPMC_GROUP_ENTRY61_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY61_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY61_L 0x09bb + +#define RTL8367C_REG_IPMC_GROUP_ENTRY62_H 0x09bc +#define RTL8367C_IPMC_GROUP_ENTRY62_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY62_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY62_L 0x09bd + +#define RTL8367C_REG_IPMC_GROUP_ENTRY63_H 0x09be +#define RTL8367C_IPMC_GROUP_ENTRY63_H_OFFSET 0 +#define RTL8367C_IPMC_GROUP_ENTRY63_H_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_ENTRY63_L 0x09bf + +#define RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE 0x09C0 +#define RTL8367C_Port7_ACTION_OFFSET 14 +#define RTL8367C_Port7_ACTION_MASK 0xC000 +#define RTL8367C_Port6_ACTION_OFFSET 12 +#define RTL8367C_Port6_ACTION_MASK 0x3000 +#define RTL8367C_Port5_ACTION_OFFSET 10 +#define RTL8367C_Port5_ACTION_MASK 0xC00 +#define RTL8367C_Port4_ACTION_OFFSET 8 +#define RTL8367C_Port4_ACTION_MASK 0x300 +#define RTL8367C_Port3_ACTION_OFFSET 6 +#define RTL8367C_Port3_ACTION_MASK 0xC0 +#define RTL8367C_Port2_ACTION_OFFSET 4 +#define RTL8367C_Port2_ACTION_MASK 0x30 +#define RTL8367C_Port1_ACTION_OFFSET 2 +#define RTL8367C_Port1_ACTION_MASK 0xC +#define RTL8367C_Port0_ACTION_OFFSET 0 +#define RTL8367C_Port0_ACTION_MASK 0x3 + +#define RTL8367C_REG_MIRROR_CTRL3 0x09C1 +#define RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET 2 +#define RTL8367C_MIRROR_ACL_OVERRIDE_EN_MASK 0x4 +#define RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET 1 +#define RTL8367C_MIRROR_TX_OVERRIDE_EN_MASK 0x2 +#define RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET 0 +#define RTL8367C_MIRROR_RX_OVERRIDE_EN_MASK 0x1 + +#define RTL8367C_REG_DPM_DUMMY02 0x09C2 + +#define RTL8367C_REG_DPM_DUMMY03 0x09C3 + +#define RTL8367C_REG_DPM_DUMMY04 0x09C4 + +#define RTL8367C_REG_DPM_DUMMY05 0x09C5 + +#define RTL8367C_REG_DPM_DUMMY06 0x09C6 + +#define RTL8367C_REG_DPM_DUMMY07 0x09C7 + +#define RTL8367C_REG_DPM_DUMMY08 0x09C8 + +#define RTL8367C_REG_DPM_DUMMY09 0x09C9 + +#define RTL8367C_REG_DPM_DUMMY10 0x09CA + +#define RTL8367C_REG_DPM_DUMMY11 0x09CB + +#define RTL8367C_REG_DPM_DUMMY12 0x09CC + +#define RTL8367C_REG_DPM_DUMMY13 0x09CD + +#define RTL8367C_REG_DPM_DUMMY14 0x09CE + +#define RTL8367C_REG_DPM_DUMMY15 0x09CF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 0x09D0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL0_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL1 0x09D1 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL1_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL1_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL2 0x09D2 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL2_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL2_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL3 0x09D3 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL3_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL3_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL4 0x09D4 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL4_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL4_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL5 0x09D5 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL5_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL5_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL6 0x09D6 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL6_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL6_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL7 0x09D7 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL7_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL7_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL8 0x09D8 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL8_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL8_MASK 0x7FF + +#define RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL9 0x09D9 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL9_OFFSET 0 +#define RTL8367C_VLAN_EGRESS_TRANS_CTRL9_MASK 0x7FF + +#define RTL8367C_REG_MIRROR_CTRL2 0x09DA +#define RTL8367C_MIRROR_REALKEEP_EN_OFFSET 4 +#define RTL8367C_MIRROR_REALKEEP_EN_MASK 0x10 +#define RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET 3 +#define RTL8367C_MIRROR_RX_ISOLATION_LEAKY_MASK 0x8 +#define RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET 2 +#define RTL8367C_MIRROR_TX_ISOLATION_LEAKY_MASK 0x4 +#define RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET 1 +#define RTL8367C_MIRROR_RX_VLAN_LEAKY_MASK 0x2 +#define RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET 0 +#define RTL8367C_MIRROR_TX_VLAN_LEAKY_MASK 0x1 + +#define RTL8367C_REG_OUTPUT_DROP_CFG 0x09DB +#define RTL8367C_ENABLE_PMASK_EXT_OFFSET 13 +#define RTL8367C_ENABLE_PMASK_EXT_MASK 0xE000 +#define RTL8367C_ENABLE_BC_OFFSET 12 +#define RTL8367C_ENABLE_BC_MASK 0x1000 +#define RTL8367C_ENABLE_MC_OFFSET 11 +#define RTL8367C_ENABLE_MC_MASK 0x800 +#define RTL8367C_ENABLE_UC_OFFSET 10 +#define RTL8367C_ENABLE_UC_MASK 0x400 +#define RTL8367C_ENABLE_PMASK_OFFSET 0 +#define RTL8367C_ENABLE_PMASK_MASK 0xFF + +#define RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT 0x09DC +#define RTL8367C_PORT10_ACTION_OFFSET 4 +#define RTL8367C_PORT10_ACTION_MASK 0x30 +#define RTL8367C_PORT9_ACTION_OFFSET 2 +#define RTL8367C_PORT9_ACTION_MASK 0xC +#define RTL8367C_PORT8_ACTION_OFFSET 0 +#define RTL8367C_PORT8_ACTION_MASK 0x3 + +#define RTL8367C_REG_RMK_CFG_SEL_CTRL 0x09DF +#define RTL8367C_RMK_1Q_CFG_SEL_OFFSET 2 +#define RTL8367C_RMK_1Q_CFG_SEL_MASK 0x4 +#define RTL8367C_RMK_DSCP_CFG_SEL_OFFSET 0 +#define RTL8367C_RMK_DSCP_CFG_SEL_MASK 0x3 + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL0 0x09E0 +#define RTL8367C_DSCP1_DSCP_OFFSET 8 +#define RTL8367C_DSCP1_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP0_DSCP_OFFSET 0 +#define RTL8367C_DSCP0_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL1 0x09E1 +#define RTL8367C_DSCP3_DSCP_OFFSET 8 +#define RTL8367C_DSCP3_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP2_DSCP_OFFSET 0 +#define RTL8367C_DSCP2_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL2 0x09E2 +#define RTL8367C_DSCP5_DSCP_OFFSET 8 +#define RTL8367C_DSCP5_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP4_DSCP_OFFSET 0 +#define RTL8367C_DSCP4_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL3 0x09E3 +#define RTL8367C_DSCP7_DSCP_OFFSET 8 +#define RTL8367C_DSCP7_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP6_DSCP_OFFSET 0 +#define RTL8367C_DSCP6_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL4 0x09E4 +#define RTL8367C_DSCP9_DSCP_OFFSET 8 +#define RTL8367C_DSCP9_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP8_DSCP_OFFSET 0 +#define RTL8367C_DSCP8_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL5 0x09E5 +#define RTL8367C_DSCP11_DSCP_OFFSET 8 +#define RTL8367C_DSCP11_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP10_DSCP_OFFSET 0 +#define RTL8367C_DSCP10_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL6 0x09E6 +#define RTL8367C_DSCP13_DSCP_OFFSET 8 +#define RTL8367C_DSCP13_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP12_DSCP_OFFSET 0 +#define RTL8367C_DSCP12_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL7 0x09E7 +#define RTL8367C_DSCP15_DSCP_OFFSET 8 +#define RTL8367C_DSCP15_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP14_DSCP_OFFSET 0 +#define RTL8367C_DSCP14_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL8 0x09E8 +#define RTL8367C_DSCP17_DSCP_OFFSET 8 +#define RTL8367C_DSCP17_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP16_DSCP_OFFSET 0 +#define RTL8367C_DSCP16_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL9 0x09E9 +#define RTL8367C_DSCP19_DSCP_OFFSET 8 +#define RTL8367C_DSCP19_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP18_DSCP_OFFSET 0 +#define RTL8367C_DSCP18_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL10 0x09EA +#define RTL8367C_DSCP21_DSCP_OFFSET 8 +#define RTL8367C_DSCP21_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP20_DSCP_OFFSET 0 +#define RTL8367C_DSCP20_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL11 0x09EB +#define RTL8367C_DSCP23_DSCP_OFFSET 8 +#define RTL8367C_DSCP23_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP22_DSCP_OFFSET 0 +#define RTL8367C_DSCP22_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL12 0x09EC +#define RTL8367C_DSCP25_DSCP_OFFSET 8 +#define RTL8367C_DSCP25_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP24_DSCP_OFFSET 0 +#define RTL8367C_DSCP24_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL13 0x09ED +#define RTL8367C_DSCP27_DSCP_OFFSET 8 +#define RTL8367C_DSCP27_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP26_DSCP_OFFSET 0 +#define RTL8367C_DSCP26_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL14 0x09EE +#define RTL8367C_DSCP29_DSCP_OFFSET 8 +#define RTL8367C_DSCP29_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP28_DSCP_OFFSET 0 +#define RTL8367C_DSCP28_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL15 0x09EF +#define RTL8367C_DSCP31_DSCP_OFFSET 8 +#define RTL8367C_DSCP31_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP30_DSCP_OFFSET 0 +#define RTL8367C_DSCP30_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL16 0x09F0 +#define RTL8367C_DSCP33_DSCP_OFFSET 8 +#define RTL8367C_DSCP33_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP32_DSCP_OFFSET 0 +#define RTL8367C_DSCP32_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL17 0x09F1 +#define RTL8367C_DSCP35_DSCP_OFFSET 8 +#define RTL8367C_DSCP35_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP34_DSCP_OFFSET 0 +#define RTL8367C_DSCP34_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL18 0x09F2 +#define RTL8367C_DSCP37_DSCP_OFFSET 8 +#define RTL8367C_DSCP37_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP36_DSCP_OFFSET 0 +#define RTL8367C_DSCP36_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL19 0x09F3 +#define RTL8367C_DSCP39_DSCP_OFFSET 8 +#define RTL8367C_DSCP39_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP38_DSCP_OFFSET 0 +#define RTL8367C_DSCP38_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL20 0x09F4 +#define RTL8367C_DSCP41_DSCP_OFFSET 8 +#define RTL8367C_DSCP41_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP40_DSCP_OFFSET 0 +#define RTL8367C_DSCP40_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL21 0x09F5 +#define RTL8367C_DSCP43_DSCP_OFFSET 8 +#define RTL8367C_DSCP43_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP42_DSCP_OFFSET 0 +#define RTL8367C_DSCP42_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL22 0x09F6 +#define RTL8367C_DSCP45_DSCP_OFFSET 8 +#define RTL8367C_DSCP45_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP44_DSCP_OFFSET 0 +#define RTL8367C_DSCP44_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL23 0x09F7 +#define RTL8367C_DSCP47_DSCP_OFFSET 8 +#define RTL8367C_DSCP47_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP46_DSCP_OFFSET 0 +#define RTL8367C_DSCP46_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL24 0x09F8 +#define RTL8367C_DSCP49_DSCP_OFFSET 8 +#define RTL8367C_DSCP49_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP48_DSCP_OFFSET 0 +#define RTL8367C_DSCP48_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL25 0x09F9 +#define RTL8367C_DSCP51_DSCP_OFFSET 8 +#define RTL8367C_DSCP51_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP50_DSCP_OFFSET 0 +#define RTL8367C_DSCP50_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL26 0x09FA +#define RTL8367C_DSCP53_DSCP_OFFSET 8 +#define RTL8367C_DSCP53_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP52_DSCP_OFFSET 0 +#define RTL8367C_DSCP52_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL27 0x09FB +#define RTL8367C_DSCP55_DSCP_OFFSET 8 +#define RTL8367C_DSCP55_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP54_DSCP_OFFSET 0 +#define RTL8367C_DSCP54_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL28 0x09FC +#define RTL8367C_DSCP57_DSCP_OFFSET 8 +#define RTL8367C_DSCP57_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP56_DSCP_OFFSET 0 +#define RTL8367C_DSCP56_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL29 0x09FD +#define RTL8367C_DSCP59_DSCP_OFFSET 8 +#define RTL8367C_DSCP59_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP58_DSCP_OFFSET 0 +#define RTL8367C_DSCP58_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL30 0x09FE +#define RTL8367C_DSCP61_DSCP_OFFSET 8 +#define RTL8367C_DSCP61_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP60_DSCP_OFFSET 0 +#define RTL8367C_DSCP60_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_DSCP_CTRL31 0x09FF +#define RTL8367C_DSCP63_DSCP_OFFSET 8 +#define RTL8367C_DSCP63_DSCP_MASK 0x3F00 +#define RTL8367C_DSCP62_DSCP_OFFSET 0 +#define RTL8367C_DSCP62_DSCP_MASK 0x3F + +/* (16'h0a00)l2_reg */ + +#define RTL8367C_REG_VLAN_MSTI0_CTRL0 0x0a00 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI0_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI0_CTRL1 0x0a01 +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI1_CTRL0 0x0a02 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI1_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI1_CTRL1 0x0a03 +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI1_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI2_CTRL0 0x0a04 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI2_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI2_CTRL1 0x0a05 +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI2_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI3_CTRL0 0x0a06 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI3_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI3_CTRL1 0x0a07 +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI3_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI4_CTRL0 0x0a08 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI4_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI4_CTRL1 0x0a09 +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI4_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI5_CTRL0 0x0a0a +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI5_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI5_CTRL1 0x0a0b +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI5_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI6_CTRL0 0x0a0c +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI6_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI6_CTRL1 0x0a0d +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI6_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI7_CTRL0 0x0a0e +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI7_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI7_CTRL1 0x0a0f +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI7_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI8_CTRL0 0x0a10 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI8_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI8_CTRL1 0x0a11 +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI8_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI9_CTRL0 0x0a12 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI9_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI9_CTRL1 0x0a13 +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI9_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI10_CTRL0 0x0a14 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI10_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI10_CTRL1 0x0a15 +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI10_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI11_CTRL0 0x0a16 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI11_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI11_CTRL1 0x0a17 +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI11_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI12_CTRL0 0x0a18 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI12_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI12_CTRL1 0x0a19 +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI12_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI13_CTRL0 0x0a1a +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI13_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI13_CTRL1 0x0a1b +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI13_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI14_CTRL0 0x0a1c +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI14_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI14_CTRL1 0x0a1d +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI14_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI15_CTRL0 0x0a1e +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_OFFSET 14 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT7_STATE_MASK 0xC000 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_OFFSET 12 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT6_STATE_MASK 0x3000 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_OFFSET 10 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT5_STATE_MASK 0xC00 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_OFFSET 8 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT4_STATE_MASK 0x300 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_OFFSET 6 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT3_STATE_MASK 0xC0 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT2_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT1_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI15_CTRL0_PORT0_STATE_MASK 0x3 + +#define RTL8367C_REG_VLAN_MSTI15_CTRL1 0x0a1f +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_OFFSET 4 +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT10_STATE_MASK 0x30 +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_OFFSET 2 +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT9_STATE_MASK 0xC +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_OFFSET 0 +#define RTL8367C_VLAN_MSTI15_CTRL1_PORT8_STATE_MASK 0x3 + +#define RTL8367C_REG_LUT_PORT0_LEARN_LIMITNO 0x0a20 +#define RTL8367C_LUT_PORT0_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT0_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT1_LEARN_LIMITNO 0x0a21 +#define RTL8367C_LUT_PORT1_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT1_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT2_LEARN_LIMITNO 0x0a22 +#define RTL8367C_LUT_PORT2_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT2_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT3_LEARN_LIMITNO 0x0a23 +#define RTL8367C_LUT_PORT3_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT3_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT4_LEARN_LIMITNO 0x0a24 +#define RTL8367C_LUT_PORT4_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT4_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT5_LEARN_LIMITNO 0x0a25 +#define RTL8367C_LUT_PORT5_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT5_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT6_LEARN_LIMITNO 0x0a26 +#define RTL8367C_LUT_PORT6_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT6_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT7_LEARN_LIMITNO 0x0a27 +#define RTL8367C_LUT_PORT7_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT7_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_SYS_LEARN_LIMITNO 0x0a28 +#define RTL8367C_LUT_SYS_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_SYS_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL 0x0a29 +#define RTL8367C_LUT_SYSTEM_LEARN_PMASK1_OFFSET 12 +#define RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK 0x7000 +#define RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_OFFSET 10 +#define RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK 0xC00 +#define RTL8367C_LUT_SYSTEM_LEARN_PMASK_OFFSET 0 +#define RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK 0xFF + +#define RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO 0x0a2a +#define RTL8367C_LUT_PORT8_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT8_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT9_LEARN_LIMITNO 0x0a2b +#define RTL8367C_LUT_PORT9_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT9_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_PORT10_LEARN_LIMITNO 0x0a2c +#define RTL8367C_LUT_PORT10_LEARN_LIMITNO_OFFSET 0 +#define RTL8367C_LUT_PORT10_LEARN_LIMITNO_MASK 0x1FFF + +#define RTL8367C_REG_LUT_CFG 0x0a30 +#define RTL8367C_AGE_SPEED_OFFSET 8 +#define RTL8367C_AGE_SPEED_MASK 0x300 +#define RTL8367C_BCAM_DISABLE_OFFSET 6 +#define RTL8367C_BCAM_DISABLE_MASK 0x40 +#define RTL8367C_LINKDOWN_AGEOUT_OFFSET 5 +#define RTL8367C_LINKDOWN_AGEOUT_MASK 0x20 +#define RTL8367C_LUT_IPMC_HASH_OFFSET 4 +#define RTL8367C_LUT_IPMC_HASH_MASK 0x10 +#define RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET 3 +#define RTL8367C_LUT_IPMC_LOOKUP_OP_MASK 0x8 +#define RTL8367C_AGE_TIMER_OFFSET 0 +#define RTL8367C_AGE_TIMER_MASK 0x7 + +#define RTL8367C_REG_LUT_AGEOUT_CTRL 0x0a31 +#define RTL8367C_LUT_AGEOUT_CTRL_OFFSET 0 +#define RTL8367C_LUT_AGEOUT_CTRL_MASK 0x7FF + +#define RTL8367C_REG_PORT_EFID_CTRL0 0x0a32 +#define RTL8367C_PORT3_EFID_OFFSET 12 +#define RTL8367C_PORT3_EFID_MASK 0x7000 +#define RTL8367C_PORT2_EFID_OFFSET 8 +#define RTL8367C_PORT2_EFID_MASK 0x700 +#define RTL8367C_PORT1_EFID_OFFSET 4 +#define RTL8367C_PORT1_EFID_MASK 0x70 +#define RTL8367C_PORT0_EFID_OFFSET 0 +#define RTL8367C_PORT0_EFID_MASK 0x7 + +#define RTL8367C_REG_PORT_EFID_CTRL1 0x0a33 +#define RTL8367C_PORT7_EFID_OFFSET 12 +#define RTL8367C_PORT7_EFID_MASK 0x7000 +#define RTL8367C_PORT6_EFID_OFFSET 8 +#define RTL8367C_PORT6_EFID_MASK 0x700 +#define RTL8367C_PORT5_EFID_OFFSET 4 +#define RTL8367C_PORT5_EFID_MASK 0x70 +#define RTL8367C_PORT4_EFID_OFFSET 0 +#define RTL8367C_PORT4_EFID_MASK 0x7 + +#define RTL8367C_REG_PORT_EFID_CTRL2 0x0a34 +#define RTL8367C_PORT10_EFID_OFFSET 8 +#define RTL8367C_PORT10_EFID_MASK 0x700 +#define RTL8367C_PORT9_EFID_OFFSET 4 +#define RTL8367C_PORT9_EFID_MASK 0x70 +#define RTL8367C_PORT8_EFID_OFFSET 0 +#define RTL8367C_PORT8_EFID_MASK 0x7 + +#define RTL8367C_REG_FORCE_FLUSH1 0x0a35 +#define RTL8367C_BUSY_STATUS1_OFFSET 3 +#define RTL8367C_BUSY_STATUS1_MASK 0x38 +#define RTL8367C_PORTMASK1_OFFSET 0 +#define RTL8367C_PORTMASK1_MASK 0x7 + +#define RTL8367C_REG_FORCE_FLUSH 0x0a36 +#define RTL8367C_BUSY_STATUS_OFFSET 8 +#define RTL8367C_BUSY_STATUS_MASK 0xFF00 +#define RTL8367C_FORCE_FLUSH_PORTMASK_OFFSET 0 +#define RTL8367C_FORCE_FLUSH_PORTMASK_MASK 0xFF + +#define RTL8367C_REG_L2_FLUSH_CTRL1 0x0a37 +#define RTL8367C_LUT_FLUSH_FID_OFFSET 12 +#define RTL8367C_LUT_FLUSH_FID_MASK 0xF000 +#define RTL8367C_LUT_FLUSH_VID_OFFSET 0 +#define RTL8367C_LUT_FLUSH_VID_MASK 0xFFF + +#define RTL8367C_REG_L2_FLUSH_CTRL2 0x0a38 +#define RTL8367C_LUT_FLUSH_TYPE_OFFSET 2 +#define RTL8367C_LUT_FLUSH_TYPE_MASK 0x4 +#define RTL8367C_LUT_FLUSH_MODE_OFFSET 0 +#define RTL8367C_LUT_FLUSH_MODE_MASK 0x3 + +#define RTL8367C_REG_L2_FLUSH_CTRL3 0x0a39 +#define RTL8367C_L2_FLUSH_CTRL3_OFFSET 0 +#define RTL8367C_L2_FLUSH_CTRL3_MASK 0x1 + +#define RTL8367C_REG_LUT_CFG2 0x0a3a +#define RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET 1 +#define RTL8367C_LUT_IPMC_FWD_RPORT_MASK 0x2 +#define RTL8367C_LUT_IPMC_VID_HASH_OFFSET 0 +#define RTL8367C_LUT_IPMC_VID_HASH_MASK 0x1 + +#define RTL8367C_REG_FLUSH_STATUS 0x0a3f +#define RTL8367C_FLUSH_STATUS_OFFSET 0 +#define RTL8367C_FLUSH_STATUS_MASK 0x1 + +#define RTL8367C_REG_STORM_BCAST 0x0a40 +#define RTL8367C_STORM_BCAST_OFFSET 0 +#define RTL8367C_STORM_BCAST_MASK 0x7FF + +#define RTL8367C_REG_STORM_MCAST 0x0a41 +#define RTL8367C_STORM_MCAST_OFFSET 0 +#define RTL8367C_STORM_MCAST_MASK 0x7FF + +#define RTL8367C_REG_STORM_UNKOWN_UCAST 0x0a42 +#define RTL8367C_STORM_UNKOWN_UCAST_OFFSET 0 +#define RTL8367C_STORM_UNKOWN_UCAST_MASK 0x7FF + +#define RTL8367C_REG_STORM_UNKOWN_MCAST 0x0a43 +#define RTL8367C_STORM_UNKOWN_MCAST_OFFSET 0 +#define RTL8367C_STORM_UNKOWN_MCAST_MASK 0x7FF + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL0 0x0a44 +#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_OFFSET 8 +#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL0_PORT0_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL1 0x0a45 +#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_OFFSET 8 +#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL1_PORT2_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL2 0x0a46 +#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_OFFSET 8 +#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL2_PORT4_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL3 0x0a47 +#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_OFFSET 8 +#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL3_PORT6_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL4 0x0a48 +#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_OFFSET 8 +#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL4_PORT8_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_BCAST_METER_CTRL5 0x0a49 +#define RTL8367C_STORM_BCAST_METER_CTRL5_OFFSET 0 +#define RTL8367C_STORM_BCAST_METER_CTRL5_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL0 0x0a4c +#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_OFFSET 8 +#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL0_PORT0_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL1 0x0a4d +#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_OFFSET 8 +#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL1_PORT2_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL2 0x0a4e +#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_OFFSET 8 +#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL2_PORT4_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL3 0x0a4f +#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_OFFSET 8 +#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL3_PORT6_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL4 0x0a50 +#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_OFFSET 8 +#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL4_PORT8_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_MCAST_METER_CTRL5 0x0a51 +#define RTL8367C_STORM_MCAST_METER_CTRL5_OFFSET 0 +#define RTL8367C_STORM_MCAST_METER_CTRL5_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL0 0x0a54 +#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL0_PORT0_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL1 0x0a55 +#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL1_PORT2_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL2 0x0a56 +#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL2_PORT4_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL3 0x0a57 +#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL3_PORT6_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL4 0x0a58 +#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL4_PORT8_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNDA_METER_CTRL5 0x0a59 +#define RTL8367C_STORM_UNDA_METER_CTRL5_OFFSET 0 +#define RTL8367C_STORM_UNDA_METER_CTRL5_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL0 0x0a5c +#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT1_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL0_PORT0_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL1 0x0a5d +#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT3_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL1_PORT2_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL2 0x0a5e +#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT5_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL2_PORT4_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL3 0x0a5f +#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT7_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL3_PORT6_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_EXT_CFG 0x0a60 +#define RTL8367C_STORM_EXT_EN_PORTMASK_EXT_OFFSET 14 +#define RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK 0x4000 +#define RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET 13 +#define RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_MASK 0x2000 +#define RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET 12 +#define RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_MASK 0x1000 +#define RTL8367C_STORM_MCAST_EXT_EN_OFFSET 11 +#define RTL8367C_STORM_MCAST_EXT_EN_MASK 0x800 +#define RTL8367C_STORM_BCAST_EXT_EN_OFFSET 10 +#define RTL8367C_STORM_BCAST_EXT_EN_MASK 0x400 +#define RTL8367C_STORM_EXT_EN_PORTMASK_OFFSET 0 +#define RTL8367C_STORM_EXT_EN_PORTMASK_MASK 0x3FF + +#define RTL8367C_REG_STORM_EXT_MTRIDX_CFG0 0x0a61 +#define RTL8367C_MC_STORM_EXT_METERIDX_OFFSET 8 +#define RTL8367C_MC_STORM_EXT_METERIDX_MASK 0x3F00 +#define RTL8367C_BC_STORM_EXT_METERIDX_OFFSET 0 +#define RTL8367C_BC_STORM_EXT_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_EXT_MTRIDX_CFG1 0x0a62 +#define RTL8367C_UNMC_STORM_EXT_METERIDX_OFFSET 8 +#define RTL8367C_UNMC_STORM_EXT_METERIDX_MASK 0x3F00 +#define RTL8367C_UNUC_STORM_EXT_METERIDX_OFFSET 0 +#define RTL8367C_UNUC_STORM_EXT_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL4 0x0a63 +#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_OFFSET 8 +#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT9_METERIDX_MASK 0x3F00 +#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL4_PORT8_METERIDX_MASK 0x3F + +#define RTL8367C_REG_STORM_UNMC_METER_CTRL5 0x0a64 +#define RTL8367C_STORM_UNMC_METER_CTRL5_OFFSET 0 +#define RTL8367C_STORM_UNMC_METER_CTRL5_MASK 0x3F + +#define RTL8367C_REG_OAM_PARSER_CTRL0 0x0a70 +#define RTL8367C_PORT7_PARACT_OFFSET 14 +#define RTL8367C_PORT7_PARACT_MASK 0xC000 +#define RTL8367C_PORT6_PARACT_OFFSET 12 +#define RTL8367C_PORT6_PARACT_MASK 0x3000 +#define RTL8367C_PORT5_PARACT_OFFSET 10 +#define RTL8367C_PORT5_PARACT_MASK 0xC00 +#define RTL8367C_PORT4_PARACT_OFFSET 8 +#define RTL8367C_PORT4_PARACT_MASK 0x300 +#define RTL8367C_PORT3_PARACT_OFFSET 6 +#define RTL8367C_PORT3_PARACT_MASK 0xC0 +#define RTL8367C_PORT2_PARACT_OFFSET 4 +#define RTL8367C_PORT2_PARACT_MASK 0x30 +#define RTL8367C_PORT1_PARACT_OFFSET 2 +#define RTL8367C_PORT1_PARACT_MASK 0xC +#define RTL8367C_PORT0_PARACT_OFFSET 0 +#define RTL8367C_PORT0_PARACT_MASK 0x3 + +#define RTL8367C_REG_OAM_PARSER_CTRL1 0x0a71 +#define RTL8367C_PORT10_PARACT_OFFSET 4 +#define RTL8367C_PORT10_PARACT_MASK 0x30 +#define RTL8367C_PORT9_PARACT_OFFSET 2 +#define RTL8367C_PORT9_PARACT_MASK 0xC +#define RTL8367C_PORT8_PARACT_OFFSET 0 +#define RTL8367C_PORT8_PARACT_MASK 0x3 + +#define RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 0x0a72 +#define RTL8367C_PORT7_MULACT_OFFSET 14 +#define RTL8367C_PORT7_MULACT_MASK 0xC000 +#define RTL8367C_PORT6_MULACT_OFFSET 12 +#define RTL8367C_PORT6_MULACT_MASK 0x3000 +#define RTL8367C_PORT5_MULACT_OFFSET 10 +#define RTL8367C_PORT5_MULACT_MASK 0xC00 +#define RTL8367C_PORT4_MULACT_OFFSET 8 +#define RTL8367C_PORT4_MULACT_MASK 0x300 +#define RTL8367C_PORT3_MULACT_OFFSET 6 +#define RTL8367C_PORT3_MULACT_MASK 0xC0 +#define RTL8367C_PORT2_MULACT_OFFSET 4 +#define RTL8367C_PORT2_MULACT_MASK 0x30 +#define RTL8367C_PORT1_MULACT_OFFSET 2 +#define RTL8367C_PORT1_MULACT_MASK 0xC +#define RTL8367C_PORT0_MULACT_OFFSET 0 +#define RTL8367C_PORT0_MULACT_MASK 0x3 + +#define RTL8367C_REG_OAM_MULTIPLEXER_CTRL1 0x0a73 +#define RTL8367C_PORT10_MULACT_OFFSET 4 +#define RTL8367C_PORT10_MULACT_MASK 0x30 +#define RTL8367C_PORT9_MULACT_OFFSET 2 +#define RTL8367C_PORT9_MULACT_MASK 0xC +#define RTL8367C_PORT8_MULACT_OFFSET 0 +#define RTL8367C_PORT8_MULACT_MASK 0x3 + +#define RTL8367C_REG_OAM_CTRL 0x0a74 +#define RTL8367C_OAM_CTRL_OFFSET 0 +#define RTL8367C_OAM_CTRL_MASK 0x1 + +#define RTL8367C_REG_DOT1X_PORT_ENABLE 0x0a80 +#define RTL8367C_DOT1X_PORT_ENABLE_OFFSET 0 +#define RTL8367C_DOT1X_PORT_ENABLE_MASK 0x7FF + +#define RTL8367C_REG_DOT1X_MAC_ENABLE 0x0a81 +#define RTL8367C_DOT1X_MAC_ENABLE_OFFSET 0 +#define RTL8367C_DOT1X_MAC_ENABLE_MASK 0x7FF + +#define RTL8367C_REG_DOT1X_PORT_AUTH 0x0a82 +#define RTL8367C_DOT1X_PORT_AUTH_OFFSET 0 +#define RTL8367C_DOT1X_PORT_AUTH_MASK 0x7FF + +#define RTL8367C_REG_DOT1X_PORT_OPDIR 0x0a83 +#define RTL8367C_DOT1X_PORT_OPDIR_OFFSET 0 +#define RTL8367C_DOT1X_PORT_OPDIR_MASK 0x7FF + +#define RTL8367C_REG_DOT1X_UNAUTH_ACT_W0 0x0a84 +#define RTL8367C_DOT1X_PORT7_UNAUTHBH_OFFSET 14 +#define RTL8367C_DOT1X_PORT7_UNAUTHBH_MASK 0xC000 +#define RTL8367C_DOT1X_PORT6_UNAUTHBH_OFFSET 12 +#define RTL8367C_DOT1X_PORT6_UNAUTHBH_MASK 0x3000 +#define RTL8367C_DOT1X_PORT5_UNAUTHBH_OFFSET 10 +#define RTL8367C_DOT1X_PORT5_UNAUTHBH_MASK 0xC00 +#define RTL8367C_DOT1X_PORT4_UNAUTHBH_OFFSET 8 +#define RTL8367C_DOT1X_PORT4_UNAUTHBH_MASK 0x300 +#define RTL8367C_DOT1X_PORT3_UNAUTHBH_OFFSET 6 +#define RTL8367C_DOT1X_PORT3_UNAUTHBH_MASK 0xC0 +#define RTL8367C_DOT1X_PORT2_UNAUTHBH_OFFSET 4 +#define RTL8367C_DOT1X_PORT2_UNAUTHBH_MASK 0x30 +#define RTL8367C_DOT1X_PORT1_UNAUTHBH_OFFSET 2 +#define RTL8367C_DOT1X_PORT1_UNAUTHBH_MASK 0xC +#define RTL8367C_DOT1X_PORT0_UNAUTHBH_OFFSET 0 +#define RTL8367C_DOT1X_PORT0_UNAUTHBH_MASK 0x3 + +#define RTL8367C_REG_DOT1X_UNAUTH_ACT_W1 0x0a85 +#define RTL8367C_DOT1X_PORT10_UNAUTHBH_OFFSET 4 +#define RTL8367C_DOT1X_PORT10_UNAUTHBH_MASK 0x30 +#define RTL8367C_DOT1X_PORT9_UNAUTHBH_OFFSET 2 +#define RTL8367C_DOT1X_PORT9_UNAUTHBH_MASK 0xC +#define RTL8367C_DOT1X_PORT8_UNAUTHBH_OFFSET 0 +#define RTL8367C_DOT1X_PORT8_UNAUTHBH_MASK 0x3 + +#define RTL8367C_REG_DOT1X_CFG 0x0a86 +#define RTL8367C_DOT1X_GVOPDIR_OFFSET 6 +#define RTL8367C_DOT1X_GVOPDIR_MASK 0x40 +#define RTL8367C_DOT1X_MAC_OPDIR_OFFSET 5 +#define RTL8367C_DOT1X_MAC_OPDIR_MASK 0x20 +#define RTL8367C_DOT1X_GVIDX_OFFSET 0 +#define RTL8367C_DOT1X_GVIDX_MASK 0x1F + +#define RTL8367C_REG_L2_LRN_CNT_CTRL0 0x0a87 +#define RTL8367C_L2_LRN_CNT_CTRL0_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL0_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL1 0x0a88 +#define RTL8367C_L2_LRN_CNT_CTRL1_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL1_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL2 0x0a89 +#define RTL8367C_L2_LRN_CNT_CTRL2_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL3 0x0a8a +#define RTL8367C_L2_LRN_CNT_CTRL3_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL3_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL4 0x0a8b +#define RTL8367C_L2_LRN_CNT_CTRL4_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL4_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL5 0x0a8c +#define RTL8367C_L2_LRN_CNT_CTRL5_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL5_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL6 0x0a8d +#define RTL8367C_L2_LRN_CNT_CTRL6_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL6_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL7 0x0a8e +#define RTL8367C_L2_LRN_CNT_CTRL7_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL7_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL8 0x0a8f +#define RTL8367C_L2_LRN_CNT_CTRL8_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL8_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL9 0x0a90 +#define RTL8367C_L2_LRN_CNT_CTRL9_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL9_MASK 0x1FFF + +#define RTL8367C_REG_L2_LRN_CNT_CTRL10 0x0a92 +#define RTL8367C_L2_LRN_CNT_CTRL10_OFFSET 0 +#define RTL8367C_L2_LRN_CNT_CTRL10_MASK 0x1FFF + +#define RTL8367C_REG_LUT_LRN_UNDER_STATUS 0x0a91 +#define RTL8367C_LUT_LRN_UNDER_STATUS_OFFSET 0 +#define RTL8367C_LUT_LRN_UNDER_STATUS_MASK 0x7FF + +#define RTL8367C_REG_L2_SA_MOVING_FORBID 0x0aa0 +#define RTL8367C_L2_SA_MOVING_FORBID_OFFSET 0 +#define RTL8367C_L2_SA_MOVING_FORBID_MASK 0x7FF + +#define RTL8367C_REG_DRPORT_LEARN_CTRL 0x0aa1 +#define RTL8367C_FORBID1_OFFSET 1 +#define RTL8367C_FORBID1_MASK 0x2 +#define RTL8367C_FORBID0_OFFSET 0 +#define RTL8367C_FORBID0_MASK 0x1 + +#define RTL8367C_REG_L2_DUMMY02 0x0aa2 + +#define RTL8367C_REG_L2_DUMMY03 0x0aa3 + +#define RTL8367C_REG_L2_DUMMY04 0x0aa4 + +#define RTL8367C_REG_L2_DUMMY05 0x0aa5 + +#define RTL8367C_REG_L2_DUMMY06 0x0aa6 + +#define RTL8367C_REG_L2_DUMMY07 0x0aa7 + +#define RTL8367C_REG_IPMC_GROUP_PMSK_00 0x0AC0 +#define RTL8367C_IPMC_GROUP_PMSK_00_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_00_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_01 0x0AC1 +#define RTL8367C_IPMC_GROUP_PMSK_01_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_01_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_02 0x0AC2 +#define RTL8367C_IPMC_GROUP_PMSK_02_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_02_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_03 0x0AC3 +#define RTL8367C_IPMC_GROUP_PMSK_03_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_03_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_04 0x0AC4 +#define RTL8367C_IPMC_GROUP_PMSK_04_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_04_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_05 0x0AC5 +#define RTL8367C_IPMC_GROUP_PMSK_05_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_05_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_06 0x0AC6 +#define RTL8367C_IPMC_GROUP_PMSK_06_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_06_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_07 0x0AC7 +#define RTL8367C_IPMC_GROUP_PMSK_07_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_07_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_08 0x0AC8 +#define RTL8367C_IPMC_GROUP_PMSK_08_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_08_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_09 0x0AC9 +#define RTL8367C_IPMC_GROUP_PMSK_09_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_09_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_10 0x0ACA +#define RTL8367C_IPMC_GROUP_PMSK_10_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_10_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_11 0x0ACB +#define RTL8367C_IPMC_GROUP_PMSK_11_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_11_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_12 0x0ACC +#define RTL8367C_IPMC_GROUP_PMSK_12_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_12_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_13 0x0ACD +#define RTL8367C_IPMC_GROUP_PMSK_13_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_13_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_14 0x0ACE +#define RTL8367C_IPMC_GROUP_PMSK_14_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_14_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_15 0x0ACF +#define RTL8367C_IPMC_GROUP_PMSK_15_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_15_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_16 0x0AD0 +#define RTL8367C_IPMC_GROUP_PMSK_16_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_16_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_17 0x0AD1 +#define RTL8367C_IPMC_GROUP_PMSK_17_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_17_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_18 0x0AD2 +#define RTL8367C_IPMC_GROUP_PMSK_18_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_18_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_19 0x0AD3 +#define RTL8367C_IPMC_GROUP_PMSK_19_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_19_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_20 0x0AD4 +#define RTL8367C_IPMC_GROUP_PMSK_20_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_20_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_21 0x0AD5 +#define RTL8367C_IPMC_GROUP_PMSK_21_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_21_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_22 0x0AD6 +#define RTL8367C_IPMC_GROUP_PMSK_22_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_22_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_23 0x0AD7 +#define RTL8367C_IPMC_GROUP_PMSK_23_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_23_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_24 0x0AD8 +#define RTL8367C_IPMC_GROUP_PMSK_24_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_24_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_25 0x0AD9 +#define RTL8367C_IPMC_GROUP_PMSK_25_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_25_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_26 0x0ADA +#define RTL8367C_IPMC_GROUP_PMSK_26_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_26_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_27 0x0ADB +#define RTL8367C_IPMC_GROUP_PMSK_27_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_27_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_28 0x0ADC +#define RTL8367C_IPMC_GROUP_PMSK_28_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_28_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_29 0x0ADD +#define RTL8367C_IPMC_GROUP_PMSK_29_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_29_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_30 0x0ADE +#define RTL8367C_IPMC_GROUP_PMSK_30_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_30_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_31 0x0ADF +#define RTL8367C_IPMC_GROUP_PMSK_31_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_31_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_32 0x0AE0 +#define RTL8367C_IPMC_GROUP_PMSK_32_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_32_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_33 0x0AE1 +#define RTL8367C_IPMC_GROUP_PMSK_33_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_33_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_34 0x0AE2 +#define RTL8367C_IPMC_GROUP_PMSK_34_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_34_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_35 0x0AE3 +#define RTL8367C_IPMC_GROUP_PMSK_35_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_35_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_36 0x0AE4 +#define RTL8367C_IPMC_GROUP_PMSK_36_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_36_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_37 0x0AE5 +#define RTL8367C_IPMC_GROUP_PMSK_37_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_37_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_38 0x0AE6 +#define RTL8367C_IPMC_GROUP_PMSK_38_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_38_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_39 0x0AE7 +#define RTL8367C_IPMC_GROUP_PMSK_39_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_39_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_40 0x0AE8 +#define RTL8367C_IPMC_GROUP_PMSK_40_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_40_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_41 0x0AE9 +#define RTL8367C_IPMC_GROUP_PMSK_41_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_41_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_42 0x0AEA +#define RTL8367C_IPMC_GROUP_PMSK_42_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_42_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_43 0x0AEB +#define RTL8367C_IPMC_GROUP_PMSK_43_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_43_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_44 0x0AEC +#define RTL8367C_IPMC_GROUP_PMSK_44_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_44_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_45 0x0AED +#define RTL8367C_IPMC_GROUP_PMSK_45_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_45_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_46 0x0AEE +#define RTL8367C_IPMC_GROUP_PMSK_46_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_46_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_47 0x0AEF +#define RTL8367C_IPMC_GROUP_PMSK_47_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_47_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_48 0x0AF0 +#define RTL8367C_IPMC_GROUP_PMSK_48_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_48_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_49 0x0AF1 +#define RTL8367C_IPMC_GROUP_PMSK_49_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_49_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_50 0x0AF2 +#define RTL8367C_IPMC_GROUP_PMSK_50_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_50_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_51 0x0AF3 +#define RTL8367C_IPMC_GROUP_PMSK_51_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_51_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_52 0x0AF4 +#define RTL8367C_IPMC_GROUP_PMSK_52_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_52_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_53 0x0AF5 +#define RTL8367C_IPMC_GROUP_PMSK_53_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_53_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_54 0x0AF6 +#define RTL8367C_IPMC_GROUP_PMSK_54_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_54_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_55 0x0AF7 +#define RTL8367C_IPMC_GROUP_PMSK_55_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_55_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_56 0x0AF8 +#define RTL8367C_IPMC_GROUP_PMSK_56_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_56_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_57 0x0AF9 +#define RTL8367C_IPMC_GROUP_PMSK_57_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_57_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_58 0x0AFA +#define RTL8367C_IPMC_GROUP_PMSK_58_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_58_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_59 0x0AFB +#define RTL8367C_IPMC_GROUP_PMSK_59_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_59_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_60 0x0AFC +#define RTL8367C_IPMC_GROUP_PMSK_60_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_60_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_61 0x0AFD +#define RTL8367C_IPMC_GROUP_PMSK_61_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_61_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_62 0x0AFE +#define RTL8367C_IPMC_GROUP_PMSK_62_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_62_MASK 0x7FF + +#define RTL8367C_REG_IPMC_GROUP_PMSK_63 0x0AFF +#define RTL8367C_IPMC_GROUP_PMSK_63_OFFSET 0 +#define RTL8367C_IPMC_GROUP_PMSK_63_MASK 0x7FF + +/* (16'h0b00)mltvlan_reg */ + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL0 0x0b00 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY0_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL1 0x0b01 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL2 0x0b02 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL3 0x0b03 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY0_CTRL4 0x0b04 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL0 0x0b05 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY1_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL1 0x0b06 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL2 0x0b07 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL3 0x0b08 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY1_CTRL4 0x0b09 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL0 0x0b0a +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY2_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL1 0x0b0b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL2 0x0b0c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL3 0x0b0d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY2_CTRL4 0x0b0e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL0 0x0b0f +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY3_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL1 0x0b10 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL2 0x0b11 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL3 0x0b12 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY3_CTRL4 0x0b13 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL0 0x0b14 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY4_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL1 0x0b15 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL2 0x0b16 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL3 0x0b17 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY4_CTRL4 0x0b18 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL0 0x0b19 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY5_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL1 0x0b1a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL2 0x0b1b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL3 0x0b1c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY5_CTRL4 0x0b1d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL0 0x0b1e +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY6_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL1 0x0b1f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL2 0x0b20 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL3 0x0b21 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY6_CTRL4 0x0b22 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL0 0x0b23 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY7_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL1 0x0b24 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL2 0x0b25 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL3 0x0b26 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY7_CTRL4 0x0b27 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL0 0x0b28 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY8_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL1 0x0b29 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL2 0x0b2a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL3 0x0b2b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY8_CTRL4 0x0b2c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL0 0x0b2d +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY9_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL1 0x0b2e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL2 0x0b2f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL3 0x0b30 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY9_CTRL4 0x0b31 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL0 0x0b32 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY10_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL1 0x0b33 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL2 0x0b34 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL3 0x0b35 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY10_CTRL4 0x0b36 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL0 0x0b37 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY11_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL1 0x0b38 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL2 0x0b39 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL3 0x0b3a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY11_CTRL4 0x0b3b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL0 0x0b3c +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY12_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL1 0x0b3d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL2 0x0b3e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL3 0x0b3f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY12_CTRL4 0x0b40 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL0 0x0b41 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY13_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL1 0x0b42 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL2 0x0b43 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL3 0x0b44 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY13_CTRL4 0x0b45 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL0 0x0b46 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY14_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL1 0x0b47 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL2 0x0b48 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL3 0x0b49 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY14_CTRL4 0x0b4a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL0 0x0b4b +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY15_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL1 0x0b4c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL2 0x0b4d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL3 0x0b4e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY15_CTRL4 0x0b4f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL0 0x0b50 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY16_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL1 0x0b51 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL2 0x0b52 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL3 0x0b53 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY16_CTRL4 0x0b54 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL0 0x0b55 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY17_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL1 0x0b56 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL2 0x0b57 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL3 0x0b58 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY17_CTRL4 0x0b59 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL0 0x0b5a +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY18_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL1 0x0b5b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL2 0x0b5c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL3 0x0b5d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY18_CTRL4 0x0b5e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL0 0x0b5f +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY19_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL1 0x0b60 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL2 0x0b61 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL3 0x0b62 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY19_CTRL4 0x0b63 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL0 0x0b64 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY20_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL1 0x0b65 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL2 0x0b66 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL3 0x0b67 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY20_CTRL4 0x0b68 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL0 0x0b69 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY21_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL1 0x0b6a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL2 0x0b6b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL3 0x0b6c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY21_CTRL4 0x0b6d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL0 0x0b6e +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY22_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL1 0x0b6f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL2 0x0b70 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL3 0x0b71 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY22_CTRL4 0x0b72 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL0 0x0b73 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY23_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL1 0x0b74 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL2 0x0b75 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL3 0x0b76 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY23_CTRL4 0x0b77 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL0 0x0b78 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY24_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL1 0x0b79 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL2 0x0b7a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL3 0x0b7b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY24_CTRL4 0x0b7c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL0 0x0b7d +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY25_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL1 0x0b7e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL2 0x0b7f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL3 0x0b80 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY25_CTRL4 0x0b81 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL0 0x0b82 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY26_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL1 0x0b83 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL2 0x0b84 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL3 0x0b85 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY26_CTRL4 0x0b86 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL0 0x0b87 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY27_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL1 0x0b88 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL2 0x0b89 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL3 0x0b8a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY27_CTRL4 0x0b8b + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL0 0x0b8c +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY28_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL1 0x0b8d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL2 0x0b8e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL3 0x0b8f + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY28_CTRL4 0x0b90 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL0 0x0b91 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY29_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL1 0x0b92 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL2 0x0b93 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL3 0x0b94 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY29_CTRL4 0x0b95 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL0 0x0b96 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY30_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL1 0x0b97 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL2 0x0b98 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL3 0x0b99 + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY30_CTRL4 0x0b9a + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL0 0x0b9b +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_OFFSET 7 +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_VALID_MASK 0x80 +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_OFFSET 6 +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_FORMAT_MASK 0x40 +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_OFFSET 0 +#define RTL8367C_SVLAN_MCAST2S_ENTRY31_CTRL0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL1 0x0b9c + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL2 0x0b9d + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL3 0x0b9e + +#define RTL8367C_REG_SVLAN_MCAST2S_ENTRY31_CTRL4 0x0b9f + +#define RTL8367C_REG_MLTVLAN_DUMMY_0 0x0ba0 + +#define RTL8367C_REG_MLTVLAN_DUMMY_1 0x0ba1 + +#define RTL8367C_REG_MLTVLAN_DUMMY_2 0x0ba2 + +#define RTL8367C_REG_MLTVLAN_DUMMY_3 0x0ba3 + +#define RTL8367C_REG_MLTVLAN_DUMMY_4 0x0ba4 + +#define RTL8367C_REG_MLTVLAN_DUMMY_5 0x0ba5 + +#define RTL8367C_REG_MLTVLAN_DUMMY_6 0x0ba6 + +#define RTL8367C_REG_MLTVLAN_DUMMY_7 0x0ba7 + +/* (16'h0c00)svlan_reg */ + +#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL1 0x0c01 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL2 0x0c02 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL3 0x0c03 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL1 0x0c04 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL2 0x0c05 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL3 0x0c06 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL1 0x0c07 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL2 0x0c08 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL3 0x0c09 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL1 0x0c0a +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL2 0x0c0b +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL3 0x0c0c +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL1 0x0c0d +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL2 0x0c0e +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL3 0x0c0f +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL1 0x0c10 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL2 0x0c11 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL3 0x0c12 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL1 0x0c13 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL2 0x0c14 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL3 0x0c15 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL1 0x0c16 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL2 0x0c17 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL3 0x0c18 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL1 0x0c19 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL2 0x0c1a +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL3 0x0c1b +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL1 0x0c1c +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL2 0x0c1d +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL3 0x0c1e +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL1 0x0c1f +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL2 0x0c20 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL3 0x0c21 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL1 0x0c22 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL2 0x0c23 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL3 0x0c24 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL1 0x0c25 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL2 0x0c26 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL3 0x0c27 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL1 0x0c28 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL2 0x0c29 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL3 0x0c2a +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL1 0x0c2b +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL2 0x0c2c +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL3 0x0c2d +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL1 0x0c2e +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL2 0x0c2f +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL3 0x0c30 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL1 0x0c31 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL2 0x0c32 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL3 0x0c33 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL1 0x0c34 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL2 0x0c35 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL3 0x0c36 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL1 0x0c37 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL2 0x0c38 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL3 0x0c39 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL1 0x0c3a +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL2 0x0c3b +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL3 0x0c3c +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL1 0x0c3d +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL2 0x0c3e +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL3 0x0c3f +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL1 0x0c40 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL2 0x0c41 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL3 0x0c42 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL1 0x0c43 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL2 0x0c44 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL3 0x0c45 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL1 0x0c46 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL2 0x0c47 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL3 0x0c48 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL1 0x0c49 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL2 0x0c4a +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL3 0x0c4b +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL1 0x0c4c +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL2 0x0c4d +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL3 0x0c4e +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL1 0x0c4f +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL2 0x0c50 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL3 0x0c51 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL1 0x0c52 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL2 0x0c53 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL3 0x0c54 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL1 0x0c55 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL2 0x0c56 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL3 0x0c57 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL1 0x0c58 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL2 0x0c59 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL3 0x0c5a +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL1 0x0c5b +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL2 0x0c5c +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL3 0x0c5d +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL1 0x0c5e +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL2 0x0c5f +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL3 0x0c60 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL1 0x0c61 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL2 0x0c62 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL3 0x0c63 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL1 0x0c64 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL2 0x0c65 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL3 0x0c66 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL1 0x0c67 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL2 0x0c68 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL3 0x0c69 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL1 0x0c6a +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL2 0x0c6b +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL3 0x0c6c +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL1 0x0c6d +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL2 0x0c6e +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL3 0x0c6f +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL1 0x0c70 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL2 0x0c71 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL3 0x0c72 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL1 0x0c73 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL2 0x0c74 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL3 0x0c75 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL1 0x0c76 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL2 0x0c77 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL3 0x0c78 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL1 0x0c79 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL2 0x0c7a +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL3 0x0c7b +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL1 0x0c7c +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL2 0x0c7d +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL3 0x0c7e +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL1 0x0c7f +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL2 0x0c80 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL3 0x0c81 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL1 0x0c82 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL2 0x0c83 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL3 0x0c84 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL1 0x0c85 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL2 0x0c86 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL3 0x0c87 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL1 0x0c88 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL2 0x0c89 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL3 0x0c8a +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL1 0x0c8b +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL2 0x0c8c +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL3 0x0c8d +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL1 0x0c8e +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL2 0x0c8f +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL3 0x0c90 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL1 0x0c91 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL2 0x0c92 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL3 0x0c93 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL1 0x0c94 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL2 0x0c95 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL3 0x0c96 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL1 0x0c97 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL2 0x0c98 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL3 0x0c99 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL1 0x0c9a +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL2 0x0c9b +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL3 0x0c9c +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL1 0x0c9d +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL2 0x0c9e +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL3 0x0c9f +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL1 0x0ca0 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL2 0x0ca1 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL3 0x0ca2 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL1 0x0ca3 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL2 0x0ca4 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL3 0x0ca5 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL1 0x0ca6 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL2 0x0ca7 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL3 0x0ca8 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL1 0x0ca9 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL2 0x0caa +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL3 0x0cab +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL1 0x0cac +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL2 0x0cad +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL3 0x0cae +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL1 0x0caf +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL2 0x0cb0 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL3 0x0cb1 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL1 0x0cb2 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL2 0x0cb3 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL3 0x0cb4 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL1 0x0cb5 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL2 0x0cb6 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL3 0x0cb7 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL1 0x0cb8 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL2 0x0cb9 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL3 0x0cba +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL1 0x0cbb +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL2 0x0cbc +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL3 0x0cbd +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL1 0x0cbe +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_UNTAGSET_MASK 0xFF00 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL1_VS_SMBR_MASK 0xFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL2 0x0cbf +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_OFFSET 7 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FIDEN_MASK 0x80 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_OFFSET 4 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_SPRI_MASK 0x70 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL2_VS_FID_MSTI_MASK 0xF + +#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL3 0x0cc0 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_OFFSET 13 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFID_MASK 0xE000 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_OFFSET 12 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_EFIDEN_MASK 0x1000 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL3_VS_SVID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4 0x0cc1 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG0_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG1_CTRL4 0x0cc2 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG1_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG2_CTRL4 0x0cc3 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG2_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG3_CTRL4 0x0cc4 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG3_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG4_CTRL4 0x0cc5 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG4_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG5_CTRL4 0x0cc6 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG5_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG6_CTRL4 0x0cc7 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG6_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG7_CTRL4 0x0cc8 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG7_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG8_CTRL4 0x0cc9 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG8_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG9_CTRL4 0x0cca +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG9_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG10_CTRL4 0x0ccb +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG10_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG11_CTRL4 0x0ccc +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG11_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG12_CTRL4 0x0ccd +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG12_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG13_CTRL4 0x0cce +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG13_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG14_CTRL4 0x0ccf +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG14_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG15_CTRL4 0x0cd0 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG15_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG16_CTRL4 0x0cd1 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG16_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG17_CTRL4 0x0cd2 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG17_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG18_CTRL4 0x0cd3 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG18_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG19_CTRL4 0x0cd4 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG19_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG20_CTRL4 0x0cd5 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG20_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG21_CTRL4 0x0cd6 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG21_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG22_CTRL4 0x0cd7 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG22_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG23_CTRL4 0x0cd8 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG23_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG24_CTRL4 0x0cd9 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG24_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG25_CTRL4 0x0cda +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG25_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG26_CTRL4 0x0cdb +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG26_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG27_CTRL4 0x0cdc +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG27_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG28_CTRL4 0x0cdd +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG28_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG29_CTRL4 0x0cde +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG29_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG30_CTRL4 0x0cdf +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG30_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG31_CTRL4 0x0ce0 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG31_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG32_CTRL4 0x0ce1 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG32_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG33_CTRL4 0x0ce2 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG33_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG34_CTRL4 0x0ce3 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG34_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG35_CTRL4 0x0ce4 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG35_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG36_CTRL4 0x0ce5 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG36_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG37_CTRL4 0x0ce6 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG37_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG38_CTRL4 0x0ce7 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG38_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG39_CTRL4 0x0ce8 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG39_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG40_CTRL4 0x0ce9 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG40_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG41_CTRL4 0x0cea +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG41_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG42_CTRL4 0x0ceb +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG42_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG43_CTRL4 0x0cec +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG43_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG44_CTRL4 0x0ced +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG44_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG45_CTRL4 0x0cee +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG45_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG46_CTRL4 0x0cef +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG46_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG47_CTRL4 0x0cf0 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG47_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG48_CTRL4 0x0cf1 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG48_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG49_CTRL4 0x0cf2 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG49_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG50_CTRL4 0x0cf3 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG50_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG51_CTRL4 0x0cf4 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG51_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG52_CTRL4 0x0cf5 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG52_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG53_CTRL4 0x0cf6 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG53_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG54_CTRL4 0x0cf7 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG54_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG55_CTRL4 0x0cf8 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG55_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG56_CTRL4 0x0cf9 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG56_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG57_CTRL4 0x0cfa +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG57_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG58_CTRL4 0x0cfb +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG58_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG59_CTRL4 0x0cfc +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG59_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG60_CTRL4 0x0cfd +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG60_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG61_CTRL4 0x0cfe +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG61_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_MEMBERCFG62_CTRL4 0x0cff +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG62_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL0 0x0d00 +#define RTL8367C_SVLAN_C2SCFG0_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG0_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL1 0x0d01 +#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG0_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG0_CTRL2 0x0d02 +#define RTL8367C_SVLAN_C2SCFG0_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG0_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL0 0x0d03 +#define RTL8367C_SVLAN_C2SCFG1_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG1_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL1 0x0d04 +#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG1_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG1_CTRL2 0x0d05 +#define RTL8367C_SVLAN_C2SCFG1_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG1_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL0 0x0d06 +#define RTL8367C_SVLAN_C2SCFG2_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG2_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL1 0x0d07 +#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG2_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG2_CTRL2 0x0d08 +#define RTL8367C_SVLAN_C2SCFG2_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG2_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL0 0x0d09 +#define RTL8367C_SVLAN_C2SCFG3_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG3_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL1 0x0d0a +#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG3_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG3_CTRL2 0x0d0b +#define RTL8367C_SVLAN_C2SCFG3_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG3_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL0 0x0d0c +#define RTL8367C_SVLAN_C2SCFG4_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG4_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL1 0x0d0d +#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG4_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG4_CTRL2 0x0d0e +#define RTL8367C_SVLAN_C2SCFG4_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG4_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL0 0x0d0f +#define RTL8367C_SVLAN_C2SCFG5_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG5_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL1 0x0d10 +#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG5_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG5_CTRL2 0x0d11 +#define RTL8367C_SVLAN_C2SCFG5_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG5_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL0 0x0d12 +#define RTL8367C_SVLAN_C2SCFG6_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG6_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL1 0x0d13 +#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG6_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG6_CTRL2 0x0d14 +#define RTL8367C_SVLAN_C2SCFG6_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG6_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL0 0x0d15 +#define RTL8367C_SVLAN_C2SCFG7_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG7_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL1 0x0d16 +#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG7_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG7_CTRL2 0x0d17 +#define RTL8367C_SVLAN_C2SCFG7_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG7_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL0 0x0d18 +#define RTL8367C_SVLAN_C2SCFG8_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG8_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL1 0x0d19 +#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG8_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG8_CTRL2 0x0d1a +#define RTL8367C_SVLAN_C2SCFG8_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG8_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL0 0x0d1b +#define RTL8367C_SVLAN_C2SCFG9_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG9_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL1 0x0d1c +#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG9_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG9_CTRL2 0x0d1d +#define RTL8367C_SVLAN_C2SCFG9_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG9_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL0 0x0d1e +#define RTL8367C_SVLAN_C2SCFG10_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG10_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL1 0x0d1f +#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG10_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG10_CTRL2 0x0d20 +#define RTL8367C_SVLAN_C2SCFG10_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG10_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL0 0x0d21 +#define RTL8367C_SVLAN_C2SCFG11_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG11_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL1 0x0d22 +#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG11_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG11_CTRL2 0x0d23 +#define RTL8367C_SVLAN_C2SCFG11_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG11_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL0 0x0d24 +#define RTL8367C_SVLAN_C2SCFG12_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG12_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL1 0x0d25 +#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG12_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG12_CTRL2 0x0d26 +#define RTL8367C_SVLAN_C2SCFG12_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG12_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL0 0x0d27 +#define RTL8367C_SVLAN_C2SCFG13_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG13_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL1 0x0d28 +#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG13_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG13_CTRL2 0x0d29 +#define RTL8367C_SVLAN_C2SCFG13_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG13_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL0 0x0d2a +#define RTL8367C_SVLAN_C2SCFG14_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG14_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL1 0x0d2b +#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG14_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG14_CTRL2 0x0d2c +#define RTL8367C_SVLAN_C2SCFG14_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG14_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL0 0x0d2d +#define RTL8367C_SVLAN_C2SCFG15_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG15_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL1 0x0d2e +#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG15_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG15_CTRL2 0x0d2f +#define RTL8367C_SVLAN_C2SCFG15_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG15_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL0 0x0d30 +#define RTL8367C_SVLAN_C2SCFG16_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG16_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL1 0x0d31 +#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG16_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG16_CTRL2 0x0d32 +#define RTL8367C_SVLAN_C2SCFG16_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG16_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL0 0x0d33 +#define RTL8367C_SVLAN_C2SCFG17_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG17_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL1 0x0d34 +#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG17_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG17_CTRL2 0x0d35 +#define RTL8367C_SVLAN_C2SCFG17_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG17_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL0 0x0d36 +#define RTL8367C_SVLAN_C2SCFG18_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG18_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL1 0x0d37 +#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG18_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG18_CTRL2 0x0d38 +#define RTL8367C_SVLAN_C2SCFG18_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG18_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL0 0x0d39 +#define RTL8367C_SVLAN_C2SCFG19_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG19_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL1 0x0d3a +#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG19_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG19_CTRL2 0x0d3b +#define RTL8367C_SVLAN_C2SCFG19_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG19_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL0 0x0d3c +#define RTL8367C_SVLAN_C2SCFG20_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG20_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL1 0x0d3d +#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG20_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG20_CTRL2 0x0d3e +#define RTL8367C_SVLAN_C2SCFG20_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG20_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL0 0x0d3f +#define RTL8367C_SVLAN_C2SCFG21_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG21_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL1 0x0d40 +#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG21_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG21_CTRL2 0x0d41 +#define RTL8367C_SVLAN_C2SCFG21_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG21_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL0 0x0d42 +#define RTL8367C_SVLAN_C2SCFG22_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG22_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL1 0x0d43 +#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG22_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG22_CTRL2 0x0d44 +#define RTL8367C_SVLAN_C2SCFG22_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG22_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL0 0x0d45 +#define RTL8367C_SVLAN_C2SCFG23_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG23_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL1 0x0d46 +#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG23_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG23_CTRL2 0x0d47 +#define RTL8367C_SVLAN_C2SCFG23_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG23_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL0 0x0d48 +#define RTL8367C_SVLAN_C2SCFG24_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG24_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL1 0x0d49 +#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG24_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG24_CTRL2 0x0d4a +#define RTL8367C_SVLAN_C2SCFG24_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG24_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL0 0x0d4b +#define RTL8367C_SVLAN_C2SCFG25_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG25_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL1 0x0d4c +#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG25_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG25_CTRL2 0x0d4d +#define RTL8367C_SVLAN_C2SCFG25_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG25_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL0 0x0d4e +#define RTL8367C_SVLAN_C2SCFG26_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG26_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL1 0x0d4f +#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG26_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG26_CTRL2 0x0d50 +#define RTL8367C_SVLAN_C2SCFG26_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG26_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL0 0x0d51 +#define RTL8367C_SVLAN_C2SCFG27_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG27_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL1 0x0d52 +#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG27_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG27_CTRL2 0x0d53 +#define RTL8367C_SVLAN_C2SCFG27_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG27_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL0 0x0d54 +#define RTL8367C_SVLAN_C2SCFG28_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG28_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL1 0x0d55 +#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG28_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG28_CTRL2 0x0d56 +#define RTL8367C_SVLAN_C2SCFG28_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG28_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL0 0x0d57 +#define RTL8367C_SVLAN_C2SCFG29_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG29_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL1 0x0d58 +#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG29_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG29_CTRL2 0x0d59 +#define RTL8367C_SVLAN_C2SCFG29_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG29_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL0 0x0d5a +#define RTL8367C_SVLAN_C2SCFG30_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG30_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL1 0x0d5b +#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG30_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG30_CTRL2 0x0d5c +#define RTL8367C_SVLAN_C2SCFG30_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG30_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL0 0x0d5d +#define RTL8367C_SVLAN_C2SCFG31_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG31_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL1 0x0d5e +#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG31_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG31_CTRL2 0x0d5f +#define RTL8367C_SVLAN_C2SCFG31_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG31_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL0 0x0d60 +#define RTL8367C_SVLAN_C2SCFG32_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG32_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL1 0x0d61 +#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG32_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG32_CTRL2 0x0d62 +#define RTL8367C_SVLAN_C2SCFG32_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG32_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL0 0x0d63 +#define RTL8367C_SVLAN_C2SCFG33_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG33_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL1 0x0d64 +#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG33_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG33_CTRL2 0x0d65 +#define RTL8367C_SVLAN_C2SCFG33_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG33_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL0 0x0d66 +#define RTL8367C_SVLAN_C2SCFG34_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG34_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL1 0x0d67 +#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG34_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG34_CTRL2 0x0d68 +#define RTL8367C_SVLAN_C2SCFG34_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG34_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL0 0x0d69 +#define RTL8367C_SVLAN_C2SCFG35_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG35_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL1 0x0d6a +#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG35_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG35_CTRL2 0x0d6b +#define RTL8367C_SVLAN_C2SCFG35_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG35_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL0 0x0d6c +#define RTL8367C_SVLAN_C2SCFG36_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG36_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL1 0x0d6d +#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG36_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG36_CTRL2 0x0d6e +#define RTL8367C_SVLAN_C2SCFG36_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG36_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL0 0x0d6f +#define RTL8367C_SVLAN_C2SCFG37_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG37_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL1 0x0d70 +#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG37_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG37_CTRL2 0x0d71 +#define RTL8367C_SVLAN_C2SCFG37_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG37_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL0 0x0d72 +#define RTL8367C_SVLAN_C2SCFG38_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG38_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL1 0x0d73 +#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG38_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG38_CTRL2 0x0d74 +#define RTL8367C_SVLAN_C2SCFG38_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG38_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL0 0x0d75 +#define RTL8367C_SVLAN_C2SCFG39_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG39_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL1 0x0d76 +#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG39_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG39_CTRL2 0x0d77 +#define RTL8367C_SVLAN_C2SCFG39_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG39_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL0 0x0d78 +#define RTL8367C_SVLAN_C2SCFG40_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG40_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL1 0x0d79 +#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG40_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG40_CTRL2 0x0d7a +#define RTL8367C_SVLAN_C2SCFG40_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG40_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL0 0x0d7b +#define RTL8367C_SVLAN_C2SCFG41_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG41_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL1 0x0d7c +#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG41_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG41_CTRL2 0x0d7d +#define RTL8367C_SVLAN_C2SCFG41_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG41_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL0 0x0d7e +#define RTL8367C_SVLAN_C2SCFG42_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG42_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL1 0x0d7f +#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG42_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG42_CTRL2 0x0d80 +#define RTL8367C_SVLAN_C2SCFG42_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG42_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL0 0x0d81 +#define RTL8367C_SVLAN_C2SCFG43_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG43_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL1 0x0d82 +#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG43_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG43_CTRL2 0x0d83 +#define RTL8367C_SVLAN_C2SCFG43_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG43_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL0 0x0d84 +#define RTL8367C_SVLAN_C2SCFG44_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG44_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL1 0x0d85 +#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG44_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG44_CTRL2 0x0d86 +#define RTL8367C_SVLAN_C2SCFG44_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG44_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL0 0x0d87 +#define RTL8367C_SVLAN_C2SCFG45_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG45_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL1 0x0d88 +#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG45_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG45_CTRL2 0x0d89 +#define RTL8367C_SVLAN_C2SCFG45_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG45_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL0 0x0d8a +#define RTL8367C_SVLAN_C2SCFG46_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG46_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL1 0x0d8b +#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG46_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG46_CTRL2 0x0d8c +#define RTL8367C_SVLAN_C2SCFG46_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG46_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL0 0x0d8d +#define RTL8367C_SVLAN_C2SCFG47_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG47_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL1 0x0d8e +#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG47_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG47_CTRL2 0x0d8f +#define RTL8367C_SVLAN_C2SCFG47_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG47_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL0 0x0d90 +#define RTL8367C_SVLAN_C2SCFG48_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG48_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL1 0x0d91 +#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG48_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG48_CTRL2 0x0d92 +#define RTL8367C_SVLAN_C2SCFG48_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG48_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL0 0x0d93 +#define RTL8367C_SVLAN_C2SCFG49_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG49_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL1 0x0d94 +#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG49_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG49_CTRL2 0x0d95 +#define RTL8367C_SVLAN_C2SCFG49_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG49_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL0 0x0d96 +#define RTL8367C_SVLAN_C2SCFG50_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG50_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL1 0x0d97 +#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG50_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG50_CTRL2 0x0d98 +#define RTL8367C_SVLAN_C2SCFG50_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG50_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL0 0x0d99 +#define RTL8367C_SVLAN_C2SCFG51_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG51_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL1 0x0d9a +#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG51_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG51_CTRL2 0x0d9b +#define RTL8367C_SVLAN_C2SCFG51_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG51_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL0 0x0d9c +#define RTL8367C_SVLAN_C2SCFG52_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG52_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL1 0x0d9d +#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG52_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG52_CTRL2 0x0d9e +#define RTL8367C_SVLAN_C2SCFG52_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG52_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL0 0x0d9f +#define RTL8367C_SVLAN_C2SCFG53_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG53_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL1 0x0da0 +#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG53_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG53_CTRL2 0x0da1 +#define RTL8367C_SVLAN_C2SCFG53_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG53_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL0 0x0da2 +#define RTL8367C_SVLAN_C2SCFG54_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG54_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL1 0x0da3 +#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG54_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG54_CTRL2 0x0da4 +#define RTL8367C_SVLAN_C2SCFG54_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG54_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL0 0x0da5 +#define RTL8367C_SVLAN_C2SCFG55_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG55_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL1 0x0da6 +#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG55_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG55_CTRL2 0x0da7 +#define RTL8367C_SVLAN_C2SCFG55_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG55_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL0 0x0da8 +#define RTL8367C_SVLAN_C2SCFG56_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG56_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL1 0x0da9 +#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG56_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG56_CTRL2 0x0daa +#define RTL8367C_SVLAN_C2SCFG56_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG56_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL0 0x0dab +#define RTL8367C_SVLAN_C2SCFG57_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG57_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL1 0x0dac +#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG57_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG57_CTRL2 0x0dad +#define RTL8367C_SVLAN_C2SCFG57_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG57_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL0 0x0dae +#define RTL8367C_SVLAN_C2SCFG58_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG58_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL1 0x0daf +#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG58_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG58_CTRL2 0x0db0 +#define RTL8367C_SVLAN_C2SCFG58_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG58_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL0 0x0db1 +#define RTL8367C_SVLAN_C2SCFG59_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG59_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL1 0x0db2 +#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG59_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG59_CTRL2 0x0db3 +#define RTL8367C_SVLAN_C2SCFG59_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG59_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL0 0x0db4 +#define RTL8367C_SVLAN_C2SCFG60_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG60_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL1 0x0db5 +#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG60_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG60_CTRL2 0x0db6 +#define RTL8367C_SVLAN_C2SCFG60_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG60_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL0 0x0db7 +#define RTL8367C_SVLAN_C2SCFG61_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG61_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL1 0x0db8 +#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG61_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG61_CTRL2 0x0db9 +#define RTL8367C_SVLAN_C2SCFG61_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG61_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL0 0x0dba +#define RTL8367C_SVLAN_C2SCFG62_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG62_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL1 0x0dbb +#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG62_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG62_CTRL2 0x0dbc +#define RTL8367C_SVLAN_C2SCFG62_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG62_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL0 0x0dbd +#define RTL8367C_SVLAN_C2SCFG63_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG63_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL1 0x0dbe +#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG63_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG63_CTRL2 0x0dbf +#define RTL8367C_SVLAN_C2SCFG63_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG63_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL0 0x0dc0 +#define RTL8367C_SVLAN_C2SCFG64_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG64_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL1 0x0dc1 +#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG64_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG64_CTRL2 0x0dc2 +#define RTL8367C_SVLAN_C2SCFG64_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG64_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL0 0x0dc3 +#define RTL8367C_SVLAN_C2SCFG65_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG65_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL1 0x0dc4 +#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG65_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG65_CTRL2 0x0dc5 +#define RTL8367C_SVLAN_C2SCFG65_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG65_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL0 0x0dc6 +#define RTL8367C_SVLAN_C2SCFG66_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG66_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL1 0x0dc7 +#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG66_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG66_CTRL2 0x0dc8 +#define RTL8367C_SVLAN_C2SCFG66_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG66_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL0 0x0dc9 +#define RTL8367C_SVLAN_C2SCFG67_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG67_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL1 0x0dca +#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG67_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG67_CTRL2 0x0dcb +#define RTL8367C_SVLAN_C2SCFG67_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG67_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL0 0x0dcc +#define RTL8367C_SVLAN_C2SCFG68_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG68_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL1 0x0dcd +#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG68_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG68_CTRL2 0x0dce +#define RTL8367C_SVLAN_C2SCFG68_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG68_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL0 0x0dcf +#define RTL8367C_SVLAN_C2SCFG69_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG69_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL1 0x0dd0 +#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG69_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG69_CTRL2 0x0dd1 +#define RTL8367C_SVLAN_C2SCFG69_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG69_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL0 0x0dd2 +#define RTL8367C_SVLAN_C2SCFG70_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG70_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL1 0x0dd3 +#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG70_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG70_CTRL2 0x0dd4 +#define RTL8367C_SVLAN_C2SCFG70_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG70_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL0 0x0dd5 +#define RTL8367C_SVLAN_C2SCFG71_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG71_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL1 0x0dd6 +#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG71_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG71_CTRL2 0x0dd7 +#define RTL8367C_SVLAN_C2SCFG71_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG71_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL0 0x0dd8 +#define RTL8367C_SVLAN_C2SCFG72_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG72_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL1 0x0dd9 +#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG72_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG72_CTRL2 0x0dda +#define RTL8367C_SVLAN_C2SCFG72_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG72_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL0 0x0ddb +#define RTL8367C_SVLAN_C2SCFG73_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG73_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL1 0x0ddc +#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG73_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG73_CTRL2 0x0ddd +#define RTL8367C_SVLAN_C2SCFG73_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG73_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL0 0x0dde +#define RTL8367C_SVLAN_C2SCFG74_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG74_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL1 0x0ddf +#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG74_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG74_CTRL2 0x0de0 +#define RTL8367C_SVLAN_C2SCFG74_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG74_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL0 0x0de1 +#define RTL8367C_SVLAN_C2SCFG75_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG75_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL1 0x0de2 +#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG75_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG75_CTRL2 0x0de3 +#define RTL8367C_SVLAN_C2SCFG75_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG75_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL0 0x0de4 +#define RTL8367C_SVLAN_C2SCFG76_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG76_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL1 0x0de5 +#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG76_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG76_CTRL2 0x0de6 +#define RTL8367C_SVLAN_C2SCFG76_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG76_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL0 0x0de7 +#define RTL8367C_SVLAN_C2SCFG77_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG77_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL1 0x0de8 +#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG77_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG77_CTRL2 0x0de9 +#define RTL8367C_SVLAN_C2SCFG77_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG77_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL0 0x0dea +#define RTL8367C_SVLAN_C2SCFG78_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG78_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL1 0x0deb +#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG78_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG78_CTRL2 0x0dec +#define RTL8367C_SVLAN_C2SCFG78_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG78_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL0 0x0ded +#define RTL8367C_SVLAN_C2SCFG79_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG79_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL1 0x0dee +#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG79_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG79_CTRL2 0x0def +#define RTL8367C_SVLAN_C2SCFG79_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG79_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL0 0x0df0 +#define RTL8367C_SVLAN_C2SCFG80_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG80_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL1 0x0df1 +#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG80_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG80_CTRL2 0x0df2 +#define RTL8367C_SVLAN_C2SCFG80_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG80_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL0 0x0df3 +#define RTL8367C_SVLAN_C2SCFG81_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG81_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL1 0x0df4 +#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG81_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG81_CTRL2 0x0df5 +#define RTL8367C_SVLAN_C2SCFG81_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG81_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL0 0x0df6 +#define RTL8367C_SVLAN_C2SCFG82_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG82_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL1 0x0df7 +#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG82_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG82_CTRL2 0x0df8 +#define RTL8367C_SVLAN_C2SCFG82_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG82_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL0 0x0df9 +#define RTL8367C_SVLAN_C2SCFG83_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG83_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL1 0x0dfa +#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG83_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG83_CTRL2 0x0dfb +#define RTL8367C_SVLAN_C2SCFG83_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG83_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL0 0x0dfc +#define RTL8367C_SVLAN_C2SCFG84_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG84_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL1 0x0dfd +#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG84_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG84_CTRL2 0x0dfe +#define RTL8367C_SVLAN_C2SCFG84_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG84_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL0 0x0dff +#define RTL8367C_SVLAN_C2SCFG85_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG85_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL1 0x0e00 +#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG85_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG85_CTRL2 0x0e01 +#define RTL8367C_SVLAN_C2SCFG85_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG85_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL0 0x0e02 +#define RTL8367C_SVLAN_C2SCFG86_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG86_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL1 0x0e03 +#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG86_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG86_CTRL2 0x0e04 +#define RTL8367C_SVLAN_C2SCFG86_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG86_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL0 0x0e05 +#define RTL8367C_SVLAN_C2SCFG87_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG87_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL1 0x0e06 +#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG87_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG87_CTRL2 0x0e07 +#define RTL8367C_SVLAN_C2SCFG87_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG87_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL0 0x0e08 +#define RTL8367C_SVLAN_C2SCFG88_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG88_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL1 0x0e09 +#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG88_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG88_CTRL2 0x0e0a +#define RTL8367C_SVLAN_C2SCFG88_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG88_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL0 0x0e0b +#define RTL8367C_SVLAN_C2SCFG89_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG89_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL1 0x0e0c +#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG89_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG89_CTRL2 0x0e0d +#define RTL8367C_SVLAN_C2SCFG89_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG89_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL0 0x0e0e +#define RTL8367C_SVLAN_C2SCFG90_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG90_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL1 0x0e0f +#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG90_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG90_CTRL2 0x0e10 +#define RTL8367C_SVLAN_C2SCFG90_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG90_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL0 0x0e11 +#define RTL8367C_SVLAN_C2SCFG91_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG91_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL1 0x0e12 +#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG91_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG91_CTRL2 0x0e13 +#define RTL8367C_SVLAN_C2SCFG91_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG91_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL0 0x0e14 +#define RTL8367C_SVLAN_C2SCFG92_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG92_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL1 0x0e15 +#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG92_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG92_CTRL2 0x0e16 +#define RTL8367C_SVLAN_C2SCFG92_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG92_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL0 0x0e17 +#define RTL8367C_SVLAN_C2SCFG93_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG93_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL1 0x0e18 +#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG93_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG93_CTRL2 0x0e19 +#define RTL8367C_SVLAN_C2SCFG93_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG93_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL0 0x0e1a +#define RTL8367C_SVLAN_C2SCFG94_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG94_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL1 0x0e1b +#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG94_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG94_CTRL2 0x0e1c +#define RTL8367C_SVLAN_C2SCFG94_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG94_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL0 0x0e1d +#define RTL8367C_SVLAN_C2SCFG95_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG95_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL1 0x0e1e +#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG95_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG95_CTRL2 0x0e1f +#define RTL8367C_SVLAN_C2SCFG95_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG95_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL0 0x0e20 +#define RTL8367C_SVLAN_C2SCFG96_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG96_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL1 0x0e21 +#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG96_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG96_CTRL2 0x0e22 +#define RTL8367C_SVLAN_C2SCFG96_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG96_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL0 0x0e23 +#define RTL8367C_SVLAN_C2SCFG97_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG97_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL1 0x0e24 +#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG97_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG97_CTRL2 0x0e25 +#define RTL8367C_SVLAN_C2SCFG97_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG97_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL0 0x0e26 +#define RTL8367C_SVLAN_C2SCFG98_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG98_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL1 0x0e27 +#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG98_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG98_CTRL2 0x0e28 +#define RTL8367C_SVLAN_C2SCFG98_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG98_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL0 0x0e29 +#define RTL8367C_SVLAN_C2SCFG99_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG99_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL1 0x0e2a +#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG99_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG99_CTRL2 0x0e2b +#define RTL8367C_SVLAN_C2SCFG99_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG99_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL0 0x0e2c +#define RTL8367C_SVLAN_C2SCFG100_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG100_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL1 0x0e2d +#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG100_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG100_CTRL2 0x0e2e +#define RTL8367C_SVLAN_C2SCFG100_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG100_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL0 0x0e2f +#define RTL8367C_SVLAN_C2SCFG101_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG101_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL1 0x0e30 +#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG101_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG101_CTRL2 0x0e31 +#define RTL8367C_SVLAN_C2SCFG101_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG101_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL0 0x0e32 +#define RTL8367C_SVLAN_C2SCFG102_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG102_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL1 0x0e33 +#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG102_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG102_CTRL2 0x0e34 +#define RTL8367C_SVLAN_C2SCFG102_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG102_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL0 0x0e35 +#define RTL8367C_SVLAN_C2SCFG103_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG103_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL1 0x0e36 +#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG103_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG103_CTRL2 0x0e37 +#define RTL8367C_SVLAN_C2SCFG103_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG103_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL0 0x0e38 +#define RTL8367C_SVLAN_C2SCFG104_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG104_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL1 0x0e39 +#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG104_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG104_CTRL2 0x0e3a +#define RTL8367C_SVLAN_C2SCFG104_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG104_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL0 0x0e3b +#define RTL8367C_SVLAN_C2SCFG105_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG105_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL1 0x0e3c +#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG105_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG105_CTRL2 0x0e3d +#define RTL8367C_SVLAN_C2SCFG105_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG105_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL0 0x0e3e +#define RTL8367C_SVLAN_C2SCFG106_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG106_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL1 0x0e3f +#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG106_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG106_CTRL2 0x0e40 +#define RTL8367C_SVLAN_C2SCFG106_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG106_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL0 0x0e41 +#define RTL8367C_SVLAN_C2SCFG107_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG107_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL1 0x0e42 +#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG107_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG107_CTRL2 0x0e43 +#define RTL8367C_SVLAN_C2SCFG107_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG107_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL0 0x0e44 +#define RTL8367C_SVLAN_C2SCFG108_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG108_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL1 0x0e45 +#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG108_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG108_CTRL2 0x0e46 +#define RTL8367C_SVLAN_C2SCFG108_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG108_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL0 0x0e47 +#define RTL8367C_SVLAN_C2SCFG109_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG109_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL1 0x0e48 +#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG109_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG109_CTRL2 0x0e49 +#define RTL8367C_SVLAN_C2SCFG109_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG109_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL0 0x0e4a +#define RTL8367C_SVLAN_C2SCFG110_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG110_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL1 0x0e4b +#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG110_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG110_CTRL2 0x0e4c +#define RTL8367C_SVLAN_C2SCFG110_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG110_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL0 0x0e4d +#define RTL8367C_SVLAN_C2SCFG111_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG111_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL1 0x0e4e +#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG111_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG111_CTRL2 0x0e4f +#define RTL8367C_SVLAN_C2SCFG111_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG111_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL0 0x0e50 +#define RTL8367C_SVLAN_C2SCFG112_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG112_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL1 0x0e51 +#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG112_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG112_CTRL2 0x0e52 +#define RTL8367C_SVLAN_C2SCFG112_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG112_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL0 0x0e53 +#define RTL8367C_SVLAN_C2SCFG113_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG113_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL1 0x0e54 +#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG113_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG113_CTRL2 0x0e55 +#define RTL8367C_SVLAN_C2SCFG113_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG113_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL0 0x0e56 +#define RTL8367C_SVLAN_C2SCFG114_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG114_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL1 0x0e57 +#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG114_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG114_CTRL2 0x0e58 +#define RTL8367C_SVLAN_C2SCFG114_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG114_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL0 0x0e59 +#define RTL8367C_SVLAN_C2SCFG115_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG115_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL1 0x0e5a +#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG115_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG115_CTRL2 0x0e5b +#define RTL8367C_SVLAN_C2SCFG115_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG115_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL0 0x0e5c +#define RTL8367C_SVLAN_C2SCFG116_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG116_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL1 0x0e5d +#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG116_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG116_CTRL2 0x0e5e +#define RTL8367C_SVLAN_C2SCFG116_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG116_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL0 0x0e5f +#define RTL8367C_SVLAN_C2SCFG117_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG117_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL1 0x0e60 +#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG117_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG117_CTRL2 0x0e61 +#define RTL8367C_SVLAN_C2SCFG117_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG117_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL0 0x0e62 +#define RTL8367C_SVLAN_C2SCFG118_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG118_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL1 0x0e63 +#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG118_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG118_CTRL2 0x0e64 +#define RTL8367C_SVLAN_C2SCFG118_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG118_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL0 0x0e65 +#define RTL8367C_SVLAN_C2SCFG119_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG119_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL1 0x0e66 +#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG119_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG119_CTRL2 0x0e67 +#define RTL8367C_SVLAN_C2SCFG119_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG119_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL0 0x0e68 +#define RTL8367C_SVLAN_C2SCFG120_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG120_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL1 0x0e69 +#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG120_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG120_CTRL2 0x0e6a +#define RTL8367C_SVLAN_C2SCFG120_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG120_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL0 0x0e6b +#define RTL8367C_SVLAN_C2SCFG121_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG121_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL1 0x0e6c +#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG121_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG121_CTRL2 0x0e6d +#define RTL8367C_SVLAN_C2SCFG121_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG121_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL0 0x0e6e +#define RTL8367C_SVLAN_C2SCFG122_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG122_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL1 0x0e6f +#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG122_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG122_CTRL2 0x0e70 +#define RTL8367C_SVLAN_C2SCFG122_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG122_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL0 0x0e71 +#define RTL8367C_SVLAN_C2SCFG123_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG123_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL1 0x0e72 +#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG123_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG123_CTRL2 0x0e73 +#define RTL8367C_SVLAN_C2SCFG123_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG123_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL0 0x0e74 +#define RTL8367C_SVLAN_C2SCFG124_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG124_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL1 0x0e75 +#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG124_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG124_CTRL2 0x0e76 +#define RTL8367C_SVLAN_C2SCFG124_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG124_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL0 0x0e77 +#define RTL8367C_SVLAN_C2SCFG125_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG125_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL1 0x0e78 +#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG125_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG125_CTRL2 0x0e79 +#define RTL8367C_SVLAN_C2SCFG125_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG125_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL0 0x0e7a +#define RTL8367C_SVLAN_C2SCFG126_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG126_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL1 0x0e7b +#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG126_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG126_CTRL2 0x0e7c +#define RTL8367C_SVLAN_C2SCFG126_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG126_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL0 0x0e7d +#define RTL8367C_SVLAN_C2SCFG127_CTRL0_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG127_CTRL0_MASK 0x3F + +#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL1 0x0e7e +#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_OFFSET 8 +#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_EXT_MASK 0x700 +#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG127_CTRL1_C2SENPMSK_MASK 0xFF + +#define RTL8367C_REG_SVLAN_C2SCFG127_CTRL2 0x0e7f +#define RTL8367C_SVLAN_C2SCFG127_CTRL2_OFFSET 0 +#define RTL8367C_SVLAN_C2SCFG127_CTRL2_MASK 0x1FFF + +#define RTL8367C_REG_SVLAN_CFG 0x0e80 +#define RTL8367C_VS_PORT7_DMACVIDSEL_OFFSET 14 +#define RTL8367C_VS_PORT7_DMACVIDSEL_MASK 0x4000 +#define RTL8367C_VS_PORT6_DMACVIDSEL_OFFSET 13 +#define RTL8367C_VS_PORT6_DMACVIDSEL_MASK 0x2000 +#define RTL8367C_VS_PORT5_DMACVIDSEL_OFFSET 12 +#define RTL8367C_VS_PORT5_DMACVIDSEL_MASK 0x1000 +#define RTL8367C_VS_PORT4_DMACVIDSEL_OFFSET 11 +#define RTL8367C_VS_PORT4_DMACVIDSEL_MASK 0x800 +#define RTL8367C_VS_PORT3_DMACVIDSEL_OFFSET 10 +#define RTL8367C_VS_PORT3_DMACVIDSEL_MASK 0x400 +#define RTL8367C_VS_PORT2_DMACVIDSEL_OFFSET 9 +#define RTL8367C_VS_PORT2_DMACVIDSEL_MASK 0x200 +#define RTL8367C_VS_PORT1_DMACVIDSEL_OFFSET 8 +#define RTL8367C_VS_PORT1_DMACVIDSEL_MASK 0x100 +#define RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET 7 +#define RTL8367C_VS_PORT0_DMACVIDSEL_MASK 0x80 +#define RTL8367C_VS_UIFSEG_OFFSET 6 +#define RTL8367C_VS_UIFSEG_MASK 0x40 +#define RTL8367C_VS_UNMAT_OFFSET 4 +#define RTL8367C_VS_UNMAT_MASK 0x30 +#define RTL8367C_VS_UNTAG_OFFSET 2 +#define RTL8367C_VS_UNTAG_MASK 0xC +#define RTL8367C_VS_SPRISEL_OFFSET 0 +#define RTL8367C_VS_SPRISEL_MASK 0x3 + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 0x0e81 +#define RTL8367C_VS_PORT1_SVIDX_OFFSET 8 +#define RTL8367C_VS_PORT1_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_PORT0_SVIDX_OFFSET 0 +#define RTL8367C_VS_PORT0_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL1 0x0e82 +#define RTL8367C_VS_PORT3_SVIDX_OFFSET 8 +#define RTL8367C_VS_PORT3_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_PORT2_SVIDX_OFFSET 0 +#define RTL8367C_VS_PORT2_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL2 0x0e83 +#define RTL8367C_VS_PORT5_SVIDX_OFFSET 8 +#define RTL8367C_VS_PORT5_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_PORT4_SVIDX_OFFSET 0 +#define RTL8367C_VS_PORT4_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL3 0x0e84 +#define RTL8367C_VS_PORT7_SVIDX_OFFSET 8 +#define RTL8367C_VS_PORT7_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_PORT6_SVIDX_OFFSET 0 +#define RTL8367C_VS_PORT6_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG 0x0e85 +#define RTL8367C_VS_UNTAG_SVIDX_OFFSET 8 +#define RTL8367C_VS_UNTAG_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_UNMAT_SVIDX_OFFSET 0 +#define RTL8367C_VS_UNMAT_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_LOOKUP_TYPE 0x0e86 +#define RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET 0 +#define RTL8367C_SVLAN_LOOKUP_TYPE_MASK 0x1 + +#define RTL8367C_REG_IPMC_GROUP_VALID_15_0 0x0e87 + +#define RTL8367C_REG_IPMC_GROUP_VALID_31_16 0x0e88 + +#define RTL8367C_REG_IPMC_GROUP_VALID_47_32 0x0e89 + +#define RTL8367C_REG_IPMC_GROUP_VALID_63_48 0x0e8a + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4 0x0e8b +#define RTL8367C_VS_PORT9_SVIDX_OFFSET 8 +#define RTL8367C_VS_PORT9_SVIDX_MASK 0x3F00 +#define RTL8367C_VS_PORT8_SVIDX_OFFSET 0 +#define RTL8367C_VS_PORT8_SVIDX_MASK 0x3F + +#define RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5 0x0e8c +#define RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_OFFSET 0 +#define RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK 0x3F + +#define RTL8367C_REG_SVLAN_CFG_EXT 0x0e8d +#define RTL8367C_VS_PORT10_DMACVIDSEL_OFFSET 2 +#define RTL8367C_VS_PORT10_DMACVIDSEL_MASK 0x4 +#define RTL8367C_VS_PORT9_DMACVIDSEL_OFFSET 1 +#define RTL8367C_VS_PORT9_DMACVIDSEL_MASK 0x2 +#define RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET 0 +#define RTL8367C_VS_PORT8_DMACVIDSEL_MASK 0x1 + +#define RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4 0x0e8e +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_OFFSET 8 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_UNTAGSET_EXT_MASK 0x700 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_OFFSET 0 +#define RTL8367C_SVLAN_MEMBERCFG63_CTRL4_VS_SMBR_EXT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_DUMMY_0 0x0e90 + +#define RTL8367C_REG_SVLAN_DUMMY_1 0x0e91 + +#define RTL8367C_REG_SVLAN_DUMMY_2 0x0e92 + +#define RTL8367C_REG_SVLAN_DUMMY_3 0x0e93 + +#define RTL8367C_REG_SVLAN_DUMMY_4 0x0e94 + +#define RTL8367C_REG_SVLAN_DUMMY_5 0x0e95 + +#define RTL8367C_REG_SVLAN_DUMMY_6 0x0e96 + +#define RTL8367C_REG_SVLAN_DUMMY_7 0x0e97 + +#define RTL8367C_REG_SVLAN_DUMMY_8 0x0e98 + +#define RTL8367C_REG_SVLAN_DUMMY_9 0x0e99 + +#define RTL8367C_REG_SVLAN_DUMMY_10 0x0e9a + +#define RTL8367C_REG_SVLAN_DUMMY_11 0x0e9b + +#define RTL8367C_REG_SVLAN_DUMMY_12 0x0e9c + +#define RTL8367C_REG_SVLAN_DUMMY_13 0x0e9d + +#define RTL8367C_REG_SVLAN_DUMMY_14 0x0e9e + +#define RTL8367C_REG_SVLAN_DUMMY_15 0x0e9f + +#define RTL8367C_REG_SVLAN_DUMMY_16 0x0ea0 + +#define RTL8367C_REG_SVLAN_DUMMY_17 0x0ea1 + +#define RTL8367C_REG_SVLAN_DUMMY_18 0x0ea2 + +#define RTL8367C_REG_SVLAN_DUMMY_19 0x0ea3 + +#define RTL8367C_REG_SVLAN_DUMMY_20 0x0ea4 + +#define RTL8367C_REG_SVLAN_DUMMY_21 0x0ea5 + +#define RTL8367C_REG_SVLAN_DUMMY_22 0x0ea6 + +#define RTL8367C_REG_SVLAN_DUMMY_23 0x0ea7 + +#define RTL8367C_REG_SVLAN_DUMMY_24 0x0ea8 + +#define RTL8367C_REG_SVLAN_DUMMY_25 0x0ea9 + +#define RTL8367C_REG_SVLAN_DUMMY_26 0x0eaa + +#define RTL8367C_REG_SVLAN_DUMMY_27 0x0eab + +#define RTL8367C_REG_SVLAN_DUMMY_28 0x0eac + +#define RTL8367C_REG_SVLAN_DUMMY_29 0x0ead + +#define RTL8367C_REG_SVLAN_DUMMY_30 0x0eae + +#define RTL8367C_REG_SVLAN_DUMMY_31 0x0eaf + +#define RTL8367C_REG_IPMC_GROUP_VID_00 0x0eb0 +#define RTL8367C_IPMC_GROUP_VID_00_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_00_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_01 0x0eb1 +#define RTL8367C_IPMC_GROUP_VID_01_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_01_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_02 0x0eb2 +#define RTL8367C_IPMC_GROUP_VID_02_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_02_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_03 0x0eb3 +#define RTL8367C_IPMC_GROUP_VID_03_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_03_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_04 0x0eb4 +#define RTL8367C_IPMC_GROUP_VID_04_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_04_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_05 0x0eb5 +#define RTL8367C_IPMC_GROUP_VID_05_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_05_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_06 0x0eb6 +#define RTL8367C_IPMC_GROUP_VID_06_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_06_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_07 0x0eb7 +#define RTL8367C_IPMC_GROUP_VID_07_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_07_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_08 0x0eb8 +#define RTL8367C_IPMC_GROUP_VID_08_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_08_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_09 0x0eb9 +#define RTL8367C_IPMC_GROUP_VID_09_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_09_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_10 0x0eba +#define RTL8367C_IPMC_GROUP_VID_10_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_10_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_11 0x0ebb +#define RTL8367C_IPMC_GROUP_VID_11_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_11_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_12 0x0ebc +#define RTL8367C_IPMC_GROUP_VID_12_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_12_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_13 0x0ebd +#define RTL8367C_IPMC_GROUP_VID_13_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_13_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_14 0x0ebe +#define RTL8367C_IPMC_GROUP_VID_14_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_14_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_15 0x0ebf +#define RTL8367C_IPMC_GROUP_VID_15_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_15_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_16 0x0ec0 +#define RTL8367C_IPMC_GROUP_VID_16_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_16_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_17 0x0ec1 +#define RTL8367C_IPMC_GROUP_VID_17_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_17_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_18 0x0ec2 +#define RTL8367C_IPMC_GROUP_VID_18_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_18_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_19 0x0ec3 +#define RTL8367C_IPMC_GROUP_VID_19_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_19_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_20 0x0ec4 +#define RTL8367C_IPMC_GROUP_VID_20_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_20_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_21 0x0ec5 +#define RTL8367C_IPMC_GROUP_VID_21_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_21_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_22 0x0ec6 +#define RTL8367C_IPMC_GROUP_VID_22_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_22_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_23 0x0ec7 +#define RTL8367C_IPMC_GROUP_VID_23_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_23_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_24 0x0ec8 +#define RTL8367C_IPMC_GROUP_VID_24_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_24_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_25 0x0ec9 +#define RTL8367C_IPMC_GROUP_VID_25_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_25_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_26 0x0eca +#define RTL8367C_IPMC_GROUP_VID_26_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_26_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_27 0x0ecb +#define RTL8367C_IPMC_GROUP_VID_27_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_27_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_28 0x0ecc +#define RTL8367C_IPMC_GROUP_VID_28_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_28_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_29 0x0ecd +#define RTL8367C_IPMC_GROUP_VID_29_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_29_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_30 0x0ece +#define RTL8367C_IPMC_GROUP_VID_30_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_30_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_31 0x0ecf +#define RTL8367C_IPMC_GROUP_VID_31_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_31_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_32 0x0ed0 +#define RTL8367C_IPMC_GROUP_VID_32_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_32_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_33 0x0ed1 +#define RTL8367C_IPMC_GROUP_VID_33_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_33_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_34 0x0ed2 +#define RTL8367C_IPMC_GROUP_VID_34_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_34_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_35 0x0ed3 +#define RTL8367C_IPMC_GROUP_VID_35_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_35_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_36 0x0ed4 +#define RTL8367C_IPMC_GROUP_VID_36_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_36_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_37 0x0ed5 +#define RTL8367C_IPMC_GROUP_VID_37_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_37_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_38 0x0ed6 +#define RTL8367C_IPMC_GROUP_VID_38_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_38_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_39 0x0ed7 +#define RTL8367C_IPMC_GROUP_VID_39_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_39_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_40 0x0ed8 +#define RTL8367C_IPMC_GROUP_VID_40_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_40_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_41 0x0ed9 +#define RTL8367C_IPMC_GROUP_VID_41_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_41_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_42 0x0eda +#define RTL8367C_IPMC_GROUP_VID_42_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_42_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_43 0x0edb +#define RTL8367C_IPMC_GROUP_VID_43_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_43_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_44 0x0edc +#define RTL8367C_IPMC_GROUP_VID_44_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_44_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_45 0x0edd +#define RTL8367C_IPMC_GROUP_VID_45_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_45_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_46 0x0ede +#define RTL8367C_IPMC_GROUP_VID_46_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_46_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_47 0x0edf +#define RTL8367C_IPMC_GROUP_VID_47_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_47_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_48 0x0ef0 +#define RTL8367C_IPMC_GROUP_VID_48_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_48_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_49 0x0ef1 +#define RTL8367C_IPMC_GROUP_VID_49_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_49_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_50 0x0ef2 +#define RTL8367C_IPMC_GROUP_VID_50_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_50_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_51 0x0ef3 +#define RTL8367C_IPMC_GROUP_VID_51_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_51_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_52 0x0ef4 +#define RTL8367C_IPMC_GROUP_VID_52_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_52_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_53 0x0ef5 +#define RTL8367C_IPMC_GROUP_VID_53_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_53_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_54 0x0ef6 +#define RTL8367C_IPMC_GROUP_VID_54_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_54_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_55 0x0ef7 +#define RTL8367C_IPMC_GROUP_VID_55_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_55_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_56 0x0ef8 +#define RTL8367C_IPMC_GROUP_VID_56_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_56_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_57 0x0ef9 +#define RTL8367C_IPMC_GROUP_VID_57_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_57_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_58 0x0efa +#define RTL8367C_IPMC_GROUP_VID_58_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_58_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_59 0x0efb +#define RTL8367C_IPMC_GROUP_VID_59_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_59_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_60 0x0efc +#define RTL8367C_IPMC_GROUP_VID_60_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_60_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_61 0x0efd +#define RTL8367C_IPMC_GROUP_VID_61_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_61_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_62 0x0efe +#define RTL8367C_IPMC_GROUP_VID_62_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_62_MASK 0xFFF + +#define RTL8367C_REG_IPMC_GROUP_VID_63 0x0eff +#define RTL8367C_IPMC_GROUP_VID_63_OFFSET 0 +#define RTL8367C_IPMC_GROUP_VID_63_MASK 0xFFF + +/* (16'h0f00)hsactrl_reg */ + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL0 0x0f00 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY0_CTRL1 0x0f01 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY0_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL0 0x0f02 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY1_CTRL1 0x0f03 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY1_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL0 0x0f04 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY2_CTRL1 0x0f05 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY2_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL0 0x0f06 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY3_CTRL1 0x0f07 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY3_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL0 0x0f08 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY4_CTRL1 0x0f09 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY4_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL0 0x0f0a +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY5_CTRL1 0x0f0b +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY5_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL0 0x0f0c +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY6_CTRL1 0x0f0d +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY6_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL0 0x0f0e +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY7_CTRL1 0x0f0f +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY7_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL0 0x0f10 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY8_CTRL1 0x0f11 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY8_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL0 0x0f12 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY9_CTRL1 0x0f13 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY9_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL0 0x0f14 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY10_CTRL1 0x0f15 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY10_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL0 0x0f16 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY11_CTRL1 0x0f17 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY11_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL0 0x0f18 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY12_CTRL1 0x0f19 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY12_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL0 0x0f1a +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY13_CTRL1 0x0f1b +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY13_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL0 0x0f1c +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY14_CTRL1 0x0f1d +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY14_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL0 0x0f1e +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY15_CTRL1 0x0f1f +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY15_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL0 0x0f20 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY16_CTRL1 0x0f21 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY16_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL0 0x0f22 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY17_CTRL1 0x0f23 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY17_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL0 0x0f24 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY18_CTRL1 0x0f25 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY18_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL0 0x0f26 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY19_CTRL1 0x0f27 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY19_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL0 0x0f28 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY20_CTRL1 0x0f29 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY20_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL0 0x0f2a +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY21_CTRL1 0x0f2b +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY21_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL0 0x0f2c +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY22_CTRL1 0x0f2d +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY22_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL0 0x0f2e +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY23_CTRL1 0x0f2f +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY23_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL0 0x0f30 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY24_CTRL1 0x0f31 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY24_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL0 0x0f32 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY25_CTRL1 0x0f33 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY25_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL0 0x0f34 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY26_CTRL1 0x0f35 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY26_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL0 0x0f36 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY27_CTRL1 0x0f37 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY27_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL0 0x0f38 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY28_CTRL1 0x0f39 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY28_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL0 0x0f3a +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY29_CTRL1 0x0f3b +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY29_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL0 0x0f3c +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY30_CTRL1 0x0f3d +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY30_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL0 0x0f3e +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY31_CTRL1 0x0f3f +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY31_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL0 0x0f40 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY32_CTRL1 0x0f41 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY32_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL0 0x0f42 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY33_CTRL1 0x0f43 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY33_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL0 0x0f44 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY34_CTRL1 0x0f45 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY34_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL0 0x0f46 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY35_CTRL1 0x0f47 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY35_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL0 0x0f48 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY36_CTRL1 0x0f49 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY36_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL0 0x0f4a +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY37_CTRL1 0x0f4b +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY37_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL0 0x0f4c +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY38_CTRL1 0x0f4d +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY38_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL0 0x0f4e +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY39_CTRL1 0x0f4f +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY39_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL0 0x0f50 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY40_CTRL1 0x0f51 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY40_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL0 0x0f52 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY41_CTRL1 0x0f53 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY41_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL0 0x0f54 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY42_CTRL1 0x0f55 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY42_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL0 0x0f56 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY43_CTRL1 0x0f57 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY43_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL0 0x0f58 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY44_CTRL1 0x0f59 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY44_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL0 0x0f5a +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY45_CTRL1 0x0f5b +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY45_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL0 0x0f5c +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY46_CTRL1 0x0f5d +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY46_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL0 0x0f5e +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY47_CTRL1 0x0f5f +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY47_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL0 0x0f60 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY48_CTRL1 0x0f61 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY48_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL0 0x0f62 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY49_CTRL1 0x0f63 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY49_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL0 0x0f64 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY50_CTRL1 0x0f65 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY50_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL0 0x0f66 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY51_CTRL1 0x0f67 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY51_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL0 0x0f68 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY52_CTRL1 0x0f69 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY52_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL0 0x0f6a +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY53_CTRL1 0x0f6b +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY53_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL0 0x0f6c +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY54_CTRL1 0x0f6d +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY54_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL0 0x0f6e +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY55_CTRL1 0x0f6f +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY55_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL0 0x0f70 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY56_CTRL1 0x0f71 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY56_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL0 0x0f72 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY57_CTRL1 0x0f73 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY57_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL0 0x0f74 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY58_CTRL1 0x0f75 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY58_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL0 0x0f76 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY59_CTRL1 0x0f77 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY59_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL0 0x0f78 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY60_CTRL1 0x0f79 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY60_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL0 0x0f7a +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY61_CTRL1 0x0f7b +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY61_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL0 0x0f7c +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY62_CTRL1 0x0f7d +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY62_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL0 0x0f7e +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY63_CTRL1 0x0f7f +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY63_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL0 0x0f80 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY64_CTRL1 0x0f81 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY64_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL0 0x0f82 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY65_CTRL1 0x0f83 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY65_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL0 0x0f84 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY66_CTRL1 0x0f85 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY66_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL0 0x0f86 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY67_CTRL1 0x0f87 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY67_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL0 0x0f88 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY68_CTRL1 0x0f89 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY68_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL0 0x0f8a +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY69_CTRL1 0x0f8b +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY69_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL0 0x0f8c +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY70_CTRL1 0x0f8d +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY70_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL0 0x0f8e +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY71_CTRL1 0x0f8f +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY71_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL0 0x0f90 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY72_CTRL1 0x0f91 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY72_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL0 0x0f92 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY73_CTRL1 0x0f93 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY73_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL0 0x0f94 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY74_CTRL1 0x0f95 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY74_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL0 0x0f96 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY75_CTRL1 0x0f97 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY75_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL0 0x0f98 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY76_CTRL1 0x0f99 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY76_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL0 0x0f9a +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY77_CTRL1 0x0f9b +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY77_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL0 0x0f9c +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY78_CTRL1 0x0f9d +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY78_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL0 0x0f9e +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY79_CTRL1 0x0f9f +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY79_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL0 0x0fa0 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY80_CTRL1 0x0fa1 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY80_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL0 0x0fa2 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY81_CTRL1 0x0fa3 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY81_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL0 0x0fa4 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY82_CTRL1 0x0fa5 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY82_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL0 0x0fa6 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY83_CTRL1 0x0fa7 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY83_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL0 0x0fa8 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY84_CTRL1 0x0fa9 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY84_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL0 0x0faa +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY85_CTRL1 0x0fab +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY85_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL0 0x0fac +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY86_CTRL1 0x0fad +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY86_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL0 0x0fae +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY87_CTRL1 0x0faf +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY87_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL0 0x0fb0 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY88_CTRL1 0x0fb1 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY88_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL0 0x0fb2 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY89_CTRL1 0x0fb3 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY89_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL0 0x0fb4 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY90_CTRL1 0x0fb5 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY90_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL0 0x0fb6 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY91_CTRL1 0x0fb7 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY91_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL0 0x0fb8 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY92_CTRL1 0x0fb9 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY92_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL0 0x0fba +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY93_CTRL1 0x0fbb +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY93_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL0 0x0fbc +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY94_CTRL1 0x0fbd +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY94_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL0 0x0fbe +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY95_CTRL1 0x0fbf +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY95_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL0 0x0fc0 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY96_CTRL1 0x0fc1 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY96_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL0 0x0fc2 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY97_CTRL1 0x0fc3 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY97_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL0 0x0fc4 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY98_CTRL1 0x0fc5 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY98_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL0 0x0fc6 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY99_CTRL1 0x0fc7 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY99_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL0 0x0fc8 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY100_CTRL1 0x0fc9 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY100_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL0 0x0fca +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY101_CTRL1 0x0fcb +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY101_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL0 0x0fcc +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY102_CTRL1 0x0fcd +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY102_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL0 0x0fce +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY103_CTRL1 0x0fcf +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY103_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL0 0x0fd0 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY104_CTRL1 0x0fd1 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY104_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL0 0x0fd2 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY105_CTRL1 0x0fd3 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY105_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL0 0x0fd4 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY106_CTRL1 0x0fd5 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY106_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL0 0x0fd6 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY107_CTRL1 0x0fd7 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY107_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL0 0x0fd8 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY108_CTRL1 0x0fd9 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY108_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL0 0x0fda +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY109_CTRL1 0x0fdb +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY109_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL0 0x0fdc +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY110_CTRL1 0x0fdd +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY110_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL0 0x0fde +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY111_CTRL1 0x0fdf +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY111_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL0 0x0fe0 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY112_CTRL1 0x0fe1 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY112_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL0 0x0fe2 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY113_CTRL1 0x0fe3 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY113_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL0 0x0fe4 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY114_CTRL1 0x0fe5 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY114_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL0 0x0fe6 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY115_CTRL1 0x0fe7 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY115_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL0 0x0fe8 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY116_CTRL1 0x0fe9 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY116_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL0 0x0fea +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY117_CTRL1 0x0feb +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY117_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL0 0x0fec +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY118_CTRL1 0x0fed +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY118_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL0 0x0fee +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY119_CTRL1 0x0fef +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY119_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL0 0x0ff0 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY120_CTRL1 0x0ff1 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY120_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL0 0x0ff2 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY121_CTRL1 0x0ff3 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY121_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL0 0x0ff4 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY122_CTRL1 0x0ff5 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY122_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL0 0x0ff6 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY123_CTRL1 0x0ff7 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY123_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL0 0x0ff8 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY124_CTRL1 0x0ff9 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY124_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL0 0x0ffa +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY125_CTRL1 0x0ffb +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY125_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL0 0x0ffc +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY126_CTRL1 0x0ffd +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY126_CTRL1_VID_MASK 0xFFF + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL0 0x0ffe +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_OFFSET 9 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT1_MASK 0x200 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_OFFSET 3 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_SVIDX_MASK 0x1F8 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL0_DST_PORT_MASK 0x7 + +#define RTL8367C_REG_SVLAN_SP2C_ENTRY127_CTRL1 0x0fff +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_OFFSET 12 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VALID_MASK 0x1000 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_OFFSET 0 +#define RTL8367C_SVLAN_SP2C_ENTRY127_CTRL1_VID_MASK 0xFFF + +/* (16'h1000)mib_reg */ + +#define RTL8367C_REG_MIB_COUNTER0 0x1000 + +#define RTL8367C_REG_MIB_COUNTER1 0x1001 + +#define RTL8367C_REG_MIB_COUNTER2 0x1002 + +#define RTL8367C_REG_MIB_COUNTER3 0x1003 + +#define RTL8367C_REG_MIB_ADDRESS 0x1004 +#define RTL8367C_MIB_ADDRESS_OFFSET 0 +#define RTL8367C_MIB_ADDRESS_MASK 0x1FF + +#define RTL8367C_REG_MIB_CTRL0 0x1005 +#define RTL8367C_PORT10_RESET_OFFSET 15 +#define RTL8367C_PORT10_RESET_MASK 0x8000 +#define RTL8367C_PORT9_RESET_OFFSET 14 +#define RTL8367C_PORT9_RESET_MASK 0x4000 +#define RTL8367C_PORT8_RESET_OFFSET 13 +#define RTL8367C_PORT8_RESET_MASK 0x2000 +#define RTL8367C_RESET_VALUE_OFFSET 12 +#define RTL8367C_RESET_VALUE_MASK 0x1000 +#define RTL8367C_GLOBAL_RESET_OFFSET 11 +#define RTL8367C_GLOBAL_RESET_MASK 0x800 +#define RTL8367C_QM_RESET_OFFSET 10 +#define RTL8367C_QM_RESET_MASK 0x400 +#define RTL8367C_PORT7_RESET_OFFSET 9 +#define RTL8367C_PORT7_RESET_MASK 0x200 +#define RTL8367C_PORT6_RESET_OFFSET 8 +#define RTL8367C_PORT6_RESET_MASK 0x100 +#define RTL8367C_PORT5_RESET_OFFSET 7 +#define RTL8367C_PORT5_RESET_MASK 0x80 +#define RTL8367C_PORT4_RESET_OFFSET 6 +#define RTL8367C_PORT4_RESET_MASK 0x40 +#define RTL8367C_PORT3_RESET_OFFSET 5 +#define RTL8367C_PORT3_RESET_MASK 0x20 +#define RTL8367C_PORT2_RESET_OFFSET 4 +#define RTL8367C_PORT2_RESET_MASK 0x10 +#define RTL8367C_PORT1_RESET_OFFSET 3 +#define RTL8367C_PORT1_RESET_MASK 0x8 +#define RTL8367C_PORT0_RESET_OFFSET 2 +#define RTL8367C_PORT0_RESET_MASK 0x4 +#define RTL8367C_RESET_FLAG_OFFSET 1 +#define RTL8367C_RESET_FLAG_MASK 0x2 +#define RTL8367C_MIB_CTRL0_BUSY_FLAG_OFFSET 0 +#define RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK 0x1 + +#define RTL8367C_REG_MIB_CTRL1 0x1007 +#define RTL8367C_COUNTER15_RESET_OFFSET 15 +#define RTL8367C_COUNTER15_RESET_MASK 0x8000 +#define RTL8367C_COUNTER14_RESET_OFFSET 14 +#define RTL8367C_COUNTER14_RESET_MASK 0x4000 +#define RTL8367C_COUNTER13_RESET_OFFSET 13 +#define RTL8367C_COUNTER13_RESET_MASK 0x2000 +#define RTL8367C_COUNTER12_RESET_OFFSET 12 +#define RTL8367C_COUNTER12_RESET_MASK 0x1000 +#define RTL8367C_COUNTER11_RESET_OFFSET 11 +#define RTL8367C_COUNTER11_RESET_MASK 0x800 +#define RTL8367C_COUNTER10_RESET_OFFSET 10 +#define RTL8367C_COUNTER10_RESET_MASK 0x400 +#define RTL8367C_COUNTER9_RESET_OFFSET 9 +#define RTL8367C_COUNTER9_RESET_MASK 0x200 +#define RTL8367C_COUNTER8_RESET_OFFSET 8 +#define RTL8367C_COUNTER8_RESET_MASK 0x100 +#define RTL8367C_COUNTER7_RESET_OFFSET 7 +#define RTL8367C_COUNTER7_RESET_MASK 0x80 +#define RTL8367C_COUNTER6_RESET_OFFSET 6 +#define RTL8367C_COUNTER6_RESET_MASK 0x40 +#define RTL8367C_COUNTER5_RESET_OFFSET 5 +#define RTL8367C_COUNTER5_RESET_MASK 0x20 +#define RTL8367C_COUNTER4_RESET_OFFSET 4 +#define RTL8367C_COUNTER4_RESET_MASK 0x10 +#define RTL8367C_COUNTER3_RESET_OFFSET 3 +#define RTL8367C_COUNTER3_RESET_MASK 0x8 +#define RTL8367C_COUNTER2_RESET_OFFSET 2 +#define RTL8367C_COUNTER2_RESET_MASK 0x4 +#define RTL8367C_COUNTER1_RESET_OFFSET 1 +#define RTL8367C_COUNTER1_RESET_MASK 0x2 +#define RTL8367C_COUNTER0_RESET_OFFSET 0 +#define RTL8367C_COUNTER0_RESET_MASK 0x1 + +#define RTL8367C_REG_MIB_CTRL2 0x1008 +#define RTL8367C_COUNTER31_RESET_OFFSET 15 +#define RTL8367C_COUNTER31_RESET_MASK 0x8000 +#define RTL8367C_COUNTER30_RESET_OFFSET 14 +#define RTL8367C_COUNTER30_RESET_MASK 0x4000 +#define RTL8367C_COUNTER29_RESET_OFFSET 13 +#define RTL8367C_COUNTER29_RESET_MASK 0x2000 +#define RTL8367C_COUNTER28_RESET_OFFSET 12 +#define RTL8367C_COUNTER28_RESET_MASK 0x1000 +#define RTL8367C_COUNTER27_RESET_OFFSET 11 +#define RTL8367C_COUNTER27_RESET_MASK 0x800 +#define RTL8367C_COUNTER26_RESET_OFFSET 10 +#define RTL8367C_COUNTER26_RESET_MASK 0x400 +#define RTL8367C_COUNTER25_RESET_OFFSET 9 +#define RTL8367C_COUNTER25_RESET_MASK 0x200 +#define RTL8367C_COUNTER24_RESET_OFFSET 8 +#define RTL8367C_COUNTER24_RESET_MASK 0x100 +#define RTL8367C_COUNTER23_RESET_OFFSET 7 +#define RTL8367C_COUNTER23_RESET_MASK 0x80 +#define RTL8367C_COUNTER22_RESET_OFFSET 6 +#define RTL8367C_COUNTER22_RESET_MASK 0x40 +#define RTL8367C_COUNTER21_RESET_OFFSET 5 +#define RTL8367C_COUNTER21_RESET_MASK 0x20 +#define RTL8367C_COUNTER20_RESET_OFFSET 4 +#define RTL8367C_COUNTER20_RESET_MASK 0x10 +#define RTL8367C_COUNTER19_RESET_OFFSET 3 +#define RTL8367C_COUNTER19_RESET_MASK 0x8 +#define RTL8367C_COUNTER18_RESET_OFFSET 2 +#define RTL8367C_COUNTER18_RESET_MASK 0x4 +#define RTL8367C_COUNTER17_RESET_OFFSET 1 +#define RTL8367C_COUNTER17_RESET_MASK 0x2 +#define RTL8367C_COUNTER16_RESET_OFFSET 0 +#define RTL8367C_COUNTER16_RESET_MASK 0x1 + +#define RTL8367C_REG_MIB_CTRL3 0x1009 +#define RTL8367C_COUNTER15_MODE_OFFSET 15 +#define RTL8367C_COUNTER15_MODE_MASK 0x8000 +#define RTL8367C_COUNTER14_MODE_OFFSET 14 +#define RTL8367C_COUNTER14_MODE_MASK 0x4000 +#define RTL8367C_COUNTER13_MODE_OFFSET 13 +#define RTL8367C_COUNTER13_MODE_MASK 0x2000 +#define RTL8367C_COUNTER12_MODE_OFFSET 12 +#define RTL8367C_COUNTER12_MODE_MASK 0x1000 +#define RTL8367C_COUNTER11_MODE_OFFSET 11 +#define RTL8367C_COUNTER11_MODE_MASK 0x800 +#define RTL8367C_COUNTER10_MODE_OFFSET 10 +#define RTL8367C_COUNTER10_MODE_MASK 0x400 +#define RTL8367C_COUNTER9_MODE_OFFSET 9 +#define RTL8367C_COUNTER9_MODE_MASK 0x200 +#define RTL8367C_COUNTER8_MODE_OFFSET 8 +#define RTL8367C_COUNTER8_MODE_MASK 0x100 +#define RTL8367C_COUNTER7_MODE_OFFSET 7 +#define RTL8367C_COUNTER7_MODE_MASK 0x80 +#define RTL8367C_COUNTER6_MODE_OFFSET 6 +#define RTL8367C_COUNTER6_MODE_MASK 0x40 +#define RTL8367C_COUNTER5_MODE_OFFSET 5 +#define RTL8367C_COUNTER5_MODE_MASK 0x20 +#define RTL8367C_COUNTER4_MODE_OFFSET 4 +#define RTL8367C_COUNTER4_MODE_MASK 0x10 +#define RTL8367C_COUNTER3_MODE_OFFSET 3 +#define RTL8367C_COUNTER3_MODE_MASK 0x8 +#define RTL8367C_COUNTER2_MODE_OFFSET 2 +#define RTL8367C_COUNTER2_MODE_MASK 0x4 +#define RTL8367C_COUNTER1_MODE_OFFSET 1 +#define RTL8367C_COUNTER1_MODE_MASK 0x2 +#define RTL8367C_COUNTER0_MODE_OFFSET 0 +#define RTL8367C_COUNTER0_MODE_MASK 0x1 + +#define RTL8367C_REG_MIB_CTRL4 0x100a +#define RTL8367C_MIB_USAGE_MODE_OFFSET 8 +#define RTL8367C_MIB_USAGE_MODE_MASK 0x100 +#define RTL8367C_MIB_TIMER_OFFSET 0 +#define RTL8367C_MIB_TIMER_MASK 0xFF + +#define RTL8367C_REG_MIB_CTRL5 0x100b +#define RTL8367C_MIB_CTRL5_COUNTER15_TYPE_OFFSET 15 +#define RTL8367C_MIB_CTRL5_COUNTER15_TYPE_MASK 0x8000 +#define RTL8367C_MIB_CTRL5_COUNTER14_TYPE_OFFSET 14 +#define RTL8367C_MIB_CTRL5_COUNTER14_TYPE_MASK 0x4000 +#define RTL8367C_MIB_CTRL5_COUNTER13_TYPE_OFFSET 13 +#define RTL8367C_MIB_CTRL5_COUNTER13_TYPE_MASK 0x2000 +#define RTL8367C_MIB_CTRL5_COUNTER12_TYPE_OFFSET 12 +#define RTL8367C_MIB_CTRL5_COUNTER12_TYPE_MASK 0x1000 +#define RTL8367C_MIB_CTRL5_COUNTER11_TYPE_OFFSET 11 +#define RTL8367C_MIB_CTRL5_COUNTER11_TYPE_MASK 0x800 +#define RTL8367C_MIB_CTRL5_COUNTER10_TYPE_OFFSET 10 +#define RTL8367C_MIB_CTRL5_COUNTER10_TYPE_MASK 0x400 +#define RTL8367C_MIB_CTRL5_COUNTER9_TYPE_OFFSET 9 +#define RTL8367C_MIB_CTRL5_COUNTER9_TYPE_MASK 0x200 +#define RTL8367C_MIB_CTRL5_COUNTER8_TYPE_OFFSET 8 +#define RTL8367C_MIB_CTRL5_COUNTER8_TYPE_MASK 0x100 +#define RTL8367C_MIB_CTRL5_COUNTER7_TYPE_OFFSET 7 +#define RTL8367C_MIB_CTRL5_COUNTER7_TYPE_MASK 0x80 +#define RTL8367C_MIB_CTRL5_COUNTER6_TYPE_OFFSET 6 +#define RTL8367C_MIB_CTRL5_COUNTER6_TYPE_MASK 0x40 +#define RTL8367C_MIB_CTRL5_COUNTER5_TYPE_OFFSET 5 +#define RTL8367C_MIB_CTRL5_COUNTER5_TYPE_MASK 0x20 +#define RTL8367C_MIB_CTRL5_COUNTER4_TYPE_OFFSET 4 +#define RTL8367C_MIB_CTRL5_COUNTER4_TYPE_MASK 0x10 +#define RTL8367C_MIB_CTRL5_COUNTER3_TYPE_OFFSET 3 +#define RTL8367C_MIB_CTRL5_COUNTER3_TYPE_MASK 0x8 +#define RTL8367C_MIB_CTRL5_COUNTER2_TYPE_OFFSET 2 +#define RTL8367C_MIB_CTRL5_COUNTER2_TYPE_MASK 0x4 +#define RTL8367C_MIB_CTRL5_COUNTER1_TYPE_OFFSET 1 +#define RTL8367C_MIB_CTRL5_COUNTER1_TYPE_MASK 0x2 +#define RTL8367C_MIB_CTRL5_COUNTER0_TYPE_OFFSET 0 +#define RTL8367C_MIB_CTRL5_COUNTER0_TYPE_MASK 0x1 + +/* (16'h1100)intrpt_reg */ + +#define RTL8367C_REG_INTR_CTRL 0x1100 +#define RTL8367C_INTR_CTRL_OFFSET 0 +#define RTL8367C_INTR_CTRL_MASK 0x1 + +#define RTL8367C_REG_INTR_IMR 0x1101 +#define RTL8367C_INTR_IMR_SLIENT_START_2_OFFSET 12 +#define RTL8367C_INTR_IMR_SLIENT_START_2_MASK 0x1000 +#define RTL8367C_INTR_IMR_SLIENT_START_OFFSET 11 +#define RTL8367C_INTR_IMR_SLIENT_START_MASK 0x800 +#define RTL8367C_INTR_IMR_ACL_ACTION_OFFSET 9 +#define RTL8367C_INTR_IMR_ACL_ACTION_MASK 0x200 +#define RTL8367C_INTR_IMR_CABLE_DIAG_FIN_OFFSET 8 +#define RTL8367C_INTR_IMR_CABLE_DIAG_FIN_MASK 0x100 +#define RTL8367C_INTR_IMR_INTERRUPT_8051_OFFSET 7 +#define RTL8367C_INTR_IMR_INTERRUPT_8051_MASK 0x80 +#define RTL8367C_INTR_IMR_LOOP_DETECTION_OFFSET 6 +#define RTL8367C_INTR_IMR_LOOP_DETECTION_MASK 0x40 +#define RTL8367C_INTR_IMR_GREEN_TIMER_OFFSET 5 +#define RTL8367C_INTR_IMR_GREEN_TIMER_MASK 0x20 +#define RTL8367C_INTR_IMR_SPECIAL_CONGEST_OFFSET 4 +#define RTL8367C_INTR_IMR_SPECIAL_CONGEST_MASK 0x10 +#define RTL8367C_INTR_IMR_SPEED_CHANGE_OFFSET 3 +#define RTL8367C_INTR_IMR_SPEED_CHANGE_MASK 0x8 +#define RTL8367C_INTR_IMR_LEARN_OVER_OFFSET 2 +#define RTL8367C_INTR_IMR_LEARN_OVER_MASK 0x4 +#define RTL8367C_INTR_IMR_METER_EXCEEDED_OFFSET 1 +#define RTL8367C_INTR_IMR_METER_EXCEEDED_MASK 0x2 +#define RTL8367C_INTR_IMR_LINK_CHANGE_OFFSET 0 +#define RTL8367C_INTR_IMR_LINK_CHANGE_MASK 0x1 + +#define RTL8367C_REG_INTR_IMS 0x1102 +#define RTL8367C_INTR_IMS_SLIENT_START_2_OFFSET 12 +#define RTL8367C_INTR_IMS_SLIENT_START_2_MASK 0x1000 +#define RTL8367C_INTR_IMS_SLIENT_START_OFFSET 11 +#define RTL8367C_INTR_IMS_SLIENT_START_MASK 0x800 +#define RTL8367C_INTR_IMS_ACL_ACTION_OFFSET 9 +#define RTL8367C_INTR_IMS_ACL_ACTION_MASK 0x200 +#define RTL8367C_INTR_IMS_CABLE_DIAG_FIN_OFFSET 8 +#define RTL8367C_INTR_IMS_CABLE_DIAG_FIN_MASK 0x100 +#define RTL8367C_INTR_IMS_INTERRUPT_8051_OFFSET 7 +#define RTL8367C_INTR_IMS_INTERRUPT_8051_MASK 0x80 +#define RTL8367C_INTR_IMS_LOOP_DETECTION_OFFSET 6 +#define RTL8367C_INTR_IMS_LOOP_DETECTION_MASK 0x40 +#define RTL8367C_INTR_IMS_GREEN_TIMER_OFFSET 5 +#define RTL8367C_INTR_IMS_GREEN_TIMER_MASK 0x20 +#define RTL8367C_INTR_IMS_SPECIAL_CONGEST_OFFSET 4 +#define RTL8367C_INTR_IMS_SPECIAL_CONGEST_MASK 0x10 +#define RTL8367C_INTR_IMS_SPEED_CHANGE_OFFSET 3 +#define RTL8367C_INTR_IMS_SPEED_CHANGE_MASK 0x8 +#define RTL8367C_INTR_IMS_LEARN_OVER_OFFSET 2 +#define RTL8367C_INTR_IMS_LEARN_OVER_MASK 0x4 +#define RTL8367C_INTR_IMS_METER_EXCEEDED_OFFSET 1 +#define RTL8367C_INTR_IMS_METER_EXCEEDED_MASK 0x2 +#define RTL8367C_INTR_IMS_LINK_CHANGE_OFFSET 0 +#define RTL8367C_INTR_IMS_LINK_CHANGE_MASK 0x1 + +#define RTL8367C_REG_LEARN_OVER_INDICATOR 0x1103 +#define RTL8367C_LEARN_OVER_INDICATOR_OFFSET 0 +#define RTL8367C_LEARN_OVER_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_SPEED_CHANGE_INDICATOR 0x1104 +#define RTL8367C_SPEED_CHANGE_INDICATOR_OFFSET 0 +#define RTL8367C_SPEED_CHANGE_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_SPECIAL_CONGEST_INDICATOR 0x1105 +#define RTL8367C_SPECIAL_CONGEST_INDICATOR_OFFSET 0 +#define RTL8367C_SPECIAL_CONGEST_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_PORT_LINKDOWN_INDICATOR 0x1106 +#define RTL8367C_PORT_LINKDOWN_INDICATOR_OFFSET 0 +#define RTL8367C_PORT_LINKDOWN_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_PORT_LINKUP_INDICATOR 0x1107 +#define RTL8367C_PORT_LINKUP_INDICATOR_OFFSET 0 +#define RTL8367C_PORT_LINKUP_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR 0x1108 +#define RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_OFFSET 0 +#define RTL8367C_SYSTEM_LEARN_OVER_INDICATOR_MASK 0x1 + +#define RTL8367C_REG_INTR_IMR_8051 0x1118 +#define RTL8367C_INTR_IMR_8051_SLIENT_START_2_OFFSET 13 +#define RTL8367C_INTR_IMR_8051_SLIENT_START_2_MASK 0x2000 +#define RTL8367C_INTR_IMR_8051_SLIENT_START_OFFSET 12 +#define RTL8367C_INTR_IMR_8051_SLIENT_START_MASK 0x1000 +#define RTL8367C_INTR_IMR_8051_ACL_ACTION_OFFSET 10 +#define RTL8367C_INTR_IMR_8051_ACL_ACTION_MASK 0x400 +#define RTL8367C_INTR_IMR_8051_SAMOVING_8051_OFFSET 9 +#define RTL8367C_INTR_IMR_8051_SAMOVING_8051_MASK 0x200 +#define RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_OFFSET 8 +#define RTL8367C_INTR_IMR_8051_CABLE_DIAG_FIN_8051_MASK 0x100 +#define RTL8367C_INTR_IMR_8051_EEELLDP_8051_OFFSET 7 +#define RTL8367C_INTR_IMR_8051_EEELLDP_8051_MASK 0x80 +#define RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_OFFSET 6 +#define RTL8367C_INTR_IMR_8051_LOOP_DETECTION_8051_MASK 0x40 +#define RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_OFFSET 5 +#define RTL8367C_INTR_IMR_8051_GREEN_TIMER_8051_MASK 0x20 +#define RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_OFFSET 4 +#define RTL8367C_INTR_IMR_8051_SPECIAL_CONGEST_8051_MASK 0x10 +#define RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_OFFSET 3 +#define RTL8367C_INTR_IMR_8051_SPEED_CHANGE_8051_MASK 0x8 +#define RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_OFFSET 2 +#define RTL8367C_INTR_IMR_8051_LEARN_OVER_8051_MASK 0x4 +#define RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_OFFSET 1 +#define RTL8367C_INTR_IMR_8051_METER_EXCEEDED_8051_MASK 0x2 +#define RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_OFFSET 0 +#define RTL8367C_INTR_IMR_8051_LINK_CHANGE_8051_MASK 0x1 + +#define RTL8367C_REG_INTR_IMS_8051 0x1119 +#define RTL8367C_INTR_IMS_8051_SLIENT_START_2_OFFSET 13 +#define RTL8367C_INTR_IMS_8051_SLIENT_START_2_MASK 0x2000 +#define RTL8367C_INTR_IMS_8051_SLIENT_START_OFFSET 12 +#define RTL8367C_INTR_IMS_8051_SLIENT_START_MASK 0x1000 +#define RTL8367C_INTR_IMS_8051_ACL_ACTION_OFFSET 10 +#define RTL8367C_INTR_IMS_8051_ACL_ACTION_MASK 0x400 +#define RTL8367C_INTR_IMS_8051_SAMOVING_8051_OFFSET 9 +#define RTL8367C_INTR_IMS_8051_SAMOVING_8051_MASK 0x200 +#define RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_OFFSET 8 +#define RTL8367C_INTR_IMS_8051_CABLE_DIAG_FIN_8051_MASK 0x100 +#define RTL8367C_INTR_IMS_8051_EEELLDP_8051_OFFSET 7 +#define RTL8367C_INTR_IMS_8051_EEELLDP_8051_MASK 0x80 +#define RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_OFFSET 6 +#define RTL8367C_INTR_IMS_8051_LOOP_DETECTION_8051_MASK 0x40 +#define RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_OFFSET 5 +#define RTL8367C_INTR_IMS_8051_GREEN_TIMER_8051_MASK 0x20 +#define RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_OFFSET 4 +#define RTL8367C_INTR_IMS_8051_SPECIAL_CONGEST_8051_MASK 0x10 +#define RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_OFFSET 3 +#define RTL8367C_INTR_IMS_8051_SPEED_CHANGE_8051_MASK 0x8 +#define RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_OFFSET 2 +#define RTL8367C_INTR_IMS_8051_LEARN_OVER_8051_MASK 0x4 +#define RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_OFFSET 1 +#define RTL8367C_INTR_IMS_8051_METER_EXCEEDED_8051_MASK 0x2 +#define RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_OFFSET 0 +#define RTL8367C_INTR_IMS_8051_LINK_CHANGE_8051_MASK 0x1 + +#define RTL8367C_REG_DW8051_INT_CPU 0x111a +#define RTL8367C_DW8051_INT_CPU_OFFSET 0 +#define RTL8367C_DW8051_INT_CPU_MASK 0x1 + +#define RTL8367C_REG_LEARN_OVER_INDICATOR_8051 0x1120 +#define RTL8367C_LEARN_OVER_INDICATOR_8051_OFFSET 0 +#define RTL8367C_LEARN_OVER_INDICATOR_8051_MASK 0x7FF + +#define RTL8367C_REG_SPEED_CHANGE_INDICATOR_8051 0x1121 +#define RTL8367C_SPEED_CHANGE_INDICATOR_8051_OFFSET 0 +#define RTL8367C_SPEED_CHANGE_INDICATOR_8051_MASK 0x7FF + +#define RTL8367C_REG_SPECIAL_CONGEST_INDICATOR_8051 0x1122 +#define RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_OFFSET 0 +#define RTL8367C_SPECIAL_CONGEST_INDICATOR_8051_MASK 0x7FF + +#define RTL8367C_REG_PORT_LINKDOWN_INDICATOR_8051 0x1123 +#define RTL8367C_PORT_LINKDOWN_INDICATOR_8051_OFFSET 0 +#define RTL8367C_PORT_LINKDOWN_INDICATOR_8051_MASK 0x7FF + +#define RTL8367C_REG_PORT_LINKUP_INDICATOR_8051 0x1124 +#define RTL8367C_PORT_LINKUP_INDICATOR_8051_OFFSET 0 +#define RTL8367C_PORT_LINKUP_INDICATOR_8051_MASK 0x7FF + +#define RTL8367C_REG_DUMMY_1125 0x1125 + +#define RTL8367C_REG_DUMMY_1126 0x1126 + +#define RTL8367C_REG_DUMMY_1127 0x1127 + +#define RTL8367C_REG_DUMMY_1128 0x1128 + +#define RTL8367C_REG_DUMMY_1129 0x1129 + +#define RTL8367C_REG_INTR_IMS_BUFFER_RESET 0x112a +#define RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_OFFSET 1 +#define RTL8367C_INTR_IMS_BUFFER_RESET_IMR_BUFF_RESET_MASK 0x2 +#define RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_OFFSET 0 +#define RTL8367C_INTR_IMS_BUFFER_RESET_BUFFER_RESET_MASK 0x1 + +#define RTL8367C_REG_INTR_IMS_8051_BUFFER_RESET 0x112b +#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_OFFSET 1 +#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_IMR_BUFF_RESET_MASK 0x2 +#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_OFFSET 0 +#define RTL8367C_INTR_IMS_8051_BUFFER_RESET_BUFFER_RESET_MASK 0x1 + +#define RTL8367C_REG_GPHY_INTRPT_8051 0x112c +#define RTL8367C_IMS_GPHY_8051_H_OFFSET 13 +#define RTL8367C_IMS_GPHY_8051_H_MASK 0xE000 +#define RTL8367C_IMR_GPHY_8051_H_OFFSET 10 +#define RTL8367C_IMR_GPHY_8051_H_MASK 0x1C00 +#define RTL8367C_IMS_GPHY_8051_OFFSET 5 +#define RTL8367C_IMS_GPHY_8051_MASK 0x3E0 +#define RTL8367C_IMR_GPHY_8051_OFFSET 0 +#define RTL8367C_IMR_GPHY_8051_MASK 0x1F + +#define RTL8367C_REG_GPHY_INTRPT 0x112d +#define RTL8367C_IMS_GPHY_H_OFFSET 13 +#define RTL8367C_IMS_GPHY_H_MASK 0xE000 +#define RTL8367C_IMR_GPHY_H_OFFSET 10 +#define RTL8367C_IMR_GPHY_H_MASK 0x1C00 +#define RTL8367C_IMS_GPHY_OFFSET 5 +#define RTL8367C_IMS_GPHY_MASK 0x3E0 +#define RTL8367C_IMR_GPHY_OFFSET 0 +#define RTL8367C_IMR_GPHY_MASK 0x1F + +#define RTL8367C_REG_THERMAL_INTRPT 0x112e +#define RTL8367C_IMS_TM_HIGH_OFFSET 3 +#define RTL8367C_IMS_TM_HIGH_MASK 0x8 +#define RTL8367C_IMR_TM_HIGH_OFFSET 2 +#define RTL8367C_IMR_TM_HIGH_MASK 0x4 +#define RTL8367C_IMS_TM_LOW_OFFSET 1 +#define RTL8367C_IMS_TM_LOW_MASK 0x2 +#define RTL8367C_IMR_TM_LOW_OFFSET 0 +#define RTL8367C_IMR_TM_LOW_MASK 0x1 + +#define RTL8367C_REG_THERMAL_INTRPT_8051 0x112f +#define RTL8367C_IMS_TM_HIGH_8051_OFFSET 3 +#define RTL8367C_IMS_TM_HIGH_8051_MASK 0x8 +#define RTL8367C_IMR_TM_HIGH_8051_OFFSET 2 +#define RTL8367C_IMR_TM_HIGH_8051_MASK 0x4 +#define RTL8367C_IMS_TM_LOW_8051_OFFSET 1 +#define RTL8367C_IMS_TM_LOW_8051_MASK 0x2 +#define RTL8367C_IMR_TM_LOW_8051_OFFSET 0 +#define RTL8367C_IMR_TM_LOW_8051_MASK 0x1 + +#define RTL8367C_REG_SDS_LINK_CHG_INT 0x1130 +#define RTL8367C_IMS_SDS_LINK_STS_C7_OFFSET 15 +#define RTL8367C_IMS_SDS_LINK_STS_C7_MASK 0x8000 +#define RTL8367C_IMS_SDS_LINK_STS_C6_OFFSET 14 +#define RTL8367C_IMS_SDS_LINK_STS_C6_MASK 0x4000 +#define RTL8367C_IMS_SDS_LINK_STS_C5_OFFSET 13 +#define RTL8367C_IMS_SDS_LINK_STS_C5_MASK 0x2000 +#define RTL8367C_IMS_SDS_LINK_STS_C4_OFFSET 12 +#define RTL8367C_IMS_SDS_LINK_STS_C4_MASK 0x1000 +#define RTL8367C_IMS_SDS_LINK_STS_C3_OFFSET 11 +#define RTL8367C_IMS_SDS_LINK_STS_C3_MASK 0x800 +#define RTL8367C_IMS_SDS_LINK_STS_C2_OFFSET 10 +#define RTL8367C_IMS_SDS_LINK_STS_C2_MASK 0x400 +#define RTL8367C_IMS_SDS_LINK_STS_C1_OFFSET 9 +#define RTL8367C_IMS_SDS_LINK_STS_C1_MASK 0x200 +#define RTL8367C_IMS_SDS_LINK_STS_C0_OFFSET 8 +#define RTL8367C_IMS_SDS_LINK_STS_C0_MASK 0x100 +#define RTL8367C_IMR_SDS_LINK_STS_C7_OFFSET 7 +#define RTL8367C_IMR_SDS_LINK_STS_C7_MASK 0x80 +#define RTL8367C_IMR_SDS_LINK_STS_C6_OFFSET 6 +#define RTL8367C_IMR_SDS_LINK_STS_C6_MASK 0x40 +#define RTL8367C_IMR_SDS_LINK_STS_C5_OFFSET 5 +#define RTL8367C_IMR_SDS_LINK_STS_C5_MASK 0x20 +#define RTL8367C_IMR_SDS_LINK_STS_C4_OFFSET 4 +#define RTL8367C_IMR_SDS_LINK_STS_C4_MASK 0x10 +#define RTL8367C_IMR_SDS_LINK_STS_C3_OFFSET 3 +#define RTL8367C_IMR_SDS_LINK_STS_C3_MASK 0x8 +#define RTL8367C_IMR_SDS_LINK_STS_C2_OFFSET 2 +#define RTL8367C_IMR_SDS_LINK_STS_C2_MASK 0x4 +#define RTL8367C_IMR_SDS_LINK_STS_C1_OFFSET 1 +#define RTL8367C_IMR_SDS_LINK_STS_C1_MASK 0x2 +#define RTL8367C_IMR_SDS_LINK_STS_C0_OFFSET 0 +#define RTL8367C_IMR_SDS_LINK_STS_C0_MASK 0x1 + +#define RTL8367C_REG_SDS_LINK_CHG_INT_8051 0x1131 +#define RTL8367C_IMS_SDS_LINK_STS_C7_8051_OFFSET 15 +#define RTL8367C_IMS_SDS_LINK_STS_C7_8051_MASK 0x8000 +#define RTL8367C_IMS_SDS_LINK_STS_C6_8051_OFFSET 14 +#define RTL8367C_IMS_SDS_LINK_STS_C6_8051_MASK 0x4000 +#define RTL8367C_IMS_SDS_LINK_STS_C5_8051_OFFSET 13 +#define RTL8367C_IMS_SDS_LINK_STS_C5_8051_MASK 0x2000 +#define RTL8367C_IMS_SDS_LINK_STS_C4_8051_OFFSET 12 +#define RTL8367C_IMS_SDS_LINK_STS_C4_8051_MASK 0x1000 +#define RTL8367C_IMS_SDS_LINK_STS_C3_8051_OFFSET 11 +#define RTL8367C_IMS_SDS_LINK_STS_C3_8051_MASK 0x800 +#define RTL8367C_IMS_SDS_LINK_STS_C2_8051_OFFSET 10 +#define RTL8367C_IMS_SDS_LINK_STS_C2_8051_MASK 0x400 +#define RTL8367C_IMS_SDS_LINK_STS_C1_8051_OFFSET 9 +#define RTL8367C_IMS_SDS_LINK_STS_C1_8051_MASK 0x200 +#define RTL8367C_IMS_SDS_LINK_STS_C0_8051_OFFSET 8 +#define RTL8367C_IMS_SDS_LINK_STS_C0_8051_MASK 0x100 +#define RTL8367C_IMR_SDS_LINK_STS_C7_8051_OFFSET 7 +#define RTL8367C_IMR_SDS_LINK_STS_C7_8051_MASK 0x80 +#define RTL8367C_IMR_SDS_LINK_STS_C6_8051_OFFSET 6 +#define RTL8367C_IMR_SDS_LINK_STS_C6_8051_MASK 0x40 +#define RTL8367C_IMR_SDS_LINK_STS_C5_8051_OFFSET 5 +#define RTL8367C_IMR_SDS_LINK_STS_C5_8051_MASK 0x20 +#define RTL8367C_IMR_SDS_LINK_STS_C4_8051_OFFSET 4 +#define RTL8367C_IMR_SDS_LINK_STS_C4_8051_MASK 0x10 +#define RTL8367C_IMR_SDS_LINK_STS_C3_8051_OFFSET 3 +#define RTL8367C_IMR_SDS_LINK_STS_C3_8051_MASK 0x8 +#define RTL8367C_IMR_SDS_LINK_STS_C2_8051_OFFSET 2 +#define RTL8367C_IMR_SDS_LINK_STS_C2_8051_MASK 0x4 +#define RTL8367C_IMR_SDS_LINK_STS_C1_8051_OFFSET 1 +#define RTL8367C_IMR_SDS_LINK_STS_C1_8051_MASK 0x2 +#define RTL8367C_IMR_SDS_LINK_STS_C0_8051_OFFSET 0 +#define RTL8367C_IMR_SDS_LINK_STS_C0_8051_MASK 0x1 + +/* (16'h1200)swcore_reg */ + +#define RTL8367C_REG_MAX_LENGTH_LIMINT_IPG 0x1200 +#define RTL8367C_MAX_LENTH_CTRL_OFFSET 13 +#define RTL8367C_MAX_LENTH_CTRL_MASK 0x6000 +#define RTL8367C_PAGES_BEFORE_FCDROP_OFFSET 6 +#define RTL8367C_PAGES_BEFORE_FCDROP_MASK 0x1FC0 +#define RTL8367C_CHECK_MIN_IPG_RXDV_OFFSET 5 +#define RTL8367C_CHECK_MIN_IPG_RXDV_MASK 0x20 +#define RTL8367C_LIMIT_IPG_CFG_OFFSET 0 +#define RTL8367C_LIMIT_IPG_CFG_MASK 0x1F + +#define RTL8367C_REG_IOL_RXDROP_CFG 0x1201 +#define RTL8367C_RX_IOL_MAX_LENGTH_CFG_OFFSET 13 +#define RTL8367C_RX_IOL_MAX_LENGTH_CFG_MASK 0x2000 +#define RTL8367C_RX_IOL_ERROR_LENGTH_CFG_OFFSET 12 +#define RTL8367C_RX_IOL_ERROR_LENGTH_CFG_MASK 0x1000 +#define RTL8367C_RX_NODROP_PAUSE_CFG_OFFSET 8 +#define RTL8367C_RX_NODROP_PAUSE_CFG_MASK 0x100 +#define RTL8367C_RX_DV_CNT_CFG_OFFSET 0 +#define RTL8367C_RX_DV_CNT_CFG_MASK 0x3F + +#define RTL8367C_REG_VS_TPID 0x1202 + +#define RTL8367C_REG_INBW_BOUND 0x1203 +#define RTL8367C_LBOUND_OFFSET 4 +#define RTL8367C_LBOUND_MASK 0xF0 +#define RTL8367C_HBOUND_OFFSET 0 +#define RTL8367C_HBOUND_MASK 0xF + +#define RTL8367C_REG_CFG_TX_ITFSP_OP 0x1204 +#define RTL8367C_MASK_OFFSET 1 +#define RTL8367C_MASK_MASK 0x2 +#define RTL8367C_OP_OFFSET 0 +#define RTL8367C_OP_MASK 0x1 + +#define RTL8367C_REG_INBW_BOUND2 0x1205 +#define RTL8367C_LBOUND2_H_OFFSET 9 +#define RTL8367C_LBOUND2_H_MASK 0x200 +#define RTL8367C_HBOUND2_H_OFFSET 8 +#define RTL8367C_HBOUND2_H_MASK 0x100 +#define RTL8367C_LBOUND2_OFFSET 4 +#define RTL8367C_LBOUND2_MASK 0xF0 +#define RTL8367C_HBOUND2_OFFSET 0 +#define RTL8367C_HBOUND2_MASK 0xF + +#define RTL8367C_REG_CFG_48PASS1_DROP 0x1206 +#define RTL8367C_CFG_48PASS1_DROP_OFFSET 0 +#define RTL8367C_CFG_48PASS1_DROP_MASK 0x1 + +#define RTL8367C_REG_CFG_BACKPRESSURE 0x1207 +#define RTL8367C_LONGTXE_OFFSET 12 +#define RTL8367C_LONGTXE_MASK 0x1000 +#define RTL8367C_EN_BYPASS_ERROR_OFFSET 8 +#define RTL8367C_EN_BYPASS_ERROR_MASK 0x100 +#define RTL8367C_EN_BACKPRESSURE_OFFSET 4 +#define RTL8367C_EN_BACKPRESSURE_MASK 0x10 +#define RTL8367C_EN_48_PASS_1_OFFSET 0 +#define RTL8367C_EN_48_PASS_1_MASK 0x1 + +#define RTL8367C_REG_CFG_UNHIOL 0x1208 +#define RTL8367C_IOL_BACKOFF_OFFSET 12 +#define RTL8367C_IOL_BACKOFF_MASK 0x1000 +#define RTL8367C_BACKOFF_RANDOM_TIME_OFFSET 8 +#define RTL8367C_BACKOFF_RANDOM_TIME_MASK 0x100 +#define RTL8367C_DISABLE_BACK_OFF_OFFSET 4 +#define RTL8367C_DISABLE_BACK_OFF_MASK 0x10 +#define RTL8367C_IPG_COMPENSATION_OFFSET 0 +#define RTL8367C_IPG_COMPENSATION_MASK 0x1 + +#define RTL8367C_REG_SWITCH_MAC0 0x1209 + +#define RTL8367C_REG_SWITCH_MAC1 0x120a + +#define RTL8367C_REG_SWITCH_MAC2 0x120b + +#define RTL8367C_REG_SWITCH_CTRL0 0x120c +#define RTL8367C_REMARKING_DSCP_ENABLE_OFFSET 8 +#define RTL8367C_REMARKING_DSCP_ENABLE_MASK 0x100 +#define RTL8367C_SHORT_IPG_OFFSET 4 +#define RTL8367C_SHORT_IPG_MASK 0x10 +#define RTL8367C_PAUSE_MAX128_OFFSET 0 +#define RTL8367C_PAUSE_MAX128_MASK 0x1 + +#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL0 0x120d +#define RTL8367C_INTPRI1_DSCP_OFFSET 8 +#define RTL8367C_INTPRI1_DSCP_MASK 0x3F00 +#define RTL8367C_INTPRI0_DSCP_OFFSET 0 +#define RTL8367C_INTPRI0_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL1 0x120e +#define RTL8367C_INTPRI3_DSCP_OFFSET 8 +#define RTL8367C_INTPRI3_DSCP_MASK 0x3F00 +#define RTL8367C_INTPRI2_DSCP_OFFSET 0 +#define RTL8367C_INTPRI2_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL2 0x120f +#define RTL8367C_INTPRI5_DSCP_OFFSET 8 +#define RTL8367C_INTPRI5_DSCP_MASK 0x3F00 +#define RTL8367C_INTPRI4_DSCP_OFFSET 0 +#define RTL8367C_INTPRI4_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_DSCP_REMARK_CTRL3 0x1210 +#define RTL8367C_INTPRI7_DSCP_OFFSET 8 +#define RTL8367C_INTPRI7_DSCP_MASK 0x3F00 +#define RTL8367C_INTPRI6_DSCP_OFFSET 0 +#define RTL8367C_INTPRI6_DSCP_MASK 0x3F + +#define RTL8367C_REG_QOS_1Q_REMARK_CTRL0 0x1211 +#define RTL8367C_INTPRI3_PRI_OFFSET 12 +#define RTL8367C_INTPRI3_PRI_MASK 0x7000 +#define RTL8367C_INTPRI2_PRI_OFFSET 8 +#define RTL8367C_INTPRI2_PRI_MASK 0x700 +#define RTL8367C_INTPRI1_PRI_OFFSET 4 +#define RTL8367C_INTPRI1_PRI_MASK 0x70 +#define RTL8367C_INTPRI0_PRI_OFFSET 0 +#define RTL8367C_INTPRI0_PRI_MASK 0x7 + +#define RTL8367C_REG_QOS_1Q_REMARK_CTRL1 0x1212 +#define RTL8367C_INTPRI7_PRI_OFFSET 12 +#define RTL8367C_INTPRI7_PRI_MASK 0x7000 +#define RTL8367C_INTPRI6_PRI_OFFSET 8 +#define RTL8367C_INTPRI6_PRI_MASK 0x700 +#define RTL8367C_INTPRI5_PRI_OFFSET 4 +#define RTL8367C_INTPRI5_PRI_MASK 0x70 +#define RTL8367C_INTPRI4_PRI_OFFSET 0 +#define RTL8367C_INTPRI4_PRI_MASK 0x7 + +#define RTL8367C_REG_PKTGEN_COMMAND 0x1213 +#define RTL8367C_PKTGEN_STOP_OFFSET 8 +#define RTL8367C_PKTGEN_STOP_MASK 0x100 +#define RTL8367C_PKTGEN_START_OFFSET 4 +#define RTL8367C_PKTGEN_START_MASK 0x10 +#define RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_OFFSET 0 +#define RTL8367C_PKTGEN_BYPASS_FLOWCONTROL_MASK 0x1 + +#define RTL8367C_REG_SW_DUMMY0 0x1214 +#define RTL8367C_SW_DUMMY0_DUMMY_OFFSET 4 +#define RTL8367C_SW_DUMMY0_DUMMY_MASK 0xFFF0 +#define RTL8367C_EEE_DEFER_TXLPI_OFFSET 3 +#define RTL8367C_EEE_DEFER_TXLPI_MASK 0x8 +#define RTL8367C_INGRESSBW_BYPASS_EN_OFFSET 2 +#define RTL8367C_INGRESSBW_BYPASS_EN_MASK 0x4 +#define RTL8367C_CFG_RX_MIN_OFFSET 0 +#define RTL8367C_CFG_RX_MIN_MASK 0x3 + +#define RTL8367C_REG_SW_DUMMY1 0x1215 + +#define RTL8367C_REG_PKTGEN_PAUSE_TIME 0x1216 + +#define RTL8367C_REG_SVLAN_UPLINK_PORTMASK 0x1218 +#define RTL8367C_SVLAN_UPLINK_PORTMASK_OFFSET 0 +#define RTL8367C_SVLAN_UPLINK_PORTMASK_MASK 0x7FF + +#define RTL8367C_REG_CPU_PORT_MASK 0x1219 +#define RTL8367C_CPU_PORT_MASK_OFFSET 0 +#define RTL8367C_CPU_PORT_MASK_MASK 0x7FF + +#define RTL8367C_REG_CPU_CTRL 0x121a +#define RTL8367C_CPU_TRAP_PORT_EXT_OFFSET 10 +#define RTL8367C_CPU_TRAP_PORT_EXT_MASK 0x400 +#define RTL8367C_CPU_TAG_FORMAT_OFFSET 9 +#define RTL8367C_CPU_TAG_FORMAT_MASK 0x200 +#define RTL8367C_IOL_16DROP_OFFSET 8 +#define RTL8367C_IOL_16DROP_MASK 0x100 +#define RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET 7 +#define RTL8367C_CPU_TAG_RXBYTECOUNT_MASK 0x80 +#define RTL8367C_CPU_TAG_POSITION_OFFSET 6 +#define RTL8367C_CPU_TAG_POSITION_MASK 0x40 +#define RTL8367C_CPU_TRAP_PORT_OFFSET 3 +#define RTL8367C_CPU_TRAP_PORT_MASK 0x38 +#define RTL8367C_CPU_INSERTMODE_OFFSET 1 +#define RTL8367C_CPU_INSERTMODE_MASK 0x6 +#define RTL8367C_CPU_EN_OFFSET 0 +#define RTL8367C_CPU_EN_MASK 0x1 + +#define RTL8367C_REG_MIRROR_CTRL 0x121c +#define RTL8367C_MIRROR_CTRL_DUMMY_OFFSET 12 +#define RTL8367C_MIRROR_CTRL_DUMMY_MASK 0xF000 +#define RTL8367C_MIRROR_ISO_OFFSET 11 +#define RTL8367C_MIRROR_ISO_MASK 0x800 +#define RTL8367C_MIRROR_TX_OFFSET 10 +#define RTL8367C_MIRROR_TX_MASK 0x400 +#define RTL8367C_MIRROR_RX_OFFSET 9 +#define RTL8367C_MIRROR_RX_MASK 0x200 +#define RTL8367C_MIRROR_MONITOR_PORT_OFFSET 4 +#define RTL8367C_MIRROR_MONITOR_PORT_MASK 0xF0 +#define RTL8367C_MIRROR_SOURCE_PORT_OFFSET 0 +#define RTL8367C_MIRROR_SOURCE_PORT_MASK 0xF + +#define RTL8367C_REG_FLOWCTRL_CTRL0 0x121d +#define RTL8367C_FLOWCTRL_TYPE_OFFSET 15 +#define RTL8367C_FLOWCTRL_TYPE_MASK 0x8000 +#define RTL8367C_DROP_ALL_THRESHOLD_OFFSET 5 +#define RTL8367C_DROP_ALL_THRESHOLD_MASK 0x7FE0 +#define RTL8367C_DROP_ALL_THRESHOLD_MSB_OFFSET 4 +#define RTL8367C_DROP_ALL_THRESHOLD_MSB_MASK 0x10 +#define RTL8367C_ITFSP_REG_OFFSET 0 +#define RTL8367C_ITFSP_REG_MASK 0x7 + +#define RTL8367C_REG_FLOWCTRL_ALL_ON 0x121e +#define RTL8367C_CFG_RLDPACT_OFFSET 12 +#define RTL8367C_CFG_RLDPACT_MASK 0x1000 +#define RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_OFFSET 0 +#define RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_SYS_ON 0x121f +#define RTL8367C_FLOWCTRL_SYS_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_SYS_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_SYS_OFF 0x1220 +#define RTL8367C_FLOWCTRL_SYS_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_SYS_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_SHARE_ON 0x1221 +#define RTL8367C_FLOWCTRL_SHARE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_SHARE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_SHARE_OFF 0x1222 +#define RTL8367C_FLOWCTRL_SHARE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_SHARE_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON 0x1223 +#define RTL8367C_FLOWCTRL_FCOFF_SYS_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF 0x1224 +#define RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON 0x1225 +#define RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF 0x1226 +#define RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_ON 0x1227 +#define RTL8367C_FLOWCTRL_PORT_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_OFF 0x1228 +#define RTL8367C_FLOWCTRL_PORT_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON 0x1229 +#define RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF 0x122a +#define RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK 0x7FF + +#define RTL8367C_REG_RRCP_CTRL0 0x122b +#define RTL8367C_COL_SEL_OFFSET 14 +#define RTL8367C_COL_SEL_MASK 0x4000 +#define RTL8367C_CRS_SEL_OFFSET 13 +#define RTL8367C_CRS_SEL_MASK 0x2000 +#define RTL8367C_RRCP_PBVLAN_EN_OFFSET 11 +#define RTL8367C_RRCP_PBVLAN_EN_MASK 0x800 +#define RTL8367C_RRCPV3_SECURITY_CRC_OFFSET 10 +#define RTL8367C_RRCPV3_SECURITY_CRC_MASK 0x400 +#define RTL8367C_RRCPV3_HANDLE_OFFSET 8 +#define RTL8367C_RRCPV3_HANDLE_MASK 0x300 +#define RTL8367C_RRCPV1_MALFORMED_ACT_OFFSET 5 +#define RTL8367C_RRCPV1_MALFORMED_ACT_MASK 0x60 +#define RTL8367C_RRCP_VLANLEAKY_OFFSET 4 +#define RTL8367C_RRCP_VLANLEAKY_MASK 0x10 +#define RTL8367C_RRCPV1_SECURITY_CRC_GET_OFFSET 3 +#define RTL8367C_RRCPV1_SECURITY_CRC_GET_MASK 0x8 +#define RTL8367C_RRCPV1_SECURITY_CRC_SET_OFFSET 2 +#define RTL8367C_RRCPV1_SECURITY_CRC_SET_MASK 0x4 +#define RTL8367C_RRCPV1_HANDLE_OFFSET 1 +#define RTL8367C_RRCPV1_HANDLE_MASK 0x2 +#define RTL8367C_RRCP_ENABLE_OFFSET 0 +#define RTL8367C_RRCP_ENABLE_MASK 0x1 + +#define RTL8367C_REG_RRCP_CTRL1 0x122c +#define RTL8367C_RRCP_ADMIN_PMSK_OFFSET 8 +#define RTL8367C_RRCP_ADMIN_PMSK_MASK 0xFF00 +#define RTL8367C_RRCP_AUTH_PMSK_OFFSET 0 +#define RTL8367C_RRCP_AUTH_PMSK_MASK 0xFF + +#define RTL8367C_REG_RRCP_CTRL2 0x122d +#define RTL8367C_RRCPV1_HELLOFWD_TAG_OFFSET 9 +#define RTL8367C_RRCPV1_HELLOFWD_TAG_MASK 0x600 +#define RTL8367C_RRCP_FWD_TAG_OFFSET 7 +#define RTL8367C_RRCP_FWD_TAG_MASK 0x180 +#define RTL8367C_RRCPV1_REPLY_TAG_OFFSET 6 +#define RTL8367C_RRCPV1_REPLY_TAG_MASK 0x40 +#define RTL8367C_RRCPV1_HELLO_COUNT_OFFSET 3 +#define RTL8367C_RRCPV1_HELLO_COUNT_MASK 0x38 +#define RTL8367C_RRCPV1_HELLO_PEDIOD_OFFSET 0 +#define RTL8367C_RRCPV1_HELLO_PEDIOD_MASK 0x3 + +#define RTL8367C_REG_RRCP_CTRL3 0x122e +#define RTL8367C_RRCP_TAG_PRIORITY_OFFSET 13 +#define RTL8367C_RRCP_TAG_PRIORITY_MASK 0xE000 +#define RTL8367C_RRCP_TAG_VID_OFFSET 0 +#define RTL8367C_RRCP_TAG_VID_MASK 0xFFF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON 0x122f +#define RTL8367C_FLOWCTRL_FCOFF_PORT_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF 0x1230 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON 0x1231 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF 0x1232 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON 0x1233 +#define RTL8367C_FLOWCTRL_JUMBO_SYS_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF 0x1234 +#define RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON 0x1235 +#define RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF 0x1236 +#define RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON 0x1237 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF 0x1238 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON 0x1239 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF 0x123a +#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_OFFSET 0 +#define RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_JUMBO_SIZE 0x123b +#define RTL8367C_JUMBO_MODE_OFFSET 2 +#define RTL8367C_JUMBO_MODE_MASK 0x4 +#define RTL8367C_JUMBO_SIZE_OFFSET 0 +#define RTL8367C_JUMBO_SIZE_MASK 0x3 + +#define RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER 0x124c +#define RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER 0x124d +#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX 0x124e +#define RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX 0x124f +#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT0_PAGE_COUNTER 0x1250 +#define RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT0_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT1_PAGE_COUNTER 0x1251 +#define RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT1_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT2_PAGE_COUNTER 0x1252 +#define RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT2_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT3_PAGE_COUNTER 0x1253 +#define RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT3_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT4_PAGE_COUNTER 0x1254 +#define RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT4_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT5_PAGE_COUNTER 0x1255 +#define RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT5_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT6_PAGE_COUNTER 0x1256 +#define RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT6_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT7_PAGE_COUNTER 0x1257 +#define RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT7_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER 0x1258 +#define RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PUBLIC_FCOFF_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER 0x1259 +#define RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PUBLIC_JUMBO_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER 0x125a +#define RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_MAX_PUBLIC_FCOFF_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER 0x125b +#define RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_MAX_PUBLIC_JUMBO_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX 0x1260 +#define RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT0_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT1_PAGE_MAX 0x1261 +#define RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT1_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT2_PAGE_MAX 0x1262 +#define RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT2_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT3_PAGE_MAX 0x1263 +#define RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT3_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT4_PAGE_MAX 0x1264 +#define RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT4_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT5_PAGE_MAX 0x1265 +#define RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT5_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT6_PAGE_MAX 0x1266 +#define RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT6_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT7_PAGE_MAX 0x1267 +#define RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT7_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PAGE_COUNT_CLEAR 0x1268 +#define RTL8367C_DIS_SKIP_FP_OFFSET 1 +#define RTL8367C_DIS_SKIP_FP_MASK 0x2 +#define RTL8367C_PAGE_COUNT_CLEAR_OFFSET 0 +#define RTL8367C_PAGE_COUNT_CLEAR_MASK 0x1 + +#define RTL8367C_REG_FLOWCTRL_PORT8_PAGE_MAX 0x1269 +#define RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT8_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT9_PAGE_MAX 0x126a +#define RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT9_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT10_PAGE_MAX 0x126b +#define RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT10_PAGE_MAX_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER 0x126c +#define RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT8_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT9_PAGE_COUNTER 0x126d +#define RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT9_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_FLOWCTRL_PORT10_PAGE_COUNTER 0x126e +#define RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_OFFSET 0 +#define RTL8367C_FLOWCTRL_PORT10_PAGE_COUNTER_MASK 0x7FF + +#define RTL8367C_REG_RRCP_CTRL1_H 0x126f +#define RTL8367C_RRCP_ADMIN_PMSK_P10_8_OFFSET 3 +#define RTL8367C_RRCP_ADMIN_PMSK_P10_8_MASK 0x38 +#define RTL8367C_RRCP_AUTH_PMSK_P10_8_OFFSET 0 +#define RTL8367C_RRCP_AUTH_PMSK_P10_8_MASK 0x7 + +#define RTL8367C_REG_EMA_CTRL0 0x1270 +#define RTL8367C_CFG_DVSE_VIAROM_OFFSET 13 +#define RTL8367C_CFG_DVSE_VIAROM_MASK 0x2000 +#define RTL8367C_CFG_DVSE_MIBRAM_OFFSET 12 +#define RTL8367C_CFG_DVSE_MIBRAM_MASK 0x1000 +#define RTL8367C_CFG_DVSE_IROM_OFFSET 11 +#define RTL8367C_CFG_DVSE_IROM_MASK 0x800 +#define RTL8367C_CFG_DVSE_ERAM_OFFSET 10 +#define RTL8367C_CFG_DVSE_ERAM_MASK 0x400 +#define RTL8367C_CFG_DVSE_IRAM_OFFSET 9 +#define RTL8367C_CFG_DVSE_IRAM_MASK 0x200 +#define RTL8367C_CFG_DVSE_NICRAM_OFFSET 8 +#define RTL8367C_CFG_DVSE_NICRAM_MASK 0x100 +#define RTL8367C_CFG_DVSE_CVLANRAM_OFFSET 7 +#define RTL8367C_CFG_DVSE_CVLANRAM_MASK 0x80 +#define RTL8367C_CFG_DVSE_ACTRAM_OFFSET 6 +#define RTL8367C_CFG_DVSE_ACTRAM_MASK 0x40 +#define RTL8367C_CFG_DVSE_INQRAM_OFFSET 5 +#define RTL8367C_CFG_DVSE_INQRAM_MASK 0x20 +#define RTL8367C_CFG_DVSE_HSARAM_OFFSET 4 +#define RTL8367C_CFG_DVSE_HSARAM_MASK 0x10 +#define RTL8367C_CFG_DVSE_OUTQRAM_OFFSET 3 +#define RTL8367C_CFG_DVSE_OUTQRAM_MASK 0x8 +#define RTL8367C_CFG_DVSE_HTRAM_OFFSET 2 +#define RTL8367C_CFG_DVSE_HTRAM_MASK 0x4 +#define RTL8367C_CFG_DVSE_PBRAM_OFFSET 1 +#define RTL8367C_CFG_DVSE_PBRAM_MASK 0x2 +#define RTL8367C_CFG_DVSE_L2RAM_OFFSET 0 +#define RTL8367C_CFG_DVSE_L2RAM_MASK 0x1 + +#define RTL8367C_REG_EMA_CTRL1 0x1271 +#define RTL8367C_CFG_DVS_OUTQRAM_OFFSET 12 +#define RTL8367C_CFG_DVS_OUTQRAM_MASK 0xF000 +#define RTL8367C_CFG_DVS_HTRAM_OFFSET 8 +#define RTL8367C_CFG_DVS_HTRAM_MASK 0x700 +#define RTL8367C_CFG_DVS_PBRAM_OFFSET 4 +#define RTL8367C_CFG_DVS_PBRAM_MASK 0xF0 +#define RTL8367C_CFG_DVS_L2RAM_OFFSET 0 +#define RTL8367C_CFG_DVS_L2RAM_MASK 0xF + +#define RTL8367C_REG_EMA_CTRL2 0x1272 +#define RTL8367C_CFG_DVS_CVLANRAM_OFFSET 12 +#define RTL8367C_CFG_DVS_CVLANRAM_MASK 0xF000 +#define RTL8367C_CFG_DVS_ACTRAM_OFFSET 8 +#define RTL8367C_CFG_DVS_ACTRAM_MASK 0xF00 +#define RTL8367C_CFG_DVS_INQRAM_OFFSET 4 +#define RTL8367C_CFG_DVS_INQRAM_MASK 0xF0 +#define RTL8367C_CFG_DVS_HSARAM_OFFSET 0 +#define RTL8367C_CFG_DVS_HSARAM_MASK 0xF + +#define RTL8367C_REG_EMA_CTRL3 0x1273 +#define RTL8367C_CFG_DVS_IROM_OFFSET 12 +#define RTL8367C_CFG_DVS_IROM_MASK 0xF000 +#define RTL8367C_CFG_DVS_ERAM_OFFSET 8 +#define RTL8367C_CFG_DVS_ERAM_MASK 0xF00 +#define RTL8367C_CFG_DVS_IRAM_OFFSET 4 +#define RTL8367C_CFG_DVS_IRAM_MASK 0xF0 +#define RTL8367C_CFG_DVS_NICRAM_OFFSET 0 +#define RTL8367C_CFG_DVS_NICRAM_MASK 0xF + +#define RTL8367C_REG_EMA_CTRL4 0x1274 +#define RTL8367C_CFG_DVS_VIAROM_OFFSET 4 +#define RTL8367C_CFG_DVS_VIAROM_MASK 0xF0 +#define RTL8367C_CFG_DVS_MIBRAM_OFFSET 0 +#define RTL8367C_CFG_DVS_MIBRAM_MASK 0xF + +#define RTL8367C_REG_DIAG_MODE 0x1275 +#define RTL8367C_DIAG_MODE_OFFSET 0 +#define RTL8367C_DIAG_MODE_MASK 0x1F + +#define RTL8367C_REG_BIST_MODE 0x1276 + +#define RTL8367C_REG_STS_BIST_DONE 0x1277 + +#define RTL8367C_REG_STS_BIST_RLT0 0x1278 +#define RTL8367C_STS_BIST_RLT0_OFFSET 0 +#define RTL8367C_STS_BIST_RLT0_MASK 0x1 + +#define RTL8367C_REG_STS_BIST_RLT1 0x1279 + +#define RTL8367C_REG_STS_BIST_RLT2 0x127a + +#define RTL8367C_REG_STS_BIST_RLT3 0x127b +#define RTL8367C_STS_BIST_RLT3_OFFSET 0 +#define RTL8367C_STS_BIST_RLT3_MASK 0x3FF + +#define RTL8367C_REG_STS_BIST_RLT4 0x127c +#define RTL8367C_STS_BIST_RLT4_OFFSET 0 +#define RTL8367C_STS_BIST_RLT4_MASK 0x7 + +#define RTL8367C_REG_VIAROM_MISR 0x127d + +#define RTL8367C_REG_DRF_BIST_MODE 0x1280 +#define RTL8367C_DRF_TCAMDEL_OFFSET 15 +#define RTL8367C_DRF_TCAMDEL_MASK 0x8000 +#define RTL8367C_CFG_DRF_BIST_MODE_OFFSET 0 +#define RTL8367C_CFG_DRF_BIST_MODE_MASK 0x7FFF + +#define RTL8367C_REG_STS_DRF_BIST 0x1281 +#define RTL8367C_STS_DRF_BIST_OFFSET 0 +#define RTL8367C_STS_DRF_BIST_MASK 0x7FFF + +#define RTL8367C_REG_STS_DRF_BIST_RLT0 0x1282 +#define RTL8367C_STS_DRF_BIST_RLT0_OFFSET 0 +#define RTL8367C_STS_DRF_BIST_RLT0_MASK 0x1 + +#define RTL8367C_REG_STS_DRF_BIST_RLT1 0x1283 + +#define RTL8367C_REG_STS_DRF_BIST_RLT2 0x1284 + +#define RTL8367C_REG_STS_DRF_BIST_RLT3 0x1285 +#define RTL8367C_STS_DRF_BIST_RLT3_OFFSET 0 +#define RTL8367C_STS_DRF_BIST_RLT3_MASK 0x3FF + +#define RTL8367C_REG_STS_DRF_BIST_RLT4 0x1286 +#define RTL8367C_STS_DRF_BIST_RLT4_OFFSET 0 +#define RTL8367C_STS_DRF_BIST_RLT4_MASK 0x7FFF + +#define RTL8367C_REG_RAM_DRF_CTRL 0x1289 +#define RTL8367C_RAM_DRF_CTRL_OFFSET 0 +#define RTL8367C_RAM_DRF_CTRL_MASK 0x1 + +#define RTL8367C_REG_MIB_RMON_LEN_CTRL 0x128a +#define RTL8367C_RX_LENGTH_CTRL_OFFSET 1 +#define RTL8367C_RX_LENGTH_CTRL_MASK 0x2 +#define RTL8367C_TX_LENGTH_CTRL_OFFSET 0 +#define RTL8367C_TX_LENGTH_CTRL_MASK 0x1 + +#define RTL8367C_REG_COND0_BISR_OUT0 0x1290 + +#define RTL8367C_REG_COND0_BISR_OUT1 0x1291 + +#define RTL8367C_REG_COND0_BISR_OUT2 0x1292 + +#define RTL8367C_REG_COND0_BISR_OUT3 0x1293 + +#define RTL8367C_REG_COND0_BISR_OUT4 0x1294 +#define RTL8367C_COND0_BISR_OUT4_OFFSET 0 +#define RTL8367C_COND0_BISR_OUT4_MASK 0x3F + +#define RTL8367C_REG_COND0_BISR_OUT5 0x1295 +#define RTL8367C_COND0_BISR_OUT5_OFFSET 0 +#define RTL8367C_COND0_BISR_OUT5_MASK 0x7 + +#define RTL8367C_REG_CHG_DUPLEX_CFG 0x1296 +#define RTL8367C_CHG_COL_CNT_PORT_OFFSET 13 +#define RTL8367C_CHG_COL_CNT_PORT_MASK 0xE000 +#define RTL8367C_CHG_COL_CNT_OFFSET 8 +#define RTL8367C_CHG_COL_CNT_MASK 0x1F00 +#define RTL8367C_CFG_CHG_DUP_EN_OFFSET 7 +#define RTL8367C_CFG_CHG_DUP_EN_MASK 0x80 +#define RTL8367C_CFG_CHG_DUP_THR_OFFSET 2 +#define RTL8367C_CFG_CHG_DUP_THR_MASK 0x7C +#define RTL8367C_CFG_CHG_DUP_CONGEST_OFFSET 1 +#define RTL8367C_CFG_CHG_DUP_CONGEST_MASK 0x2 +#define RTL8367C_CFG_CHG_DUP_REF_OFFSET 0 +#define RTL8367C_CFG_CHG_DUP_REF_MASK 0x1 + +#define RTL8367C_REG_COND0_BIST_PASS 0x1297 +#define RTL8367C_COND0_DRF_BIST_NOFAIL_OFFSET 1 +#define RTL8367C_COND0_DRF_BIST_NOFAIL_MASK 0x2 +#define RTL8367C_COND0_BIST_NOFAIL_OFFSET 0 +#define RTL8367C_COND0_BIST_NOFAIL_MASK 0x1 + +#define RTL8367C_REG_COND1_BISR_OUT0 0x1298 + +#define RTL8367C_REG_COND1_BISR_OUT1 0x1299 + +#define RTL8367C_REG_COND1_BISR_OUT2 0x129a + +#define RTL8367C_REG_COND1_BISR_OUT3 0x129b + +#define RTL8367C_REG_COND1_BISR_OUT4 0x129c +#define RTL8367C_COND1_BISR_OUT4_OFFSET 0 +#define RTL8367C_COND1_BISR_OUT4_MASK 0x3F + +#define RTL8367C_REG_COND1_BISR_OUT5 0x129d +#define RTL8367C_COND1_BISR_OUT5_OFFSET 0 +#define RTL8367C_COND1_BISR_OUT5_MASK 0x7 + +#define RTL8367C_REG_COND1_BIST_PASS 0x129f +#define RTL8367C_COND1_DRF_BIST_NOFAIL_OFFSET 1 +#define RTL8367C_COND1_DRF_BIST_NOFAIL_MASK 0x2 +#define RTL8367C_COND1_BIST_NOFAIL_OFFSET 0 +#define RTL8367C_COND1_BIST_NOFAIL_MASK 0x1 + +#define RTL8367C_REG_EEE_TX_THR_Giga_500M 0x12a0 + +#define RTL8367C_REG_EEE_TX_THR_FE 0x12a1 + +#define RTL8367C_REG_EEE_MISC 0x12a3 +#define RTL8367C_EEE_REQ_SET1_OFFSET 13 +#define RTL8367C_EEE_REQ_SET1_MASK 0x2000 +#define RTL8367C_EEE_REQ_SET0_OFFSET 12 +#define RTL8367C_EEE_REQ_SET0_MASK 0x1000 +#define RTL8367C_EEE_WAKE_SET1_OFFSET 9 +#define RTL8367C_EEE_WAKE_SET1_MASK 0x200 +#define RTL8367C_EEE_Wake_SET0_OFFSET 8 +#define RTL8367C_EEE_Wake_SET0_MASK 0x100 +#define RTL8367C_EEE_TU_GIGA_500M_OFFSET 4 +#define RTL8367C_EEE_TU_GIGA_500M_MASK 0x30 +#define RTL8367C_EEE_TU_100M_OFFSET 2 +#define RTL8367C_EEE_TU_100M_MASK 0xC + +#define RTL8367C_REG_EEE_GIGA_CTRL0 0x12a4 +#define RTL8367C_EEE_TW_GIGA_OFFSET 8 +#define RTL8367C_EEE_TW_GIGA_MASK 0xFF00 +#define RTL8367C_EEE_TR_GIGA_500M_OFFSET 0 +#define RTL8367C_EEE_TR_GIGA_500M_MASK 0xFF + +#define RTL8367C_REG_EEE_GIGA_CTRL1 0x12a5 +#define RTL8367C_EEE_TD_GIGA_500M_OFFSET 8 +#define RTL8367C_EEE_TD_GIGA_500M_MASK 0xFF00 +#define RTL8367C_EEE_TP_GIGA_OFFSET 0 +#define RTL8367C_EEE_TP_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEE_100M_CTRL0 0x12a6 +#define RTL8367C_EEE_TW_100M_OFFSET 8 +#define RTL8367C_EEE_TW_100M_MASK 0xFF00 +#define RTL8367C_EEE_TR_100M_OFFSET 0 +#define RTL8367C_EEE_TR_100M_MASK 0xFF + +#define RTL8367C_REG_EEE_100M_CTRL1 0x12a7 +#define RTL8367C_EEE_TD_100M_OFFSET 8 +#define RTL8367C_EEE_TD_100M_MASK 0xFF00 +#define RTL8367C_EEE_TP_100M_OFFSET 0 +#define RTL8367C_EEE_TP_100M_MASK 0xFF + +#define RTL8367C_REG_RX_FC_REG 0x12aa +#define RTL8367C_EN_EEE_HALF_DUP_OFFSET 8 +#define RTL8367C_EN_EEE_HALF_DUP_MASK 0x100 +#define RTL8367C_RX_PGCNT_OFFSET 0 +#define RTL8367C_RX_PGCNT_MASK 0xFF + +#define RTL8367C_REG_MAX_FIFO_SIZE 0x12af +#define RTL8367C_MAX_FIFO_SIZE_OFFSET 0 +#define RTL8367C_MAX_FIFO_SIZE_MASK 0xF + +#define RTL8367C_REG_EEEP_RX_RATE_GIGA 0x12b0 + +#define RTL8367C_REG_EEEP_RX_RATE_100M 0x12b1 + +#define RTL8367C_REG_DUMMY_REG_12_2 0x12b2 + +#define RTL8367C_REG_EEEP_TX_RATE_GIGA 0x12b3 + +#define RTL8367C_REG_EEEP_TX_RATE_100M 0x12b4 + +#define RTL8367C_REG_DUMMY_REG_12_3 0x12b5 + +#define RTL8367C_REG_EEEP_GIGA_CTRL0 0x12b6 +#define RTL8367C_EEEP_TR_GIGA_OFFSET 8 +#define RTL8367C_EEEP_TR_GIGA_MASK 0xFF00 +#define RTL8367C_EEEP_RW_GIGA_MST_OFFSET 0 +#define RTL8367C_EEEP_RW_GIGA_MST_MASK 0xFF + +#define RTL8367C_REG_EEEP_GIGA_CTRL1 0x12b7 +#define RTL8367C_EEEP_TW_GIGA_OFFSET 8 +#define RTL8367C_EEEP_TW_GIGA_MASK 0xFF00 +#define RTL8367C_EEEP_TP_GIGA_OFFSET 0 +#define RTL8367C_EEEP_TP_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEEP_GIGA_CTRL2 0x12b8 +#define RTL8367C_EEEP_TXEN_GIGA_OFFSET 12 +#define RTL8367C_EEEP_TXEN_GIGA_MASK 0x1000 +#define RTL8367C_EEEP_TU_GIGA_OFFSET 8 +#define RTL8367C_EEEP_TU_GIGA_MASK 0x300 +#define RTL8367C_EEEP_TS_GIGA_OFFSET 0 +#define RTL8367C_EEEP_TS_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEEP_100M_CTRL0 0x12b9 +#define RTL8367C_EEEP_TR_100M_OFFSET 8 +#define RTL8367C_EEEP_TR_100M_MASK 0xFF00 +#define RTL8367C_EEEP_RW_100M_OFFSET 0 +#define RTL8367C_EEEP_RW_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_100M_CTRL1 0x12ba +#define RTL8367C_EEEP_TW_100M_OFFSET 8 +#define RTL8367C_EEEP_TW_100M_MASK 0xFF00 +#define RTL8367C_EEEP_TP_100M_OFFSET 0 +#define RTL8367C_EEEP_TP_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_100M_CTRL2 0x12bb +#define RTL8367C_EEEP_TXEN_100M_OFFSET 12 +#define RTL8367C_EEEP_TXEN_100M_MASK 0x1000 +#define RTL8367C_EEEP_TU_100M_OFFSET 8 +#define RTL8367C_EEEP_TU_100M_MASK 0x300 +#define RTL8367C_EEEP_TS_100M_OFFSET 0 +#define RTL8367C_EEEP_TS_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_CTRL0 0x12bc +#define RTL8367C_EEEP_CTRL0_DUMMY_OFFSET 8 +#define RTL8367C_EEEP_CTRL0_DUMMY_MASK 0xFF00 +#define RTL8367C_EEEP_SLEEP_STEP_OFFSET 0 +#define RTL8367C_EEEP_SLEEP_STEP_MASK 0xFF + +#define RTL8367C_REG_EEEP_CTRL1 0x12bd +#define RTL8367C_EEEP_TXR_GIGA_OFFSET 8 +#define RTL8367C_EEEP_TXR_GIGA_MASK 0xFF00 +#define RTL8367C_EEEP_TXR_100M_OFFSET 0 +#define RTL8367C_EEEP_TXR_100M_MASK 0xFF + +#define RTL8367C_REG_BACK_PRESSURE_IPG 0x12be +#define RTL8367C_BACK_PRESSURE_IPG_OFFSET 0 +#define RTL8367C_BACK_PRESSURE_IPG_MASK 0x3 + +#define RTL8367C_REG_TX_ESD_LEVEL 0x12bf +#define RTL8367C_TX_ESD_LEVEL_MODE_OFFSET 8 +#define RTL8367C_TX_ESD_LEVEL_MODE_MASK 0x100 +#define RTL8367C_LEVEL_OFFSET 0 +#define RTL8367C_LEVEL_MASK 0xFF + +#define RTL8367C_REG_RRCP_CTRL4 0x12e0 + +#define RTL8367C_REG_RRCP_CTRL5 0x12e1 + +#define RTL8367C_REG_RRCP_CTRL6 0x12e2 + +#define RTL8367C_REG_RRCP_CTRL7 0x12e3 + +#define RTL8367C_REG_RRCP_CTRL8 0x12e4 + +#define RTL8367C_REG_RRCP_CTRL9 0x12e5 + +#define RTL8367C_REG_RRCP_CTRL10 0x12e6 + +#define RTL8367C_REG_FIELD_SELECTOR0 0x12e7 +#define RTL8367C_FIELD_SELECTOR0_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR0_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR0_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR0_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR1 0x12e8 +#define RTL8367C_FIELD_SELECTOR1_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR1_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR1_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR1_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR2 0x12e9 +#define RTL8367C_FIELD_SELECTOR2_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR2_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR2_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR2_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR3 0x12ea +#define RTL8367C_FIELD_SELECTOR3_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR3_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR3_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR3_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR4 0x12eb +#define RTL8367C_FIELD_SELECTOR4_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR4_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR4_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR4_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR5 0x12ec +#define RTL8367C_FIELD_SELECTOR5_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR5_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR5_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR5_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR6 0x12ed +#define RTL8367C_FIELD_SELECTOR6_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR6_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR6_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR6_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR7 0x12ee +#define RTL8367C_FIELD_SELECTOR7_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR7_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR7_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR7_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR8 0x12ef +#define RTL8367C_FIELD_SELECTOR8_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR8_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR8_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR8_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR9 0x12f0 +#define RTL8367C_FIELD_SELECTOR9_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR9_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR9_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR9_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR10 0x12f1 +#define RTL8367C_FIELD_SELECTOR10_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR10_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR10_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR10_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR11 0x12f2 +#define RTL8367C_FIELD_SELECTOR11_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR11_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR11_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR11_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR12 0x12f3 +#define RTL8367C_FIELD_SELECTOR12_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR12_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR12_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR12_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR13 0x12f4 +#define RTL8367C_FIELD_SELECTOR13_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR13_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR13_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR13_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR14 0x12f5 +#define RTL8367C_FIELD_SELECTOR14_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR14_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR14_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR14_OFFSET_MASK 0xFF + +#define RTL8367C_REG_FIELD_SELECTOR15 0x12f6 +#define RTL8367C_FIELD_SELECTOR15_FORMAT_OFFSET 8 +#define RTL8367C_FIELD_SELECTOR15_FORMAT_MASK 0x700 +#define RTL8367C_FIELD_SELECTOR15_OFFSET_OFFSET 0 +#define RTL8367C_FIELD_SELECTOR15_OFFSET_MASK 0xFF + +#define RTL8367C_REG_HWPKT_GEN_MISC_H 0x12f7 +#define RTL8367C_PKT_GEN_SUSPEND_P10_8_OFFSET 3 +#define RTL8367C_PKT_GEN_SUSPEND_P10_8_MASK 0x38 +#define RTL8367C_PKT_GEN_STATUS_P10_8_OFFSET 0 +#define RTL8367C_PKT_GEN_STATUS_P10_8_MASK 0x7 + +#define RTL8367C_REG_MIRROR_SRC_PMSK 0x12fb +#define RTL8367C_MIRROR_SRC_PMSK_OFFSET 0 +#define RTL8367C_MIRROR_SRC_PMSK_MASK 0x7FF + +#define RTL8367C_REG_EEE_BURSTSIZE 0x12fc + +#define RTL8367C_REG_EEE_IFG_CFG 0x12fd +#define RTL8367C_EEE_IFG_CFG_OFFSET 0 +#define RTL8367C_EEE_IFG_CFG_MASK 0x1 + +#define RTL8367C_REG_FPGA_VER_MAC 0x12fe + +#define RTL8367C_REG_HWPKT_GEN_MISC 0x12ff +#define RTL8367C_PKT_GEN_SUSPEND_OFFSET 8 +#define RTL8367C_PKT_GEN_SUSPEND_MASK 0xFF00 +#define RTL8367C_PKT_GEN_STATUS_OFFSET 0 +#define RTL8367C_PKT_GEN_STATUS_MASK 0xFF + +/* (16'h1300)chip_reg */ + +#define RTL8367C_REG_CHIP_NUMBER 0x1300 + +#define RTL8367C_REG_CHIP_VER 0x1301 +#define RTL8367C_VERID_OFFSET 12 +#define RTL8367C_VERID_MASK 0xF000 +#define RTL8367C_MCID_OFFSET 8 +#define RTL8367C_MCID_MASK 0xF00 +#define RTL8367C_MODEL_ID_OFFSET 4 +#define RTL8367C_MODEL_ID_MASK 0xF0 +#define RTL8367C_AFE_VERSION_OFFSET 0 +#define RTL8367C_AFE_VERSION_MASK 0x1 + +#define RTL8367C_REG_CHIP_DEBUG0 0x1303 +#define RTL8367C_SEL33_EXT2_OFFSET 10 +#define RTL8367C_SEL33_EXT2_MASK 0x400 +#define RTL8367C_SEL33_EXT1_OFFSET 9 +#define RTL8367C_SEL33_EXT1_MASK 0x200 +#define RTL8367C_SEL33_EXT0_OFFSET 8 +#define RTL8367C_SEL33_EXT0_MASK 0x100 +#define RTL8367C_DRI_OTHER_OFFSET 7 +#define RTL8367C_DRI_OTHER_MASK 0x80 +#define RTL8367C_DRI_EXT1_RG_OFFSET 6 +#define RTL8367C_DRI_EXT1_RG_MASK 0x40 +#define RTL8367C_DRI_EXT0_RG_OFFSET 5 +#define RTL8367C_DRI_EXT0_RG_MASK 0x20 +#define RTL8367C_DRI_EXT1_OFFSET 4 +#define RTL8367C_DRI_EXT1_MASK 0x10 +#define RTL8367C_DRI_EXT0_OFFSET 3 +#define RTL8367C_DRI_EXT0_MASK 0x8 +#define RTL8367C_SLR_OTHER_OFFSET 2 +#define RTL8367C_SLR_OTHER_MASK 0x4 +#define RTL8367C_SLR_EXT1_OFFSET 1 +#define RTL8367C_SLR_EXT1_MASK 0x2 +#define RTL8367C_SLR_EXT0_OFFSET 0 +#define RTL8367C_SLR_EXT0_MASK 0x1 + +#define RTL8367C_REG_CHIP_DEBUG1 0x1304 +#define RTL8367C_RG1_DN_OFFSET 12 +#define RTL8367C_RG1_DN_MASK 0x7000 +#define RTL8367C_RG1_DP_OFFSET 8 +#define RTL8367C_RG1_DP_MASK 0x700 +#define RTL8367C_RG0_DN_OFFSET 4 +#define RTL8367C_RG0_DN_MASK 0x70 +#define RTL8367C_RG0_DP_OFFSET 0 +#define RTL8367C_RG0_DP_MASK 0x7 + +#define RTL8367C_REG_DIGITAL_INTERFACE_SELECT 0x1305 +#define RTL8367C_ORG_COL_OFFSET 15 +#define RTL8367C_ORG_COL_MASK 0x8000 +#define RTL8367C_ORG_CRS_OFFSET 14 +#define RTL8367C_ORG_CRS_MASK 0x4000 +#define RTL8367C_SKIP_MII_1_RXER_OFFSET 13 +#define RTL8367C_SKIP_MII_1_RXER_MASK 0x2000 +#define RTL8367C_SKIP_MII_0_RXER_OFFSET 12 +#define RTL8367C_SKIP_MII_0_RXER_MASK 0x1000 +#define RTL8367C_SELECT_GMII_1_OFFSET 4 +#define RTL8367C_SELECT_GMII_1_MASK 0xF0 +#define RTL8367C_SELECT_GMII_0_OFFSET 0 +#define RTL8367C_SELECT_GMII_0_MASK 0xF + +#define RTL8367C_REG_EXT0_RGMXF 0x1306 +#define RTL8367C_EXT0_RGTX_INV_OFFSET 6 +#define RTL8367C_EXT0_RGTX_INV_MASK 0x40 +#define RTL8367C_EXT0_RGRX_INV_OFFSET 5 +#define RTL8367C_EXT0_RGRX_INV_MASK 0x20 +#define RTL8367C_EXT0_RGMXF_OFFSET 0 +#define RTL8367C_EXT0_RGMXF_MASK 0x1F + +#define RTL8367C_REG_EXT1_RGMXF 0x1307 +#define RTL8367C_EXT1_RGTX_INV_OFFSET 6 +#define RTL8367C_EXT1_RGTX_INV_MASK 0x40 +#define RTL8367C_EXT1_RGRX_INV_OFFSET 5 +#define RTL8367C_EXT1_RGRX_INV_MASK 0x20 +#define RTL8367C_EXT1_RGMXF_OFFSET 0 +#define RTL8367C_EXT1_RGMXF_MASK 0x1F + +#define RTL8367C_REG_BISR_CTRL 0x1308 +#define RTL8367C_BISR_CTRL_OFFSET 0 +#define RTL8367C_BISR_CTRL_MASK 0x7 + +#define RTL8367C_REG_SLF_IF 0x1309 +#define RTL8367C_LINK_DOWN_CLR_FIFO_OFFSET 7 +#define RTL8367C_LINK_DOWN_CLR_FIFO_MASK 0x80 +#define RTL8367C_LOOPBACK_OFFSET 6 +#define RTL8367C_LOOPBACK_MASK 0x40 +#define RTL8367C_WATER_LEVEL_OFFSET 4 +#define RTL8367C_WATER_LEVEL_MASK 0x30 +#define RTL8367C_SLF_IF_OFFSET 0 +#define RTL8367C_SLF_IF_MASK 0x3 + +#define RTL8367C_REG_I2C_CLOCK_DIV 0x130a +#define RTL8367C_I2C_CLOCK_DIV_OFFSET 0 +#define RTL8367C_I2C_CLOCK_DIV_MASK 0x3FF + +#define RTL8367C_REG_MDX_MDC_DIV 0x130b +#define RTL8367C_MDX_MDC_DIV_OFFSET 0 +#define RTL8367C_MDX_MDC_DIV_MASK 0x3FF + +#define RTL8367C_REG_MISCELLANEOUS_CONFIGURE0 0x130c +#define RTL8367C_ADCCKI_FROM_PAD_OFFSET 14 +#define RTL8367C_ADCCKI_FROM_PAD_MASK 0x4000 +#define RTL8367C_ADCCKI_EN_OFFSET 13 +#define RTL8367C_ADCCKI_EN_MASK 0x2000 +#define RTL8367C_FLASH_ENABLE_OFFSET 12 +#define RTL8367C_FLASH_ENABLE_MASK 0x1000 +#define RTL8367C_EEE_ENABLE_OFFSET 11 +#define RTL8367C_EEE_ENABLE_MASK 0x800 +#define RTL8367C_NIC_ENABLE_OFFSET 10 +#define RTL8367C_NIC_ENABLE_MASK 0x400 +#define RTL8367C_FT_ENABLE_OFFSET 9 +#define RTL8367C_FT_ENABLE_MASK 0x200 +#define RTL8367C_OLT_ENABLE_OFFSET 8 +#define RTL8367C_OLT_ENABLE_MASK 0x100 +#define RTL8367C_RTCT_EN_OFFSET 7 +#define RTL8367C_RTCT_EN_MASK 0x80 +#define RTL8367C_PON_LIGHT_EN_OFFSET 6 +#define RTL8367C_PON_LIGHT_EN_MASK 0x40 +#define RTL8367C_DW8051_EN_OFFSET 5 +#define RTL8367C_DW8051_EN_MASK 0x20 +#define RTL8367C_AUTOLOAD_EN_OFFSET 4 +#define RTL8367C_AUTOLOAD_EN_MASK 0x10 +#define RTL8367C_NRESTORE_EN_OFFSET 3 +#define RTL8367C_NRESTORE_EN_MASK 0x8 +#define RTL8367C_DIS_PON_TABLE_INIT_OFFSET 2 +#define RTL8367C_DIS_PON_TABLE_INIT_MASK 0x4 +#define RTL8367C_DIS_PON_BIST_OFFSET 1 +#define RTL8367C_DIS_PON_BIST_MASK 0x2 +#define RTL8367C_EFUSE_EN_OFFSET 0 +#define RTL8367C_EFUSE_EN_MASK 0x1 + +#define RTL8367C_REG_MISCELLANEOUS_CONFIGURE1 0x130d +#define RTL8367C_EEPROM_DEV_ADR_OFFSET 8 +#define RTL8367C_EEPROM_DEV_ADR_MASK 0x7F00 +#define RTL8367C_EEPROM_MSB_OFFSET 7 +#define RTL8367C_EEPROM_MSB_MASK 0x80 +#define RTL8367C_EEPROM_ADDRESS_16B_OFFSET 6 +#define RTL8367C_EEPROM_ADDRESS_16B_MASK 0x40 +#define RTL8367C_EEPROM_DWONLOAD_COMPLETE_OFFSET 3 +#define RTL8367C_EEPROM_DWONLOAD_COMPLETE_MASK 0x8 +#define RTL8367C_SPI_SLAVE_EN_OFFSET 2 +#define RTL8367C_SPI_SLAVE_EN_MASK 0x4 +#define RTL8367C_SMI_SEL_OFFSET 0 +#define RTL8367C_SMI_SEL_MASK 0x3 + +#define RTL8367C_REG_PHY_AD 0x130f +#define RTL8367C_EN_PHY_MAX_POWER_OFFSET 14 +#define RTL8367C_EN_PHY_MAX_POWER_MASK 0x4000 +#define RTL8367C_EN_PHY_SEL_DEG_OFFSET 13 +#define RTL8367C_EN_PHY_SEL_DEG_MASK 0x2000 +#define RTL8367C_EXTPHY_AD_OFFSET 8 +#define RTL8367C_EXTPHY_AD_MASK 0x1F00 +#define RTL8367C_EN_PHY_LOW_POWER_MODE_OFFSET 7 +#define RTL8367C_EN_PHY_LOW_POWER_MODE_MASK 0x80 +#define RTL8367C_EN_PHY_GREEN_OFFSET 6 +#define RTL8367C_EN_PHY_GREEN_MASK 0x40 +#define RTL8367C_PDNPHY_OFFSET 5 +#define RTL8367C_PDNPHY_MASK 0x20 +#define RTL8367C_INTPHY_AD_OFFSET 0 +#define RTL8367C_INTPHY_AD_MASK 0x1F + +#define RTL8367C_REG_DIGITAL_INTERFACE0_FORCE 0x1310 +#define RTL8367C_GMII_0_FORCE_OFFSET 12 +#define RTL8367C_GMII_0_FORCE_MASK 0x1000 +#define RTL8367C_RGMII_0_FORCE_OFFSET 0 +#define RTL8367C_RGMII_0_FORCE_MASK 0xFFF + +#define RTL8367C_REG_DIGITAL_INTERFACE1_FORCE 0x1311 +#define RTL8367C_GMII_1_FORCE_OFFSET 12 +#define RTL8367C_GMII_1_FORCE_MASK 0x1000 +#define RTL8367C_RGMII_1_FORCE_OFFSET 0 +#define RTL8367C_RGMII_1_FORCE_MASK 0xFFF + +#define RTL8367C_REG_MAC0_FORCE_SELECT 0x1312 +#define RTL8367C_EN_MAC0_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC0_FORCE_MASK 0x1000 +#define RTL8367C_MAC0_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC0_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC1_FORCE_SELECT 0x1313 +#define RTL8367C_EN_MAC1_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC1_FORCE_MASK 0x1000 +#define RTL8367C_MAC1_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC1_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC2_FORCE_SELECT 0x1314 +#define RTL8367C_EN_MAC2_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC2_FORCE_MASK 0x1000 +#define RTL8367C_MAC2_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC2_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC3_FORCE_SELECT 0x1315 +#define RTL8367C_EN_MAC3_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC3_FORCE_MASK 0x1000 +#define RTL8367C_MAC3_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC3_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC4_FORCE_SELECT 0x1316 +#define RTL8367C_EN_MAC4_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC4_FORCE_MASK 0x1000 +#define RTL8367C_MAC4_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC4_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC5_FORCE_SELECT 0x1317 +#define RTL8367C_EN_MAC5_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC5_FORCE_MASK 0x1000 +#define RTL8367C_MAC5_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC5_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC6_FORCE_SELECT 0x1318 +#define RTL8367C_EN_MAC6_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC6_FORCE_MASK 0x1000 +#define RTL8367C_MAC6_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC6_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_MAC7_FORCE_SELECT 0x1319 +#define RTL8367C_EN_MAC7_FORCE_OFFSET 12 +#define RTL8367C_EN_MAC7_FORCE_MASK 0x1000 +#define RTL8367C_MAC7_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_MAC7_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_M10_FORCE_SELECT 0x131c +#define RTL8367C_EN_M10_FORCE_OFFSET 12 +#define RTL8367C_EN_M10_FORCE_MASK 0x1000 +#define RTL8367C_M10_FORCE_ABLTY_OFFSET 0 +#define RTL8367C_M10_FORCE_ABLTY_MASK 0xFFF + +#define RTL8367C_REG_CHIP_RESET 0x1322 +#define RTL8367C_GPHY_RESET_OFFSET 6 +#define RTL8367C_GPHY_RESET_MASK 0x40 +#define RTL8367C_NIC_RST_OFFSET 5 +#define RTL8367C_NIC_RST_MASK 0x20 +#define RTL8367C_DW8051_RST_OFFSET 4 +#define RTL8367C_DW8051_RST_MASK 0x10 +#define RTL8367C_SDS_RST_OFFSET 3 +#define RTL8367C_SDS_RST_MASK 0x8 +#define RTL8367C_CONFIG_RST_OFFSET 2 +#define RTL8367C_CONFIG_RST_MASK 0x4 +#define RTL8367C_SW_RST_OFFSET 1 +#define RTL8367C_SW_RST_MASK 0x2 +#define RTL8367C_CHIP_RST_OFFSET 0 +#define RTL8367C_CHIP_RST_MASK 0x1 + +#define RTL8367C_REG_DIGITAL_DEBUG_0 0x1323 + +#define RTL8367C_REG_DIGITAL_DEBUG_1 0x1324 + +#define RTL8367C_REG_INTERNAL_PHY_MDC_DRIVER 0x1325 +#define RTL8367C_INTERNAL_PHY_MDC_DRIVER_OFFSET 0 +#define RTL8367C_INTERNAL_PHY_MDC_DRIVER_MASK 0x3FF + +#define RTL8367C_REG_LINKDOWN_TIME_CTRL 0x1326 +#define RTL8367C_LINKDOWN_TIME_CFG_OFFSET 9 +#define RTL8367C_LINKDOWN_TIME_CFG_MASK 0x7E00 +#define RTL8367C_LINKDOWN_TIME_ENABLE_OFFSET 8 +#define RTL8367C_LINKDOWN_TIME_ENABLE_MASK 0x100 +#define RTL8367C_LINKDOWN_TIME_OFFSET 0 +#define RTL8367C_LINKDOWN_TIME_MASK 0xFF + +#define RTL8367C_REG_PHYACK_TIMEOUT 0x1331 + +#define RTL8367C_REG_MDXACK_TIMEOUT 0x1333 + +#define RTL8367C_REG_DW8051_RDY 0x1336 +#define RTL8367C_VIAROM_WRITE_EN_OFFSET 9 +#define RTL8367C_VIAROM_WRITE_EN_MASK 0x200 +#define RTL8367C_SPIF_CK2_OFFSET 8 +#define RTL8367C_SPIF_CK2_MASK 0x100 +#define RTL8367C_RRCP_MDOE_OFFSET 7 +#define RTL8367C_RRCP_MDOE_MASK 0x80 +#define RTL8367C_DW8051_RATE_OFFSET 4 +#define RTL8367C_DW8051_RATE_MASK 0x70 +#define RTL8367C_IROM_MSB_OFFSET 2 +#define RTL8367C_IROM_MSB_MASK 0xC +#define RTL8367C_ACS_IROM_ENABLE_OFFSET 1 +#define RTL8367C_ACS_IROM_ENABLE_MASK 0x2 +#define RTL8367C_DW8051_READY_OFFSET 0 +#define RTL8367C_DW8051_READY_MASK 0x1 + +#define RTL8367C_REG_BIST_CTRL 0x133c +#define RTL8367C_DRF_BIST_DONE_ALL_OFFSET 5 +#define RTL8367C_DRF_BIST_DONE_ALL_MASK 0x20 +#define RTL8367C_DRF_BIST_PAUSE_ALL_OFFSET 4 +#define RTL8367C_DRF_BIST_PAUSE_ALL_MASK 0x10 +#define RTL8367C_BIST_DOAN_ALL_OFFSET 3 +#define RTL8367C_BIST_DOAN_ALL_MASK 0x8 +#define RTL8367C_BIST_PASS_OFFSET 0 +#define RTL8367C_BIST_PASS_MASK 0x7 + +#define RTL8367C_REG_DIAG_MODE2 0x133d +#define RTL8367C_DIAG_MODE2_ACTRAM_OFFSET 1 +#define RTL8367C_DIAG_MODE2_ACTRAM_MASK 0x2 +#define RTL8367C_DIAG_MODE2_BCAM_ACTION_OFFSET 0 +#define RTL8367C_DIAG_MODE2_BCAM_ACTION_MASK 0x1 + +#define RTL8367C_REG_MDX_PHY_REG0 0x133e +#define RTL8367C_PHY_BRD_MASK_OFFSET 4 +#define RTL8367C_PHY_BRD_MASK_MASK 0x1F0 +#define RTL8367C_MDX_INDACC_PAGE_OFFSET 0 +#define RTL8367C_MDX_INDACC_PAGE_MASK 0xF + +#define RTL8367C_REG_MDX_PHY_REG1 0x133f +#define RTL8367C_PHY_BRD_MODE_OFFSET 5 +#define RTL8367C_PHY_BRD_MODE_MASK 0x20 +#define RTL8367C_BRD_PHYAD_OFFSET 0 +#define RTL8367C_BRD_PHYAD_MASK 0x1F + +#define RTL8367C_REG_DEBUG_SIGNAL_SELECT_SW 0x1340 + +#define RTL8367C_REG_DEBUG_SIGNAL_SELECT_B 0x1341 +#define RTL8367C_DEBUG_MX_OFFSET 9 +#define RTL8367C_DEBUG_MX_MASK 0xE00 +#define RTL8367C_DEBUG_SHIFT_MISC_OFFSET 6 +#define RTL8367C_DEBUG_SHIFT_MISC_MASK 0x1C0 +#define RTL8367C_DEBUG_SHIFT_SW_OFFSET 3 +#define RTL8367C_DEBUG_SHIFT_SW_MASK 0x38 +#define RTL8367C_DEBUG_SHIFT_GPHY_OFFSET 0 +#define RTL8367C_DEBUG_SHIFT_GPHY_MASK 0x7 + +#define RTL8367C_REG_DEBUG_SIGNAL_I 0x1343 + +#define RTL8367C_REG_DEBUG_SIGNAL_H 0x1344 + +#define RTL8367C_REG_DBGO_SEL_GPHY 0x1345 + +#define RTL8367C_REG_DBGO_SEL_MISC 0x1346 + +#define RTL8367C_REG_BYPASS_ABLTY_LOCK 0x1349 +#define RTL8367C_BYPASS_ABLTY_LOCK_OFFSET 0 +#define RTL8367C_BYPASS_ABLTY_LOCK_MASK 0xFF + +#define RTL8367C_REG_BYPASS_ABLTY_LOCK_EXT 0x134a +#define RTL8367C_BYPASS_P10_ABILIITY_LOCK_OFFSET 3 +#define RTL8367C_BYPASS_P10_ABILIITY_LOCK_MASK 0x8 +#define RTL8367C_BYPASS_EXT_ABILITY_LOCK_OFFSET 0 +#define RTL8367C_BYPASS_EXT_ABILITY_LOCK_MASK 0x7 + +#define RTL8367C_REG_ACL_GPIO 0x134f +#define RTL8367C_ACL_GPIO_13_OFFSET 13 +#define RTL8367C_ACL_GPIO_13_MASK 0x2000 +#define RTL8367C_ACL_GPIO_12_OFFSET 12 +#define RTL8367C_ACL_GPIO_12_MASK 0x1000 +#define RTL8367C_ACL_GPIO_11_OFFSET 11 +#define RTL8367C_ACL_GPIO_11_MASK 0x800 +#define RTL8367C_ACL_GPIO_10_OFFSET 10 +#define RTL8367C_ACL_GPIO_10_MASK 0x400 +#define RTL8367C_ACL_GPIO_9_OFFSET 9 +#define RTL8367C_ACL_GPIO_9_MASK 0x200 +#define RTL8367C_ACL_GPIO_8_OFFSET 8 +#define RTL8367C_ACL_GPIO_8_MASK 0x100 +#define RTL8367C_ACL_GPIO_7_OFFSET 7 +#define RTL8367C_ACL_GPIO_7_MASK 0x80 +#define RTL8367C_ACL_GPIO_6_OFFSET 6 +#define RTL8367C_ACL_GPIO_6_MASK 0x40 +#define RTL8367C_ACL_GPIO_5_OFFSET 5 +#define RTL8367C_ACL_GPIO_5_MASK 0x20 +#define RTL8367C_ACL_GPIO_4_OFFSET 4 +#define RTL8367C_ACL_GPIO_4_MASK 0x10 +#define RTL8367C_ACL_GPIO_3_OFFSET 3 +#define RTL8367C_ACL_GPIO_3_MASK 0x8 +#define RTL8367C_ACL_GPIO_2_OFFSET 2 +#define RTL8367C_ACL_GPIO_2_MASK 0x4 +#define RTL8367C_ACL_GPIO_1_OFFSET 1 +#define RTL8367C_ACL_GPIO_1_MASK 0x2 +#define RTL8367C_ACL_GPIO_0_OFFSET 0 +#define RTL8367C_ACL_GPIO_0_MASK 0x1 + +#define RTL8367C_REG_EN_GPIO 0x1350 +#define RTL8367C_EN_GPIO_13_OFFSET 13 +#define RTL8367C_EN_GPIO_13_MASK 0x2000 +#define RTL8367C_EN_GPIO_12_OFFSET 12 +#define RTL8367C_EN_GPIO_12_MASK 0x1000 +#define RTL8367C_EN_GPIO_11_OFFSET 11 +#define RTL8367C_EN_GPIO_11_MASK 0x800 +#define RTL8367C_EN_GPIO_10_OFFSET 10 +#define RTL8367C_EN_GPIO_10_MASK 0x400 +#define RTL8367C_EN_GPIO_9_OFFSET 9 +#define RTL8367C_EN_GPIO_9_MASK 0x200 +#define RTL8367C_EN_GPIO_8_OFFSET 8 +#define RTL8367C_EN_GPIO_8_MASK 0x100 +#define RTL8367C_EN_GPIO_7_OFFSET 7 +#define RTL8367C_EN_GPIO_7_MASK 0x80 +#define RTL8367C_EN_GPIO_6_OFFSET 6 +#define RTL8367C_EN_GPIO_6_MASK 0x40 +#define RTL8367C_EN_GPIO_5_OFFSET 5 +#define RTL8367C_EN_GPIO_5_MASK 0x20 +#define RTL8367C_EN_GPIO_4_OFFSET 4 +#define RTL8367C_EN_GPIO_4_MASK 0x10 +#define RTL8367C_EN_GPIO_3_OFFSET 3 +#define RTL8367C_EN_GPIO_3_MASK 0x8 +#define RTL8367C_EN_GPIO_2_OFFSET 2 +#define RTL8367C_EN_GPIO_2_MASK 0x4 +#define RTL8367C_EN_GPIO_1_OFFSET 1 +#define RTL8367C_EN_GPIO_1_MASK 0x2 +#define RTL8367C_EN_GPIO_0_OFFSET 0 +#define RTL8367C_EN_GPIO_0_MASK 0x1 + +#define RTL8367C_REG_CFG_MULTI_PIN 0x1351 +#define RTL8367C_CFG_MULTI_PIN_OFFSET 0 +#define RTL8367C_CFG_MULTI_PIN_MASK 0x3 + +#define RTL8367C_REG_PORT0_STATUS 0x1352 +#define RTL8367C_PORT0_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT0_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT0_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT0_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT0_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT0_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT0_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT0_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT0_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT0_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT0_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT0_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT0_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT0_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT0_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT0_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT0_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT1_STATUS 0x1353 +#define RTL8367C_PORT1_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT1_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT1_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT1_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT1_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT1_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT1_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT1_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT1_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT1_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT1_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT1_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT1_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT1_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT1_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT1_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT1_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT2_STATUS 0x1354 +#define RTL8367C_PORT2_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT2_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT2_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT2_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT2_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT2_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT2_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT2_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT2_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT2_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT2_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT2_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT2_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT2_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT2_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT2_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT2_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT3_STATUS 0x1355 +#define RTL8367C_PORT3_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT3_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT3_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT3_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT3_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT3_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT3_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT3_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT3_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT3_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT3_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT3_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT3_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT3_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT3_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT3_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT3_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT4_STATUS 0x1356 +#define RTL8367C_PORT4_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT4_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT4_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT4_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT4_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT4_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT4_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT4_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT4_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT4_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT4_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT4_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT4_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT4_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT4_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT4_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT4_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT5_STATUS 0x1357 +#define RTL8367C_PORT5_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT5_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT5_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT5_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT5_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT5_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT5_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT5_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT5_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT5_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT5_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT5_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT5_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT5_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT5_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT5_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT5_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT6_STATUS 0x1358 +#define RTL8367C_PORT6_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT6_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT6_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT6_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT6_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT6_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT6_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT6_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT6_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT6_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT6_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT6_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT6_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT6_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT6_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT6_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT6_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT7_STATUS 0x1359 +#define RTL8367C_PORT7_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT7_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT7_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT7_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT7_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT7_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT7_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT7_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT7_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT7_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT7_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT7_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT7_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT7_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT7_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT7_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT7_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT8_STATUS 0x135a +#define RTL8367C_PORT8_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT8_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT8_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT8_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT8_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT8_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT8_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT8_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT8_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT8_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT8_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT8_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT8_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT8_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT8_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT8_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT8_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT9_STATUS 0x135b +#define RTL8367C_PORT9_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT9_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT9_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT9_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT9_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT9_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT9_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT9_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT9_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT9_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT9_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT9_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT9_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT9_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT9_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT9_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT9_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_PORT10_STATUS 0x135c +#define RTL8367C_PORT10_STATUS_EN_1000_LPI_OFFSET 11 +#define RTL8367C_PORT10_STATUS_EN_1000_LPI_MASK 0x800 +#define RTL8367C_PORT10_STATUS_EN_100_LPI_OFFSET 10 +#define RTL8367C_PORT10_STATUS_EN_100_LPI_MASK 0x400 +#define RTL8367C_PORT10_STATUS_NWAY_FAULT_OFFSET 9 +#define RTL8367C_PORT10_STATUS_NWAY_FAULT_MASK 0x200 +#define RTL8367C_PORT10_STATUS_LINK_ON_MASTER_OFFSET 8 +#define RTL8367C_PORT10_STATUS_LINK_ON_MASTER_MASK 0x100 +#define RTL8367C_PORT10_STATUS_NWAY_CAP_OFFSET 7 +#define RTL8367C_PORT10_STATUS_NWAY_CAP_MASK 0x80 +#define RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_OFFSET 6 +#define RTL8367C_PORT10_STATUS_TX_FLOWCTRL_CAP_MASK 0x40 +#define RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_OFFSET 5 +#define RTL8367C_PORT10_STATUS_RX_FLOWCTRL_CAP_MASK 0x20 +#define RTL8367C_PORT10_STATUS_LINK_STATE_OFFSET 4 +#define RTL8367C_PORT10_STATUS_LINK_STATE_MASK 0x10 +#define RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_OFFSET 2 +#define RTL8367C_PORT10_STATUS_FULL_DUPLUX_CAP_MASK 0x4 +#define RTL8367C_PORT10_STATUS_LINK_SPEED_OFFSET 0 +#define RTL8367C_PORT10_STATUS_LINK_SPEED_MASK 0x3 + +#define RTL8367C_REG_UPS_CTRL0 0x1362 +#define RTL8367C_P3_REF_SD_BIT0_OFFSET 8 +#define RTL8367C_P3_REF_SD_BIT0_MASK 0xFF00 +#define RTL8367C_P2_REF_SD_OFFSET 0 +#define RTL8367C_P2_REF_SD_MASK 0xFF + +#define RTL8367C_REG_UPS_CTRL1 0x1363 +#define RTL8367C_UPS_OUT_OFFSET 8 +#define RTL8367C_UPS_OUT_MASK 0xFF00 +#define RTL8367C_UPS_WRITE_PULSE_OFFSET 1 +#define RTL8367C_UPS_WRITE_PULSE_MASK 0x2 +#define RTL8367C_UPS_EN_OFFSET 0 +#define RTL8367C_UPS_EN_MASK 0x1 + +#define RTL8367C_REG_UPS_CTRL2 0x1364 +#define RTL8367C_IGNOE_MAC8_LINK_OFFSET 15 +#define RTL8367C_IGNOE_MAC8_LINK_MASK 0x8000 +#define RTL8367C_AGREE_SLEEP_OFFSET 14 +#define RTL8367C_AGREE_SLEEP_MASK 0x4000 +#define RTL8367C_WAIT_FOR_AGREEMENT_OFFSET 13 +#define RTL8367C_WAIT_FOR_AGREEMENT_MASK 0x2000 +#define RTL8367C_WAKE_UP_BY_LINK_OFFSET 12 +#define RTL8367C_WAKE_UP_BY_LINK_MASK 0x1000 +#define RTL8367C_WAKE_UP_BY_PHY_OFFSET 11 +#define RTL8367C_WAKE_UP_BY_PHY_MASK 0x800 +#define RTL8367C_SLOW_CLK_TGL_RATE_OFFSET 7 +#define RTL8367C_SLOW_CLK_TGL_RATE_MASK 0x780 +#define RTL8367C_PLL_G1_CTRL_EN_OFFSET 6 +#define RTL8367C_PLL_G1_CTRL_EN_MASK 0x40 +#define RTL8367C_PLL_G0_CTRL_EN_OFFSET 5 +#define RTL8367C_PLL_G0_CTRL_EN_MASK 0x20 +#define RTL8367C_SLOW_DOWN_PLL_EN_OFFSET 4 +#define RTL8367C_SLOW_DOWN_PLL_EN_MASK 0x10 +#define RTL8367C_SLOW_DOWN_CLK_EN_OFFSET 3 +#define RTL8367C_SLOW_DOWN_CLK_EN_MASK 0x8 +#define RTL8367C_GATING_CLK_SDS_EN_OFFSET 2 +#define RTL8367C_GATING_CLK_SDS_EN_MASK 0x4 +#define RTL8367C_GATING_CLK_CHIP_EN_OFFSET 1 +#define RTL8367C_GATING_CLK_CHIP_EN_MASK 0x2 +#define RTL8367C_GATING_SW_EN_OFFSET 0 +#define RTL8367C_GATING_SW_EN_MASK 0x1 + +#define RTL8367C_REG_GATING_CLK_1 0x1365 +#define RTL8367C_ALDPS_MODE_4_OFFSET 15 +#define RTL8367C_ALDPS_MODE_4_MASK 0x8000 +#define RTL8367C_ALDPS_MODE_3_OFFSET 14 +#define RTL8367C_ALDPS_MODE_3_MASK 0x4000 +#define RTL8367C_ALDPS_MODE_2_OFFSET 13 +#define RTL8367C_ALDPS_MODE_2_MASK 0x2000 +#define RTL8367C_ALDPS_MODE_1_OFFSET 12 +#define RTL8367C_ALDPS_MODE_1_MASK 0x1000 +#define RTL8367C_ALDPS_MODE_0_OFFSET 11 +#define RTL8367C_ALDPS_MODE_0_MASK 0x800 +#define RTL8367C_UPS_DBGO_OFFSET 10 +#define RTL8367C_UPS_DBGO_MASK 0x400 +#define RTL8367C_IFMX_AFF_NOT_FF_OUT_OFFSET 9 +#define RTL8367C_IFMX_AFF_NOT_FF_OUT_MASK 0x200 +#define RTL8367C_WATER_LEVEL_FD_OFFSET 6 +#define RTL8367C_WATER_LEVEL_FD_MASK 0x1C0 +#define RTL8367C_WATER_LEVEL_Y2X_OFFSET 3 +#define RTL8367C_WATER_LEVEL_Y2X_MASK 0x38 +#define RTL8367C_WATER_LEVEL_X2Y_2_OFFSET 2 +#define RTL8367C_WATER_LEVEL_X2Y_2_MASK 0x4 +#define RTL8367C_IGNOE_MAC10_LINK_OFFSET 1 +#define RTL8367C_IGNOE_MAC10_LINK_MASK 0x2 +#define RTL8367C_IGNOE_MAC9_LINK_OFFSET 0 +#define RTL8367C_IGNOE_MAC9_LINK_MASK 0x1 + +#define RTL8367C_REG_UPS_CTRL4 0x1366 +#define RTL8367C_PROB_EN_OFFSET 6 +#define RTL8367C_PROB_EN_MASK 0x40 +#define RTL8367C_PLL_DOWN_OFFSET 1 +#define RTL8367C_PLL_DOWN_MASK 0x2 +#define RTL8367C_XTAL_DOWN_OFFSET 0 +#define RTL8367C_XTAL_DOWN_MASK 0x1 + +#define RTL8367C_REG_UPS_CTRL5 0x1367 +#define RTL8367C_FRC_CPU_ACPT_OFFSET 3 +#define RTL8367C_FRC_CPU_ACPT_MASK 0x8 +#define RTL8367C_UPS_CPU_ACPT_OFFSET 2 +#define RTL8367C_UPS_CPU_ACPT_MASK 0x4 +#define RTL8367C_UPS_DBG_4_OFFSET 0 +#define RTL8367C_UPS_DBG_4_MASK 0x3 + +#define RTL8367C_REG_UPS_CTRL6 0x1368 +#define RTL8367C_UPS_CTRL6_OFFSET 0 +#define RTL8367C_UPS_CTRL6_MASK 0xF + +#define RTL8367C_REG_EFUSE_CMD_70B 0x1369 + +#define RTL8367C_REG_EFUSE_CMD 0x1370 +#define RTL8367C_EFUSE_TIME_OUT_FLAG_OFFSET 3 +#define RTL8367C_EFUSE_TIME_OUT_FLAG_MASK 0x8 +#define RTL8367C_EFUSE_ACCESS_BUSY_OFFSET 2 +#define RTL8367C_EFUSE_ACCESS_BUSY_MASK 0x4 +#define RTL8367C_EFUSE_COMMAND_EN_OFFSET 1 +#define RTL8367C_EFUSE_COMMAND_EN_MASK 0x2 +#define RTL8367C_EFUSE_WR_OFFSET 0 +#define RTL8367C_EFUSE_WR_MASK 0x1 + +#define RTL8367C_REG_EFUSE_ADR 0x1371 +#define RTL8367C_DUMMY_15_10_OFFSET 8 +#define RTL8367C_DUMMY_15_10_MASK 0xFF00 +#define RTL8367C_EFUSE_ADDRESS_OFFSET 0 +#define RTL8367C_EFUSE_ADDRESS_MASK 0xFF + +#define RTL8367C_REG_EFUSE_WDAT 0x1372 + +#define RTL8367C_REG_EFUSE_RDAT 0x1373 + +#define RTL8367C_REG_I2C_CTRL 0x1374 +#define RTL8367C_MDX_MST_FAIL_LAT_OFFSET 1 +#define RTL8367C_MDX_MST_FAIL_LAT_MASK 0x2 +#define RTL8367C_MDX_MST_FAIL_CLRPS_OFFSET 0 +#define RTL8367C_MDX_MST_FAIL_CLRPS_MASK 0x1 + +#define RTL8367C_REG_EEE_CFG 0x1375 +#define RTL8367C_CFG_BYPASS_GATELPTD_OFFSET 11 +#define RTL8367C_CFG_BYPASS_GATELPTD_MASK 0x800 +#define RTL8367C_EEE_ABT_ADDR2_OFFSET 6 +#define RTL8367C_EEE_ABT_ADDR2_MASK 0x7C0 +#define RTL8367C_EEE_ABT_ADDR1_OFFSET 1 +#define RTL8367C_EEE_ABT_ADDR1_MASK 0x3E +#define RTL8367C_EEE_POLL_EN_OFFSET 0 +#define RTL8367C_EEE_POLL_EN_MASK 0x1 + +#define RTL8367C_REG_EEE_PAGE 0x1376 + +#define RTL8367C_REG_EEE_EXT_PAGE 0x1377 + +#define RTL8367C_REG_EEE_EN_SPD1000 0x1378 + +#define RTL8367C_REG_EEE_EN_SPD100 0x1379 + +#define RTL8367C_REG_EEE_LP_SPD1000 0x137a + +#define RTL8367C_REG_EEE_LP_SPD100 0x137b + +#define RTL8367C_REG_DW8051_PRO_REG0 0x13a0 + +#define RTL8367C_REG_DW8051_PRO_REG1 0x13a1 + +#define RTL8367C_REG_DW8051_PRO_REG2 0x13a2 + +#define RTL8367C_REG_DW8051_PRO_REG3 0x13a3 + +#define RTL8367C_REG_DW8051_PRO_REG4 0x13a4 + +#define RTL8367C_REG_DW8051_PRO_REG5 0x13a5 + +#define RTL8367C_REG_DW8051_PRO_REG6 0x13a6 + +#define RTL8367C_REG_DW8051_PRO_REG7 0x13a7 + +#define RTL8367C_REG_PROTECT_ID 0x13c0 + +#define RTL8367C_REG_CHIP_VER_INTL 0x13c1 +#define RTL8367C_CHIP_VER_INTL_OFFSET 0 +#define RTL8367C_CHIP_VER_INTL_MASK 0xF + +#define RTL8367C_REG_MAGIC_ID 0x13c2 + +#define RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1 0x13c3 +#define RTL8367C_SKIP_MII_2_RXER_OFFSET 4 +#define RTL8367C_SKIP_MII_2_RXER_MASK 0x10 +#define RTL8367C_SELECT_GMII_2_OFFSET 0 +#define RTL8367C_SELECT_GMII_2_MASK 0xF + +#define RTL8367C_REG_DIGITAL_INTERFACE2_FORCE 0x13c4 +#define RTL8367C_GMII_2_FORCE_OFFSET 12 +#define RTL8367C_GMII_2_FORCE_MASK 0x1000 +#define RTL8367C_RGMII_2_FORCE_OFFSET 0 +#define RTL8367C_RGMII_2_FORCE_MASK 0xFFF + +#define RTL8367C_REG_EXT2_RGMXF 0x13c5 +#define RTL8367C_EXT2_RGTX_INV_OFFSET 6 +#define RTL8367C_EXT2_RGTX_INV_MASK 0x40 +#define RTL8367C_EXT2_RGRX_INV_OFFSET 5 +#define RTL8367C_EXT2_RGRX_INV_MASK 0x20 +#define RTL8367C_EXT2_RGMXF_OFFSET 0 +#define RTL8367C_EXT2_RGMXF_MASK 0x1F + +#define RTL8367C_REG_ROUTER_UPS_CFG 0x13c6 +#define RTL8367C_UPS_Status_OFFSET 1 +#define RTL8367C_UPS_Status_MASK 0x2 +#define RTL8367C_SoftStart_OFFSET 0 +#define RTL8367C_SoftStart_MASK 0x1 + +#define RTL8367C_REG_CTRL_GPIO 0x13c7 +#define RTL8367C_CTRL_GPIO_13_OFFSET 13 +#define RTL8367C_CTRL_GPIO_13_MASK 0x2000 +#define RTL8367C_CTRL_GPIO_12_OFFSET 12 +#define RTL8367C_CTRL_GPIO_12_MASK 0x1000 +#define RTL8367C_CTRL_GPIO_11_OFFSET 11 +#define RTL8367C_CTRL_GPIO_11_MASK 0x800 +#define RTL8367C_CTRL_GPIO_10_OFFSET 10 +#define RTL8367C_CTRL_GPIO_10_MASK 0x400 +#define RTL8367C_CTRL_GPIO_9_OFFSET 9 +#define RTL8367C_CTRL_GPIO_9_MASK 0x200 +#define RTL8367C_CTRL_GPIO_8_OFFSET 8 +#define RTL8367C_CTRL_GPIO_8_MASK 0x100 +#define RTL8367C_CTRL_GPIO_7_OFFSET 7 +#define RTL8367C_CTRL_GPIO_7_MASK 0x80 +#define RTL8367C_CTRL_GPIO_6_OFFSET 6 +#define RTL8367C_CTRL_GPIO_6_MASK 0x40 +#define RTL8367C_CTRL_GPIO_5_OFFSET 5 +#define RTL8367C_CTRL_GPIO_5_MASK 0x20 +#define RTL8367C_CTRL_GPIO_4_OFFSET 4 +#define RTL8367C_CTRL_GPIO_4_MASK 0x10 +#define RTL8367C_CTRL_GPIO_3_OFFSET 3 +#define RTL8367C_CTRL_GPIO_3_MASK 0x8 +#define RTL8367C_CTRL_GPIO_2_OFFSET 2 +#define RTL8367C_CTRL_GPIO_2_MASK 0x4 +#define RTL8367C_CTRL_GPIO_1_OFFSET 1 +#define RTL8367C_CTRL_GPIO_1_MASK 0x2 +#define RTL8367C_CTRL_GPIO_0_OFFSET 0 +#define RTL8367C_CTRL_GPIO_0_MASK 0x1 + +#define RTL8367C_REG_SEL_GPIO 0x13c8 +#define RTL8367C_SEL_GPIO_13_OFFSET 13 +#define RTL8367C_SEL_GPIO_13_MASK 0x2000 +#define RTL8367C_SEL_GPIO_12_OFFSET 12 +#define RTL8367C_SEL_GPIO_12_MASK 0x1000 +#define RTL8367C_SEL_GPIO_11_OFFSET 11 +#define RTL8367C_SEL_GPIO_11_MASK 0x800 +#define RTL8367C_SEL_GPIO_10_OFFSET 10 +#define RTL8367C_SEL_GPIO_10_MASK 0x400 +#define RTL8367C_SEL_GPIO_9_OFFSET 9 +#define RTL8367C_SEL_GPIO_9_MASK 0x200 +#define RTL8367C_SEL_GPIO_8_OFFSET 8 +#define RTL8367C_SEL_GPIO_8_MASK 0x100 +#define RTL8367C_SEL_GPIO_7_OFFSET 7 +#define RTL8367C_SEL_GPIO_7_MASK 0x80 +#define RTL8367C_SEL_GPIO_6_OFFSET 6 +#define RTL8367C_SEL_GPIO_6_MASK 0x40 +#define RTL8367C_SEL_GPIO_5_OFFSET 5 +#define RTL8367C_SEL_GPIO_5_MASK 0x20 +#define RTL8367C_SEL_GPIO_4_OFFSET 4 +#define RTL8367C_SEL_GPIO_4_MASK 0x10 +#define RTL8367C_SEL_GPIO_3_OFFSET 3 +#define RTL8367C_SEL_GPIO_3_MASK 0x8 +#define RTL8367C_SEL_GPIO_2_OFFSET 2 +#define RTL8367C_SEL_GPIO_2_MASK 0x4 +#define RTL8367C_SEL_GPIO_1_OFFSET 1 +#define RTL8367C_SEL_GPIO_1_MASK 0x2 +#define RTL8367C_SEL_GPIO_0_OFFSET 0 +#define RTL8367C_SEL_GPIO_0_MASK 0x1 + +#define RTL8367C_REG_STATUS_GPIO 0x13c9 +#define RTL8367C_STATUS_GPIO_OFFSET 0 +#define RTL8367C_STATUS_GPIO_MASK 0x3FFF + +#define RTL8367C_REG_SYNC_ETH_CFG 0x13e0 +#define RTL8367C_DUMMY2_OFFSET 9 +#define RTL8367C_DUMMY2_MASK 0xFE00 +#define RTL8367C_RFC2819_TYPE_OFFSET 8 +#define RTL8367C_RFC2819_TYPE_MASK 0x100 +#define RTL8367C_DUMMY1_OFFSET 7 +#define RTL8367C_DUMMY1_MASK 0x80 +#define RTL8367C_FIBER_SYNCE125_L_SEL_OFFSET 6 +#define RTL8367C_FIBER_SYNCE125_L_SEL_MASK 0x40 +#define RTL8367C_SYNC_ETH_EN_RTT2_OFFSET 5 +#define RTL8367C_SYNC_ETH_EN_RTT2_MASK 0x20 +#define RTL8367C_SYNC_ETH_EN_RTT1_OFFSET 4 +#define RTL8367C_SYNC_ETH_EN_RTT1_MASK 0x10 +#define RTL8367C_SYNC_ETH_SEL_DPLL_OFFSET 3 +#define RTL8367C_SYNC_ETH_SEL_DPLL_MASK 0x8 +#define RTL8367C_SYNC_ETH_SEL_PHYREF_OFFSET 2 +#define RTL8367C_SYNC_ETH_SEL_PHYREF_MASK 0x4 +#define RTL8367C_SYNC_ETH_SEL_XTAL_OFFSET 1 +#define RTL8367C_SYNC_ETH_SEL_XTAL_MASK 0x2 +#define RTL8367C_DUMMY0_OFFSET 0 +#define RTL8367C_DUMMY0_MASK 0x1 + +#define RTL8367C_REG_LED_DRI_CFG 0x13e1 +#define RTL8367C_LED_DRI_CFG_DUMMY_OFFSET 1 +#define RTL8367C_LED_DRI_CFG_DUMMY_MASK 0xFFFE +#define RTL8367C_LED_DRIVING_OFFSET 0 +#define RTL8367C_LED_DRIVING_MASK 0x1 + +#define RTL8367C_REG_CHIP_DEBUG2 0x13e2 +#define RTL8367C_RG2_DN_OFFSET 6 +#define RTL8367C_RG2_DN_MASK 0x1C0 +#define RTL8367C_RG2_DP_OFFSET 3 +#define RTL8367C_RG2_DP_MASK 0x38 +#define RTL8367C_DRI_EXT2_RG_OFFSET 2 +#define RTL8367C_DRI_EXT2_RG_MASK 0x4 +#define RTL8367C_DRI_EXT2_OFFSET 1 +#define RTL8367C_DRI_EXT2_MASK 0x2 +#define RTL8367C_SLR_EXT2_OFFSET 0 +#define RTL8367C_SLR_EXT2_MASK 0x1 + +#define RTL8367C_REG_DIGITAL_DEBUG_2 0x13e3 + +#define RTL8367C_REG_FIBER_RTL_OUI_CFG0 0x13e4 +#define RTL8367C_FIBER_RTL_OUI_CFG0_OFFSET 0 +#define RTL8367C_FIBER_RTL_OUI_CFG0_MASK 0xFF + +#define RTL8367C_REG_FIBER_RTL_OUI_CFG1 0x13e5 + +#define RTL8367C_REG_FIBER_CFG_0 0x13e6 +#define RTL8367C_REV_NUM_OFFSET 8 +#define RTL8367C_REV_NUM_MASK 0xF00 +#define RTL8367C_MODEL_NUM_OFFSET 0 +#define RTL8367C_MODEL_NUM_MASK 0x3F + +#define RTL8367C_REG_FIBER_CFG_1 0x13e7 +#define RTL8367C_SDS_FRC_REG4_OFFSET 12 +#define RTL8367C_SDS_FRC_REG4_MASK 0x1000 +#define RTL8367C_SDS_FRC_REG4_FIB100_OFFSET 11 +#define RTL8367C_SDS_FRC_REG4_FIB100_MASK 0x800 +#define RTL8367C_SEL_MASK_ONL_OFFSET 5 +#define RTL8367C_SEL_MASK_ONL_MASK 0x20 +#define RTL8367C_DIS_QUALITY_IN_MASK_OFFSET 4 +#define RTL8367C_DIS_QUALITY_IN_MASK_MASK 0x10 +#define RTL8367C_SDS_FRC_MODE_OFFSET 3 +#define RTL8367C_SDS_FRC_MODE_MASK 0x8 +#define RTL8367C_SDS_MODE_OFFSET 0 +#define RTL8367C_SDS_MODE_MASK 0x7 + +#define RTL8367C_REG_FIBER_CFG_2 0x13e8 +#define RTL8367C_SEL_SDET_PS_OFFSET 12 +#define RTL8367C_SEL_SDET_PS_MASK 0xF000 +#define RTL8367C_UTP_DIS_RX_OFFSET 10 +#define RTL8367C_UTP_DIS_RX_MASK 0xC00 +#define RTL8367C_UTP_FRC_LD_OFFSET 8 +#define RTL8367C_UTP_FRC_LD_MASK 0x300 +#define RTL8367C_SDS_RX_DISABLE_OFFSET 6 +#define RTL8367C_SDS_RX_DISABLE_MASK 0xC0 +#define RTL8367C_SDS_TX_DISABLE_OFFSET 4 +#define RTL8367C_SDS_TX_DISABLE_MASK 0x30 +#define RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_OFFSET 2 +#define RTL8367C_FIBER_CFG_2_SDS_PWR_ISO_MASK 0xC +#define RTL8367C_SDS_FRC_LD_OFFSET 0 +#define RTL8367C_SDS_FRC_LD_MASK 0x3 + +#define RTL8367C_REG_FIBER_CFG_3 0x13e9 +#define RTL8367C_FIBER_CFG_3_OFFSET 0 +#define RTL8367C_FIBER_CFG_3_MASK 0xFFF + +#define RTL8367C_REG_FIBER_CFG_4 0x13ea + +#define RTL8367C_REG_UTP_FIB_DET 0x13eb +#define RTL8367C_FORCE_SEL_FIBER_OFFSET 14 +#define RTL8367C_FORCE_SEL_FIBER_MASK 0xC000 +#define RTL8367C_FIB_FINAL_TIMER_OFFSET 12 +#define RTL8367C_FIB_FINAL_TIMER_MASK 0x3000 +#define RTL8367C_FIB_LINK_TIMER_OFFSET 10 +#define RTL8367C_FIB_LINK_TIMER_MASK 0xC00 +#define RTL8367C_FIB_SDET_TIMER_OFFSET 8 +#define RTL8367C_FIB_SDET_TIMER_MASK 0x300 +#define RTL8367C_UTP_LINK_TIMER_OFFSET 6 +#define RTL8367C_UTP_LINK_TIMER_MASK 0xC0 +#define RTL8367C_UTP_SDET_TIMER_OFFSET 4 +#define RTL8367C_UTP_SDET_TIMER_MASK 0x30 +#define RTL8367C_FORCE_AUTODET_OFFSET 3 +#define RTL8367C_FORCE_AUTODET_MASK 0x8 +#define RTL8367C_AUTODET_FSM_CLR_OFFSET 2 +#define RTL8367C_AUTODET_FSM_CLR_MASK 0x4 +#define RTL8367C_UTP_FIRST_OFFSET 1 +#define RTL8367C_UTP_FIRST_MASK 0x2 +#define RTL8367C_UTP_FIB_DISAUTODET_OFFSET 0 +#define RTL8367C_UTP_FIB_DISAUTODET_MASK 0x1 + +#define RTL8367C_REG_NRESTORE_MAGIC_NUM 0x13ec +#define RTL8367C_NRESTORE_MAGIC_NUM_MASK 0xFFFF +#define RTL8367C_EEPROM_PROGRAM_CYCLE_OFFSET 0 +#define RTL8367C_EEPROM_PROGRAM_CYCLE_MASK 0x3 + +#define RTL8367C_REG_MAC_ACTIVE 0x13ee +#define RTL8367C_MAC_ACTIVE_H_OFFSET 9 +#define RTL8367C_MAC_ACTIVE_H_MASK 0xE00 +#define RTL8367C_FORCE_MAC_ACTIVE_OFFSET 8 +#define RTL8367C_FORCE_MAC_ACTIVE_MASK 0x100 +#define RTL8367C_MAC_ACTIVE_OFFSET 0 +#define RTL8367C_MAC_ACTIVE_MASK 0xFF + +#define RTL8367C_REG_SERDES_RESULT 0x13ef +#define RTL8367C_FIB100_DET_1_OFFSET 12 +#define RTL8367C_FIB100_DET_1_MASK 0x1000 +#define RTL8367C_FIB_ISO_1_OFFSET 11 +#define RTL8367C_FIB_ISO_1_MASK 0x800 +#define RTL8367C_SDS_ANFAULT_1_OFFSET 10 +#define RTL8367C_SDS_ANFAULT_1_MASK 0x400 +#define RTL8367C_SDS_INTB_1_OFFSET 9 +#define RTL8367C_SDS_INTB_1_MASK 0x200 +#define RTL8367C_SDS_LINK_OK_1_OFFSET 8 +#define RTL8367C_SDS_LINK_OK_1_MASK 0x100 +#define RTL8367C_FIB100_DET_OFFSET 4 +#define RTL8367C_FIB100_DET_MASK 0x10 +#define RTL8367C_FIB_ISO_OFFSET 3 +#define RTL8367C_FIB_ISO_MASK 0x8 +#define RTL8367C_SDS_ANFAULT_OFFSET 2 +#define RTL8367C_SDS_ANFAULT_MASK 0x4 +#define RTL8367C_SDS_INTB_OFFSET 1 +#define RTL8367C_SDS_INTB_MASK 0x2 +#define RTL8367C_SDS_LINK_OK_OFFSET 0 +#define RTL8367C_SDS_LINK_OK_MASK 0x1 + +#define RTL8367C_REG_CHIP_ECO 0x13f0 +#define RTL8367C_CFG_CHIP_ECO_OFFSET 1 +#define RTL8367C_CFG_CHIP_ECO_MASK 0xFFFE +#define RTL8367C_CFG_CKOUTEN_OFFSET 0 +#define RTL8367C_CFG_CKOUTEN_MASK 0x1 + +#define RTL8367C_REG_WAKELPI_SLOT_PRD 0x13f1 +#define RTL8367C_WAKELPI_SLOT_PRD_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_PRD_MASK 0x1F + +#define RTL8367C_REG_WAKELPI_SLOT_PG0 0x13f2 +#define RTL8367C_WAKELPI_SLOT_P1_OFFSET 8 +#define RTL8367C_WAKELPI_SLOT_P1_MASK 0x1F00 +#define RTL8367C_WAKELPI_SLOT_P0_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_P0_MASK 0x1F + +#define RTL8367C_REG_WAKELPI_SLOT_PG1 0x13f3 +#define RTL8367C_WAKELPI_SLOT_P3_OFFSET 8 +#define RTL8367C_WAKELPI_SLOT_P3_MASK 0x1F00 +#define RTL8367C_WAKELPI_SLOT_P2_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_P2_MASK 0x1F + +#define RTL8367C_REG_WAKELPI_SLOT_PG2 0x13f4 +#define RTL8367C_WAKELPI_SLOT_P5_OFFSET 8 +#define RTL8367C_WAKELPI_SLOT_P5_MASK 0x1F00 +#define RTL8367C_WAKELPI_SLOT_P4_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_P4_MASK 0x1F + +#define RTL8367C_REG_WAKELPI_SLOT_PG3 0x13f5 +#define RTL8367C_WAKELPI_SLOT_P7_OFFSET 8 +#define RTL8367C_WAKELPI_SLOT_P7_MASK 0x1F00 +#define RTL8367C_WAKELPI_SLOT_P6_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_P6_MASK 0x1F + +#define RTL8367C_REG_SYNC_FIFO_0 0x13f6 +#define RTL8367C_SYNC_FIFO_TX_OFFSET 8 +#define RTL8367C_SYNC_FIFO_TX_MASK 0x700 +#define RTL8367C_SYNC_FIFO_RX_OFFSET 0 +#define RTL8367C_SYNC_FIFO_RX_MASK 0xFF + +#define RTL8367C_REG_SYNC_FIFO_1 0x13f7 +#define RTL8367C_SYNC_FIFO_RX_ERR_P10_8_OFFSET 11 +#define RTL8367C_SYNC_FIFO_RX_ERR_P10_8_MASK 0x3800 +#define RTL8367C_SYNC_FIFO_TX_ERR_OFFSET 8 +#define RTL8367C_SYNC_FIFO_TX_ERR_MASK 0x700 +#define RTL8367C_SYNC_FIFO_RX_ERR_OFFSET 0 +#define RTL8367C_SYNC_FIFO_RX_ERR_MASK 0xFF + +#define RTL8367C_REG_RGM_EEE 0x13f8 +#define RTL8367C_EXT2_PAD_STOP_EN_OFFSET 14 +#define RTL8367C_EXT2_PAD_STOP_EN_MASK 0x4000 +#define RTL8367C_EXT1_PAD_STOP_EN_OFFSET 13 +#define RTL8367C_EXT1_PAD_STOP_EN_MASK 0x2000 +#define RTL8367C_EXT0_PAD_STOP_EN_OFFSET 12 +#define RTL8367C_EXT0_PAD_STOP_EN_MASK 0x1000 +#define RTL8367C_EXT2_CYCLE_PAD_OFFSET 8 +#define RTL8367C_EXT2_CYCLE_PAD_MASK 0xF00 +#define RTL8367C_EXT1_CYCLE_PAD_OFFSET 4 +#define RTL8367C_EXT1_CYCLE_PAD_MASK 0xF0 +#define RTL8367C_EXT0_CYCLE_PAD_OFFSET 0 +#define RTL8367C_EXT0_CYCLE_PAD_MASK 0xF + +#define RTL8367C_REG_EXT_TXC_DLY 0x13f9 +#define RTL8367C_EXT1_GMII_TX_DELAY_OFFSET 12 +#define RTL8367C_EXT1_GMII_TX_DELAY_MASK 0x7000 +#define RTL8367C_EXT0_GMII_TX_DELAY_OFFSET 9 +#define RTL8367C_EXT0_GMII_TX_DELAY_MASK 0xE00 +#define RTL8367C_EXT2_RGMII_TX_DELAY_OFFSET 6 +#define RTL8367C_EXT2_RGMII_TX_DELAY_MASK 0x1C0 +#define RTL8367C_EXT1_RGMII_TX_DELAY_OFFSET 3 +#define RTL8367C_EXT1_RGMII_TX_DELAY_MASK 0x38 +#define RTL8367C_EXT0_RGMII_TX_DELAY_OFFSET 0 +#define RTL8367C_EXT0_RGMII_TX_DELAY_MASK 0x7 + +#define RTL8367C_REG_IO_MISC_CTRL 0x13fa +#define RTL8367C_IO_BUZZER_EN_OFFSET 3 +#define RTL8367C_IO_BUZZER_EN_MASK 0x8 +#define RTL8367C_IO_INTRPT_EN_OFFSET 2 +#define RTL8367C_IO_INTRPT_EN_MASK 0x4 +#define RTL8367C_IO_NRESTORE_EN_OFFSET 1 +#define RTL8367C_IO_NRESTORE_EN_MASK 0x2 +#define RTL8367C_IO_UART_EN_OFFSET 0 +#define RTL8367C_IO_UART_EN_MASK 0x1 + +#define RTL8367C_REG_CHIP_DUMMY_NO 0x13fb +#define RTL8367C_CHIP_DUMMY_NO_OFFSET 0 +#define RTL8367C_CHIP_DUMMY_NO_MASK 0xF + +#define RTL8367C_REG_RC_CALIB_CFG 0x13fc +#define RTL8367C_TRIG_BURN_EFUSE_OFFSET 9 +#define RTL8367C_TRIG_BURN_EFUSE_MASK 0x200 +#define RTL8367C_AMP_CALIB_FAIL_OFFSET 8 +#define RTL8367C_AMP_CALIB_FAIL_MASK 0x100 +#define RTL8367C_R_CALIB_FAIL_OFFSET 7 +#define RTL8367C_R_CALIB_FAIL_MASK 0x80 +#define RTL8367C_CFG_CALIB_MODE_OFFSET 6 +#define RTL8367C_CFG_CALIB_MODE_MASK 0x40 +#define RTL8367C_CENTER_PORT_SEL_OFFSET 3 +#define RTL8367C_CENTER_PORT_SEL_MASK 0x38 +#define RTL8367C_CALIB_FINISH_OFFSET 2 +#define RTL8367C_CALIB_FINISH_MASK 0x4 +#define RTL8367C_CFG_CALIB_OPTION_OFFSET 1 +#define RTL8367C_CFG_CALIB_OPTION_MASK 0x2 +#define RTL8367C_CFG_CALIB_EN_OFFSET 0 +#define RTL8367C_CFG_CALIB_EN_MASK 0x1 + +#define RTL8367C_REG_WAKELPI_SLOT_PG4 0x13fd +#define RTL8367C_WAKELPI_SLOT_P9_OFFSET 8 +#define RTL8367C_WAKELPI_SLOT_P9_MASK 0x1F00 +#define RTL8367C_WAKELPI_SLOT_P8_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_P8_MASK 0x1F + +#define RTL8367C_REG_WAKELPI_SLOT_PG5 0x13fe +#define RTL8367C_WAKELPI_SLOT_PG5_OFFSET 0 +#define RTL8367C_WAKELPI_SLOT_PG5_MASK 0x1F + +/* (16'h1400)mtrpool_reg */ + +#define RTL8367C_REG_METER0_RATE_CTRL0 0x1400 + +#define RTL8367C_REG_METER0_RATE_CTRL1 0x1401 +#define RTL8367C_METER0_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER0_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER1_RATE_CTRL0 0x1402 + +#define RTL8367C_REG_METER1_RATE_CTRL1 0x1403 +#define RTL8367C_METER1_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER1_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER2_RATE_CTRL0 0x1404 + +#define RTL8367C_REG_METER2_RATE_CTRL1 0x1405 +#define RTL8367C_METER2_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER2_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER3_RATE_CTRL0 0x1406 + +#define RTL8367C_REG_METER3_RATE_CTRL1 0x1407 +#define RTL8367C_METER3_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER3_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER4_RATE_CTRL0 0x1408 + +#define RTL8367C_REG_METER4_RATE_CTRL1 0x1409 +#define RTL8367C_METER4_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER4_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER5_RATE_CTRL0 0x140a + +#define RTL8367C_REG_METER5_RATE_CTRL1 0x140b +#define RTL8367C_METER5_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER5_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER6_RATE_CTRL0 0x140c + +#define RTL8367C_REG_METER6_RATE_CTRL1 0x140d +#define RTL8367C_METER6_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER6_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER7_RATE_CTRL0 0x140e + +#define RTL8367C_REG_METER7_RATE_CTRL1 0x140f +#define RTL8367C_METER7_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER7_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER8_RATE_CTRL0 0x1410 + +#define RTL8367C_REG_METER8_RATE_CTRL1 0x1411 +#define RTL8367C_METER8_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER8_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER9_RATE_CTRL0 0x1412 + +#define RTL8367C_REG_METER9_RATE_CTRL1 0x1413 +#define RTL8367C_METER9_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER9_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER10_RATE_CTRL0 0x1414 + +#define RTL8367C_REG_METER10_RATE_CTRL1 0x1415 +#define RTL8367C_METER10_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER10_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER11_RATE_CTRL0 0x1416 + +#define RTL8367C_REG_METER11_RATE_CTRL1 0x1417 +#define RTL8367C_METER11_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER11_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER12_RATE_CTRL0 0x1418 + +#define RTL8367C_REG_METER12_RATE_CTRL1 0x1419 +#define RTL8367C_METER12_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER12_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER13_RATE_CTRL0 0x141a + +#define RTL8367C_REG_METER13_RATE_CTRL1 0x141b +#define RTL8367C_METER13_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER13_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER14_RATE_CTRL0 0x141c + +#define RTL8367C_REG_METER14_RATE_CTRL1 0x141d +#define RTL8367C_METER14_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER14_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER15_RATE_CTRL0 0x141e + +#define RTL8367C_REG_METER15_RATE_CTRL1 0x141f +#define RTL8367C_METER15_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER15_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER16_RATE_CTRL0 0x1420 + +#define RTL8367C_REG_METER16_RATE_CTRL1 0x1421 +#define RTL8367C_METER16_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER16_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER17_RATE_CTRL0 0x1422 + +#define RTL8367C_REG_METER17_RATE_CTRL1 0x1423 +#define RTL8367C_METER17_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER17_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER18_RATE_CTRL0 0x1424 + +#define RTL8367C_REG_METER18_RATE_CTRL1 0x1425 +#define RTL8367C_METER18_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER18_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER19_RATE_CTRL0 0x1426 + +#define RTL8367C_REG_METER19_RATE_CTRL1 0x1427 +#define RTL8367C_METER19_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER19_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER20_RATE_CTRL0 0x1428 + +#define RTL8367C_REG_METER20_RATE_CTRL1 0x1429 +#define RTL8367C_METER20_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER20_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER21_RATE_CTRL0 0x142a + +#define RTL8367C_REG_METER21_RATE_CTRL1 0x142b +#define RTL8367C_METER21_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER21_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER22_RATE_CTRL0 0x142c + +#define RTL8367C_REG_METER22_RATE_CTRL1 0x142d +#define RTL8367C_METER22_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER22_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER23_RATE_CTRL0 0x142e + +#define RTL8367C_REG_METER23_RATE_CTRL1 0x142f +#define RTL8367C_METER23_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER23_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER24_RATE_CTRL0 0x1430 + +#define RTL8367C_REG_METER24_RATE_CTRL1 0x1431 +#define RTL8367C_METER24_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER24_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER25_RATE_CTRL0 0x1432 + +#define RTL8367C_REG_METER25_RATE_CTRL1 0x1433 +#define RTL8367C_METER25_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER25_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER26_RATE_CTRL0 0x1434 + +#define RTL8367C_REG_METER26_RATE_CTRL1 0x1435 +#define RTL8367C_METER26_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER26_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER27_RATE_CTRL0 0x1436 + +#define RTL8367C_REG_METER27_RATE_CTRL1 0x1437 +#define RTL8367C_METER27_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER27_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER28_RATE_CTRL0 0x1438 + +#define RTL8367C_REG_METER28_RATE_CTRL1 0x1439 +#define RTL8367C_METER28_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER28_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER29_RATE_CTRL0 0x143a + +#define RTL8367C_REG_METER29_RATE_CTRL1 0x143b +#define RTL8367C_METER29_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER29_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER30_RATE_CTRL0 0x143c + +#define RTL8367C_REG_METER30_RATE_CTRL1 0x143d +#define RTL8367C_METER30_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER30_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER31_RATE_CTRL0 0x143e + +#define RTL8367C_REG_METER31_RATE_CTRL1 0x143f +#define RTL8367C_METER31_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER31_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER_MODE_SETTING0 0x1440 + +#define RTL8367C_REG_METER_MODE_SETTING1 0x1441 + +#define RTL8367C_REG_METER_MODE_TOKEN_CFG 0x1442 +#define RTL8367C_METER_MODE_TOKEN_CFG_OFFSET 0 +#define RTL8367C_METER_MODE_TOKEN_CFG_MASK 0x7FF + +#define RTL8367C_REG_METER0_BUCKET_SIZE 0x1600 + +#define RTL8367C_REG_METER1_BUCKET_SIZE 0x1601 + +#define RTL8367C_REG_METER2_BUCKET_SIZE 0x1602 + +#define RTL8367C_REG_METER3_BUCKET_SIZE 0x1603 + +#define RTL8367C_REG_METER4_BUCKET_SIZE 0x1604 + +#define RTL8367C_REG_METER5_BUCKET_SIZE 0x1605 + +#define RTL8367C_REG_METER6_BUCKET_SIZE 0x1606 + +#define RTL8367C_REG_METER7_BUCKET_SIZE 0x1607 + +#define RTL8367C_REG_METER8_BUCKET_SIZE 0x1608 + +#define RTL8367C_REG_METER9_BUCKET_SIZE 0x1609 + +#define RTL8367C_REG_METER10_BUCKET_SIZE 0x160a + +#define RTL8367C_REG_METER11_BUCKET_SIZE 0x160b + +#define RTL8367C_REG_METER12_BUCKET_SIZE 0x160c + +#define RTL8367C_REG_METER13_BUCKET_SIZE 0x160d + +#define RTL8367C_REG_METER14_BUCKET_SIZE 0x160e + +#define RTL8367C_REG_METER15_BUCKET_SIZE 0x160f + +#define RTL8367C_REG_METER16_BUCKET_SIZE 0x1610 + +#define RTL8367C_REG_METER17_BUCKET_SIZE 0x1611 + +#define RTL8367C_REG_METER18_BUCKET_SIZE 0x1612 + +#define RTL8367C_REG_METER19_BUCKET_SIZE 0x1613 + +#define RTL8367C_REG_METER20_BUCKET_SIZE 0x1614 + +#define RTL8367C_REG_METER21_BUCKET_SIZE 0x1615 + +#define RTL8367C_REG_METER22_BUCKET_SIZE 0x1616 + +#define RTL8367C_REG_METER23_BUCKET_SIZE 0x1617 + +#define RTL8367C_REG_METER24_BUCKET_SIZE 0x1618 + +#define RTL8367C_REG_METER25_BUCKET_SIZE 0x1619 + +#define RTL8367C_REG_METER26_BUCKET_SIZE 0x161a + +#define RTL8367C_REG_METER27_BUCKET_SIZE 0x161b + +#define RTL8367C_REG_METER28_BUCKET_SIZE 0x161c + +#define RTL8367C_REG_METER29_BUCKET_SIZE 0x161d + +#define RTL8367C_REG_METER30_BUCKET_SIZE 0x161e + +#define RTL8367C_REG_METER31_BUCKET_SIZE 0x161f + +#define RTL8367C_REG_METER_CTRL0 0x1700 +#define RTL8367C_METER_OP_OFFSET 8 +#define RTL8367C_METER_OP_MASK 0x100 +#define RTL8367C_METER_TICK_OFFSET 0 +#define RTL8367C_METER_TICK_MASK 0xFF + +#define RTL8367C_REG_METER_CTRL1 0x1701 +#define RTL8367C_METER_CTRL1_OFFSET 0 +#define RTL8367C_METER_CTRL1_MASK 0xFF + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR0 0x1702 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR1 0x1703 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR0_8051 0x1704 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR1_8051 0x1705 + +#define RTL8367C_REG_METER_IFG_CTRL0 0x1712 +#define RTL8367C_METER15_IFG_OFFSET 15 +#define RTL8367C_METER15_IFG_MASK 0x8000 +#define RTL8367C_METER14_IFG_OFFSET 14 +#define RTL8367C_METER14_IFG_MASK 0x4000 +#define RTL8367C_METER13_IFG_OFFSET 13 +#define RTL8367C_METER13_IFG_MASK 0x2000 +#define RTL8367C_METER12_IFG_OFFSET 12 +#define RTL8367C_METER12_IFG_MASK 0x1000 +#define RTL8367C_METER11_IFG_OFFSET 11 +#define RTL8367C_METER11_IFG_MASK 0x800 +#define RTL8367C_METER10_IFG_OFFSET 10 +#define RTL8367C_METER10_IFG_MASK 0x400 +#define RTL8367C_METER9_IFG_OFFSET 9 +#define RTL8367C_METER9_IFG_MASK 0x200 +#define RTL8367C_METER8_IFG_OFFSET 8 +#define RTL8367C_METER8_IFG_MASK 0x100 +#define RTL8367C_METER7_IFG_OFFSET 7 +#define RTL8367C_METER7_IFG_MASK 0x80 +#define RTL8367C_METER6_IFG_OFFSET 6 +#define RTL8367C_METER6_IFG_MASK 0x40 +#define RTL8367C_METER5_IFG_OFFSET 5 +#define RTL8367C_METER5_IFG_MASK 0x20 +#define RTL8367C_METER4_IFG_OFFSET 4 +#define RTL8367C_METER4_IFG_MASK 0x10 +#define RTL8367C_METER3_IFG_OFFSET 3 +#define RTL8367C_METER3_IFG_MASK 0x8 +#define RTL8367C_METER2_IFG_OFFSET 2 +#define RTL8367C_METER2_IFG_MASK 0x4 +#define RTL8367C_METER1_IFG_OFFSET 1 +#define RTL8367C_METER1_IFG_MASK 0x2 +#define RTL8367C_METER0_IFG_OFFSET 0 +#define RTL8367C_METER0_IFG_MASK 0x1 + +#define RTL8367C_REG_METER_IFG_CTRL1 0x1713 +#define RTL8367C_METER31_IFG_OFFSET 15 +#define RTL8367C_METER31_IFG_MASK 0x8000 +#define RTL8367C_METER30_IFG_OFFSET 14 +#define RTL8367C_METER30_IFG_MASK 0x4000 +#define RTL8367C_METER29_IFG_OFFSET 13 +#define RTL8367C_METER29_IFG_MASK 0x2000 +#define RTL8367C_METER28_IFG_OFFSET 12 +#define RTL8367C_METER28_IFG_MASK 0x1000 +#define RTL8367C_METER27_IFG_OFFSET 11 +#define RTL8367C_METER27_IFG_MASK 0x800 +#define RTL8367C_METER26_IFG_OFFSET 10 +#define RTL8367C_METER26_IFG_MASK 0x400 +#define RTL8367C_METER25_IFG_OFFSET 9 +#define RTL8367C_METER25_IFG_MASK 0x200 +#define RTL8367C_METER24_IFG_OFFSET 8 +#define RTL8367C_METER24_IFG_MASK 0x100 +#define RTL8367C_METER23_IFG_OFFSET 7 +#define RTL8367C_METER23_IFG_MASK 0x80 +#define RTL8367C_METER22_IFG_OFFSET 6 +#define RTL8367C_METER22_IFG_MASK 0x40 +#define RTL8367C_METER21_IFG_OFFSET 5 +#define RTL8367C_METER21_IFG_MASK 0x20 +#define RTL8367C_METER20_IFG_OFFSET 4 +#define RTL8367C_METER20_IFG_MASK 0x10 +#define RTL8367C_METER19_IFG_OFFSET 3 +#define RTL8367C_METER19_IFG_MASK 0x8 +#define RTL8367C_METER18_IFG_OFFSET 2 +#define RTL8367C_METER18_IFG_MASK 0x4 +#define RTL8367C_METER17_IFG_OFFSET 1 +#define RTL8367C_METER17_IFG_MASK 0x2 +#define RTL8367C_METER16_IFG_OFFSET 0 +#define RTL8367C_METER16_IFG_MASK 0x1 + +#define RTL8367C_REG_METER_CTRL2 0x1722 +#define RTL8367C_cfg_mtr_tick_8g_OFFSET 8 +#define RTL8367C_cfg_mtr_tick_8g_MASK 0xFF00 +#define RTL8367C_cfg_mtr_dec_cnt_8g_OFFSET 0 +#define RTL8367C_cfg_mtr_dec_cnt_8g_MASK 0xFF + +#define RTL8367C_REG_DUMMY_1723 0x1723 + +#define RTL8367C_REG_DUMMY_1724 0x1724 + +#define RTL8367C_REG_DUMMY_1725 0x1725 + +#define RTL8367C_REG_DUMMY_1726 0x1726 + +#define RTL8367C_REG_DUMMY_1727 0x1727 + +#define RTL8367C_REG_DUMMY_1728 0x1728 + +#define RTL8367C_REG_DUMMY_1729 0x1729 + +#define RTL8367C_REG_DUMMY_172A 0x172a + +#define RTL8367C_REG_DUMMY_172B 0x172b + +#define RTL8367C_REG_DUMMY_172C 0x172c + +#define RTL8367C_REG_DUMMY_172D 0x172d + +#define RTL8367C_REG_DUMMY_172E 0x172e + +#define RTL8367C_REG_DUMMY_172F 0x172f + +#define RTL8367C_REG_DUMMY_1730 0x1730 + +#define RTL8367C_REG_DUMMY_1731 0x1731 + +#define RTL8367C_REG_METER32_RATE_CTRL0 0x1740 + +#define RTL8367C_REG_METER32_RATE_CTRL1 0x1741 +#define RTL8367C_METER32_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER32_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER33_RATE_CTRL0 0x1742 + +#define RTL8367C_REG_METER33_RATE_CTRL1 0x1743 +#define RTL8367C_METER33_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER33_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER34_RATE_CTRL0 0x1744 + +#define RTL8367C_REG_METER34_RATE_CTRL1 0x1745 +#define RTL8367C_METER34_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER34_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER35_RATE_CTRL0 0x1746 + +#define RTL8367C_REG_METER35_RATE_CTRL1 0x1747 +#define RTL8367C_METER35_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER35_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER36_RATE_CTRL0 0x1748 + +#define RTL8367C_REG_METER36_RATE_CTRL1 0x1749 +#define RTL8367C_METER36_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER36_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER37_RATE_CTRL0 0x174a + +#define RTL8367C_REG_METER37_RATE_CTRL1 0x174b +#define RTL8367C_METER37_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER37_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER38_RATE_CTRL0 0x174c + +#define RTL8367C_REG_METER38_RATE_CTRL1 0x174d +#define RTL8367C_METER38_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER38_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER39_RATE_CTRL0 0x174e + +#define RTL8367C_REG_METER39_RATE_CTRL1 0x174f +#define RTL8367C_METER39_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER39_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER40_RATE_CTRL0 0x1750 + +#define RTL8367C_REG_METER40_RATE_CTRL1 0x1751 +#define RTL8367C_METER40_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER40_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER41_RATE_CTRL0 0x1752 + +#define RTL8367C_REG_METER41_RATE_CTRL1 0x1753 +#define RTL8367C_METER41_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER41_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER42_RATE_CTRL0 0x1754 + +#define RTL8367C_REG_METER42_RATE_CTRL1 0x1755 +#define RTL8367C_METER42_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER42_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER43_RATE_CTRL0 0x1756 + +#define RTL8367C_REG_METER43_RATE_CTRL1 0x1757 +#define RTL8367C_METER43_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER43_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER44_RATE_CTRL0 0x1758 + +#define RTL8367C_REG_METER44_RATE_CTRL1 0x1759 +#define RTL8367C_METER44_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER44_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER45_RATE_CTRL0 0x175a + +#define RTL8367C_REG_METER45_RATE_CTRL1 0x175b +#define RTL8367C_METER45_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER45_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER46_RATE_CTRL0 0x175c + +#define RTL8367C_REG_METER46_RATE_CTRL1 0x175d +#define RTL8367C_METER46_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER46_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER47_RATE_CTRL0 0x175e + +#define RTL8367C_REG_METER47_RATE_CTRL1 0x175f +#define RTL8367C_METER47_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER47_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER48_RATE_CTRL0 0x1760 + +#define RTL8367C_REG_METER48_RATE_CTRL1 0x1761 +#define RTL8367C_METER48_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER48_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER49_RATE_CTRL0 0x1762 + +#define RTL8367C_REG_METER49_RATE_CTRL1 0x1763 +#define RTL8367C_METER49_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER49_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER50_RATE_CTRL0 0x1764 + +#define RTL8367C_REG_METER50_RATE_CTRL1 0x1765 +#define RTL8367C_METER50_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER50_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER51_RATE_CTRL0 0x1766 + +#define RTL8367C_REG_METER51_RATE_CTRL1 0x1767 +#define RTL8367C_METER51_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER51_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER52_RATE_CTRL0 0x1768 + +#define RTL8367C_REG_METER52_RATE_CTRL1 0x1769 +#define RTL8367C_METER52_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER52_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER53_RATE_CTRL0 0x176a + +#define RTL8367C_REG_METER53_RATE_CTRL1 0x176b +#define RTL8367C_METER53_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER53_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER54_RATE_CTRL0 0x176c + +#define RTL8367C_REG_METER54_RATE_CTRL1 0x176d +#define RTL8367C_METER54_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER54_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER55_RATE_CTRL0 0x176e + +#define RTL8367C_REG_METER55_RATE_CTRL1 0x176f +#define RTL8367C_METER55_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER55_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER56_RATE_CTRL0 0x1770 + +#define RTL8367C_REG_METER56_RATE_CTRL1 0x1771 +#define RTL8367C_METER56_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER56_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER57_RATE_CTRL0 0x1772 + +#define RTL8367C_REG_METER57_RATE_CTRL1 0x1773 +#define RTL8367C_METER57_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER57_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER58_RATE_CTRL0 0x1774 + +#define RTL8367C_REG_METER58_RATE_CTRL1 0x1775 +#define RTL8367C_METER58_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER58_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER59_RATE_CTRL0 0x1776 + +#define RTL8367C_REG_METER59_RATE_CTRL1 0x1777 +#define RTL8367C_METER59_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER59_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER60_RATE_CTRL0 0x1778 + +#define RTL8367C_REG_METER60_RATE_CTRL1 0x1779 +#define RTL8367C_METER60_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER60_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER61_RATE_CTRL0 0x177a + +#define RTL8367C_REG_METER61_RATE_CTRL1 0x177b +#define RTL8367C_METER61_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER61_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER62_RATE_CTRL0 0x177c + +#define RTL8367C_REG_METER62_RATE_CTRL1 0x177d +#define RTL8367C_METER62_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER62_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER63_RATE_CTRL0 0x177e + +#define RTL8367C_REG_METER63_RATE_CTRL1 0x177f +#define RTL8367C_METER63_RATE_CTRL1_OFFSET 0 +#define RTL8367C_METER63_RATE_CTRL1_MASK 0x7 + +#define RTL8367C_REG_METER_MODE_SETTING2 0x1780 + +#define RTL8367C_REG_METER_MODE_SETTING3 0x1781 + +#define RTL8367C_REG_METER32_BUCKET_SIZE 0x1790 + +#define RTL8367C_REG_METER33_BUCKET_SIZE 0x1791 + +#define RTL8367C_REG_METER34_BUCKET_SIZE 0x1792 + +#define RTL8367C_REG_METER35_BUCKET_SIZE 0x1793 + +#define RTL8367C_REG_METER36_BUCKET_SIZE 0x1794 + +#define RTL8367C_REG_METER37_BUCKET_SIZE 0x1795 + +#define RTL8367C_REG_METER38_BUCKET_SIZE 0x1796 + +#define RTL8367C_REG_METER39_BUCKET_SIZE 0x1797 + +#define RTL8367C_REG_METER40_BUCKET_SIZE 0x1798 + +#define RTL8367C_REG_METER41_BUCKET_SIZE 0x1799 + +#define RTL8367C_REG_METER42_BUCKET_SIZE 0x179a + +#define RTL8367C_REG_METER43_BUCKET_SIZE 0x179b + +#define RTL8367C_REG_METER44_BUCKET_SIZE 0x179c + +#define RTL8367C_REG_METER45_BUCKET_SIZE 0x179d + +#define RTL8367C_REG_METER46_BUCKET_SIZE 0x179e + +#define RTL8367C_REG_METER47_BUCKET_SIZE 0x179f + +#define RTL8367C_REG_METER48_BUCKET_SIZE 0x17a0 + +#define RTL8367C_REG_METER49_BUCKET_SIZE 0x17a1 + +#define RTL8367C_REG_METER50_BUCKET_SIZE 0x17a2 + +#define RTL8367C_REG_METER51_BUCKET_SIZE 0x17a3 + +#define RTL8367C_REG_METER52_BUCKET_SIZE 0x17a4 + +#define RTL8367C_REG_METER53_BUCKET_SIZE 0x17a5 + +#define RTL8367C_REG_METER54_BUCKET_SIZE 0x17a6 + +#define RTL8367C_REG_METER55_BUCKET_SIZE 0x17a7 + +#define RTL8367C_REG_METER56_BUCKET_SIZE 0x17a8 + +#define RTL8367C_REG_METER57_BUCKET_SIZE 0x17a9 + +#define RTL8367C_REG_METER58_BUCKET_SIZE 0x17aa + +#define RTL8367C_REG_METER59_BUCKET_SIZE 0x17ab + +#define RTL8367C_REG_METER60_BUCKET_SIZE 0x17ac + +#define RTL8367C_REG_METER61_BUCKET_SIZE 0x17ad + +#define RTL8367C_REG_METER62_BUCKET_SIZE 0x17ae + +#define RTL8367C_REG_METER63_BUCKET_SIZE 0x17af + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR2 0x17b0 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR3 0x17b1 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR2_8051 0x17b2 + +#define RTL8367C_REG_METER_OVERRATE_INDICATOR3_8051 0x17b3 + +#define RTL8367C_REG_METER_IFG_CTRL2 0x17b4 +#define RTL8367C_METER47_IFG_OFFSET 15 +#define RTL8367C_METER47_IFG_MASK 0x8000 +#define RTL8367C_METER46_IFG_OFFSET 14 +#define RTL8367C_METER46_IFG_MASK 0x4000 +#define RTL8367C_METER45_IFG_OFFSET 13 +#define RTL8367C_METER45_IFG_MASK 0x2000 +#define RTL8367C_METER44_IFG_OFFSET 12 +#define RTL8367C_METER44_IFG_MASK 0x1000 +#define RTL8367C_METER43_IFG_OFFSET 11 +#define RTL8367C_METER43_IFG_MASK 0x800 +#define RTL8367C_METER42_IFG_OFFSET 10 +#define RTL8367C_METER42_IFG_MASK 0x400 +#define RTL8367C_METER41_IFG_OFFSET 9 +#define RTL8367C_METER41_IFG_MASK 0x200 +#define RTL8367C_METER40_IFG_OFFSET 8 +#define RTL8367C_METER40_IFG_MASK 0x100 +#define RTL8367C_METER39_IFG_OFFSET 7 +#define RTL8367C_METER39_IFG_MASK 0x80 +#define RTL8367C_METER38_IFG_OFFSET 6 +#define RTL8367C_METER38_IFG_MASK 0x40 +#define RTL8367C_METER37_IFG_OFFSET 5 +#define RTL8367C_METER37_IFG_MASK 0x20 +#define RTL8367C_METER36_IFG_OFFSET 4 +#define RTL8367C_METER36_IFG_MASK 0x10 +#define RTL8367C_METER35_IFG_OFFSET 3 +#define RTL8367C_METER35_IFG_MASK 0x8 +#define RTL8367C_METER34_IFG_OFFSET 2 +#define RTL8367C_METER34_IFG_MASK 0x4 +#define RTL8367C_METER33_IFG_OFFSET 1 +#define RTL8367C_METER33_IFG_MASK 0x2 +#define RTL8367C_METER32_IFG_OFFSET 0 +#define RTL8367C_METER32_IFG_MASK 0x1 + +#define RTL8367C_REG_METER_IFG_CTRL3 0x17b5 +#define RTL8367C_METER63_IFG_OFFSET 15 +#define RTL8367C_METER63_IFG_MASK 0x8000 +#define RTL8367C_METER62_IFG_OFFSET 14 +#define RTL8367C_METER62_IFG_MASK 0x4000 +#define RTL8367C_METER61_IFG_OFFSET 13 +#define RTL8367C_METER61_IFG_MASK 0x2000 +#define RTL8367C_METER60_IFG_OFFSET 12 +#define RTL8367C_METER60_IFG_MASK 0x1000 +#define RTL8367C_METER59_IFG_OFFSET 11 +#define RTL8367C_METER59_IFG_MASK 0x800 +#define RTL8367C_METER58_IFG_OFFSET 10 +#define RTL8367C_METER58_IFG_MASK 0x400 +#define RTL8367C_METER57_IFG_OFFSET 9 +#define RTL8367C_METER57_IFG_MASK 0x200 +#define RTL8367C_METER56_IFG_OFFSET 8 +#define RTL8367C_METER56_IFG_MASK 0x100 +#define RTL8367C_METER55_IFG_OFFSET 7 +#define RTL8367C_METER55_IFG_MASK 0x80 +#define RTL8367C_METER54_IFG_OFFSET 6 +#define RTL8367C_METER54_IFG_MASK 0x40 +#define RTL8367C_METER53_IFG_OFFSET 5 +#define RTL8367C_METER53_IFG_MASK 0x20 +#define RTL8367C_METER52_IFG_OFFSET 4 +#define RTL8367C_METER52_IFG_MASK 0x10 +#define RTL8367C_METER51_IFG_OFFSET 3 +#define RTL8367C_METER51_IFG_MASK 0x8 +#define RTL8367C_METER50_IFG_OFFSET 2 +#define RTL8367C_METER50_IFG_MASK 0x4 +#define RTL8367C_METER49_IFG_OFFSET 1 +#define RTL8367C_METER49_IFG_MASK 0x2 +#define RTL8367C_METER48_IFG_OFFSET 0 +#define RTL8367C_METER48_IFG_MASK 0x1 + +#define RTL8367C_REG_METER_MISC 0x17b6 +#define RTL8367C_METER_MISC_OFFSET 0 +#define RTL8367C_METER_MISC_MASK 0x1 + +/* (16'h1800)8051_RLDP_EEE_reg */ + +#define RTL8367C_REG_EEELLDP_CTRL0 0x1820 +#define RTL8367C_EEELLDP_SUBTYPE_OFFSET 6 +#define RTL8367C_EEELLDP_SUBTYPE_MASK 0x3FC0 +#define RTL8367C_EEELLDP_TRAP_8051_OFFSET 2 +#define RTL8367C_EEELLDP_TRAP_8051_MASK 0x4 +#define RTL8367C_EEELLDP_TRAP_CPU_OFFSET 1 +#define RTL8367C_EEELLDP_TRAP_CPU_MASK 0x2 +#define RTL8367C_EEELLDP_ENABLE_OFFSET 0 +#define RTL8367C_EEELLDP_ENABLE_MASK 0x1 + +#define RTL8367C_REG_EEELLDP_PMSK 0x1822 +#define RTL8367C_EEELLDP_PMSK_OFFSET 0 +#define RTL8367C_EEELLDP_PMSK_MASK 0x7FF + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_08 0x1843 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_07 0x1844 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_06 0x1845 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_05 0x1846 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_04 0x1847 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_03 0x1848 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_02 0x1849 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_01 0x184a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P00_00 0x184b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_08 0x184c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_07 0x184d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_06 0x184e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_05 0x184f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_04 0x1850 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_03 0x1851 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_02 0x1852 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_01 0x1853 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P01_00 0x1854 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_08 0x1855 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_07 0x1856 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_06 0x1857 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_05 0x1858 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_04 0x1859 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_03 0x185a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_02 0x185b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_01 0x185c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P02_00 0x185d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_08 0x185e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_07 0x185f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_06 0x1860 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_05 0x1861 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_04 0x1862 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_03 0x1863 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_02 0x1864 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_01 0x1865 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P03_00 0x1866 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_08 0x1867 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_07 0x1868 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_06 0x1869 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_05 0x186a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_04 0x186b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_03 0x186c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_02 0x186d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_01 0x186e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P04_00 0x186f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_08 0x1870 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_07 0x1871 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_06 0x1872 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_05 0x1873 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_04 0x1874 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_03 0x1875 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_02 0x1876 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_01 0x1877 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P05_00 0x1878 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_08 0x1879 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_07 0x187a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_06 0x187b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_05 0x187c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_04 0x187d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_03 0x187e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_02 0x187f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_01 0x1880 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P06_00 0x1881 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_08 0x1882 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_07 0x1883 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_06 0x1884 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_05 0x1885 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_04 0x1886 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_03 0x1887 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_02 0x1888 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_01 0x1889 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P07_00 0x188a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_08 0x188b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_07 0x188c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_06 0x188d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_05 0x188e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_04 0x188f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_03 0x1890 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_02 0x1891 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_01 0x1892 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P08_00 0x1893 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_08 0x1894 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_07 0x1895 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_06 0x1896 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_05 0x1897 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_04 0x1898 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_03 0x1899 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_02 0x189a + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_01 0x189b + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P09_00 0x189c + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_08 0x189d + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_07 0x189e + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_06 0x189f + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_05 0x18a0 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_04 0x18a1 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_03 0x18a2 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_02 0x18a3 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_01 0x18a4 + +#define RTL8367C_REG_EEELLDP_RX_VALUE_P10_00 0x18a5 + +#define RTL8367C_REG_RLDP_CTRL0 0x18e0 +#define RTL8367C_RLDP_TRIGGER_MODE_OFFSET 14 +#define RTL8367C_RLDP_TRIGGER_MODE_MASK 0x4000 +#define RTL8367C_RLDP_8051_LOOP_PORTMSK_OFFSET 6 +#define RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK 0x3FC0 +#define RTL8367C_RLPP_8051_TRAP_OFFSET 5 +#define RTL8367C_RLPP_8051_TRAP_MASK 0x20 +#define RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET 4 +#define RTL8367C_RLDP_INDICATOR_SOURCE_MASK 0x10 +#define RTL8367C_RLDP_GEN_RANDOM_OFFSET 3 +#define RTL8367C_RLDP_GEN_RANDOM_MASK 0x8 +#define RTL8367C_RLDP_COMP_ID_OFFSET 2 +#define RTL8367C_RLDP_COMP_ID_MASK 0x4 +#define RTL8367C_RLDP_8051_ENABLE_OFFSET 1 +#define RTL8367C_RLDP_8051_ENABLE_MASK 0x2 +#define RTL8367C_RLDP_ENABLE_OFFSET 0 +#define RTL8367C_RLDP_ENABLE_MASK 0x1 + +#define RTL8367C_REG_RLDP_CTRL1 0x18e1 +#define RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_OFFSET 8 +#define RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK 0xFF00 +#define RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_OFFSET 0 +#define RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK 0xFF + +#define RTL8367C_REG_RLDP_CTRL2 0x18e2 + +#define RTL8367C_REG_RLDP_CTRL3 0x18e3 + +#define RTL8367C_REG_RLDP_CTRL4 0x18e4 +#define RTL8367C_RLDP_CTRL4_OFFSET 0 +#define RTL8367C_RLDP_CTRL4_MASK 0x7FF + +#define RTL8367C_REG_RLDP_RAND_NUM0 0x18e5 + +#define RTL8367C_REG_RLDP_RAND_NUM1 0x18e6 + +#define RTL8367C_REG_RLDP_RAND_NUM2 0x18e7 + +#define RTL8367C_REG_RLDP_MAGIC_NUM0 0x18e8 + +#define RTL8367C_REG_RLDP_MAGIC_NUM1 0x18e9 + +#define RTL8367C_REG_RLDP_MAGIC_NUM2 0x18ea + +#define RTL8367C_REG_RLDP_LOOPED_INDICATOR 0x18eb +#define RTL8367C_RLDP_LOOPED_INDICATOR_OFFSET 0 +#define RTL8367C_RLDP_LOOPED_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG0 0x18ec +#define RTL8367C_RLDP_LOOP_PORT_01_OFFSET 8 +#define RTL8367C_RLDP_LOOP_PORT_01_MASK 0xF00 +#define RTL8367C_RLDP_LOOP_PORT_00_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_00_MASK 0xF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG1 0x18ed +#define RTL8367C_RLDP_LOOP_PORT_03_OFFSET 8 +#define RTL8367C_RLDP_LOOP_PORT_03_MASK 0xF00 +#define RTL8367C_RLDP_LOOP_PORT_02_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_02_MASK 0xF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG2 0x18ee +#define RTL8367C_RLDP_LOOP_PORT_05_OFFSET 8 +#define RTL8367C_RLDP_LOOP_PORT_05_MASK 0xF00 +#define RTL8367C_RLDP_LOOP_PORT_04_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_04_MASK 0xF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG3 0x18ef +#define RTL8367C_RLDP_LOOP_PORT_07_OFFSET 8 +#define RTL8367C_RLDP_LOOP_PORT_07_MASK 0xF00 +#define RTL8367C_RLDP_LOOP_PORT_06_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_06_MASK 0xF + +#define RTL8367C_REG_RLDP_RELEASED_INDICATOR 0x18f0 +#define RTL8367C_RLDP_RELEASED_INDICATOR_OFFSET 0 +#define RTL8367C_RLDP_RELEASED_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_RLDP_LOOPSTATUS_INDICATOR 0x18f1 +#define RTL8367C_RLDP_LOOPSTATUS_INDICATOR_OFFSET 0 +#define RTL8367C_RLDP_LOOPSTATUS_INDICATOR_MASK 0x7FF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG4 0x18f2 +#define RTL8367C_RLDP_LOOP_PORT_9_OFFSET 8 +#define RTL8367C_RLDP_LOOP_PORT_9_MASK 0xF00 +#define RTL8367C_RLDP_LOOP_PORT_8_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_8_MASK 0xF + +#define RTL8367C_REG_RLDP_LOOP_PORT_REG5 0x18f3 +#define RTL8367C_RLDP_LOOP_PORT_REG5_OFFSET 0 +#define RTL8367C_RLDP_LOOP_PORT_REG5_MASK 0xF + +#define RTL8367C_REG_RLDP_CTRL5 0x18f4 +#define RTL8367C_RLDP_CTRL5_OFFSET 0 +#define RTL8367C_RLDP_CTRL5_MASK 0x7 + +/* (16'h1900)EEE_EEEP_reg */ + +#define RTL8367C_REG_EEE_500M_CTRL0 0x1900 +#define RTL8367C_EEE_500M_CTRL0_OFFSET 0 +#define RTL8367C_EEE_500M_CTRL0_MASK 0xFF + +#define RTL8367C_REG_EEE_RXIDLE_GIGA_CTRL 0x1901 +#define RTL8367C_EEE_RXIDLE_GIGA_EN_OFFSET 8 +#define RTL8367C_EEE_RXIDLE_GIGA_EN_MASK 0x100 +#define RTL8367C_EEE_RXIDLE_GIGA_OFFSET 0 +#define RTL8367C_EEE_RXIDLE_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEE_RXIDLE_500M_CTRL 0x1902 +#define RTL8367C_EEE_RXIDLE_500M_EN_OFFSET 8 +#define RTL8367C_EEE_RXIDLE_500M_EN_MASK 0x100 +#define RTL8367C_EEE_RXIDLE_500M_OFFSET 0 +#define RTL8367C_EEE_RXIDLE_500M_MASK 0xFF + +#define RTL8367C_REG_EEE_DECISION_GIGA_500M 0x1903 +#define RTL8367C_EEE_DECISION_GIGA_OFFSET 8 +#define RTL8367C_EEE_DECISION_GIGA_MASK 0xFF00 +#define RTL8367C_EEE_DECISION_500M_OFFSET 0 +#define RTL8367C_EEE_DECISION_500M_MASK 0xFF + +#define RTL8367C_REG_EEE_DECISION_100M 0x1904 +#define RTL8367C_EEE_DECISION_100M_OFFSET 0 +#define RTL8367C_EEE_DECISION_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_DEFER_TXLPI 0x1905 +#define RTL8367C_EEEP_DEFER_TXLPI_OFFSET 0 +#define RTL8367C_EEEP_DEFER_TXLPI_MASK 0x1 + +#define RTL8367C_REG_EEEP_EN 0x1906 +#define RTL8367C_EEEP_SLAVE_EN_OFFSET 3 +#define RTL8367C_EEEP_SLAVE_EN_MASK 0x8 +#define RTL8367C_EEEP_100M_OFFSET 2 +#define RTL8367C_EEEP_100M_MASK 0x4 +#define RTL8367C_EEEP_500M_OFFSET 1 +#define RTL8367C_EEEP_500M_MASK 0x2 +#define RTL8367C_EEEP_GIGA_OFFSET 0 +#define RTL8367C_EEEP_GIGA_MASK 0x1 + +#define RTL8367C_REG_EEEP_TI_GIGA_500M 0x1907 +#define RTL8367C_EEEP_TI_GIGA_OFFSET 8 +#define RTL8367C_EEEP_TI_GIGA_MASK 0xFF00 +#define RTL8367C_EEEP_TI_500M_OFFSET 0 +#define RTL8367C_EEEP_TI_500M_MASK 0xFF + +#define RTL8367C_REG_EEEP_TI_100M 0x1908 +#define RTL8367C_EEEP_TI_100M_OFFSET 0 +#define RTL8367C_EEEP_TI_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_CTRL2 0x1909 +#define RTL8367C_EEEP_CTRL2_OFFSET 0 +#define RTL8367C_EEEP_CTRL2_MASK 0xFF + +#define RTL8367C_REG_EEEP_RX_RATE_500M 0x190b + +#define RTL8367C_REG_EEEP_RW_GIGA_SLV 0x190c +#define RTL8367C_EEEP_RW_GIGA_SLV_OFFSET 0 +#define RTL8367C_EEEP_RW_GIGA_SLV_MASK 0xFF + +#define RTL8367C_REG_EEEP_TMR_GIGA 0x190d +#define RTL8367C_RX_IDLE_EEEP_GIGA_OFFSET 8 +#define RTL8367C_RX_IDLE_EEEP_GIGA_MASK 0xFF00 +#define RTL8367C_RX_MIN_SLP_TMR_GIGA_OFFSET 0 +#define RTL8367C_RX_MIN_SLP_TMR_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEEP_TMR_500M 0x190e +#define RTL8367C_RX_IDLE_EEEP_500M_OFFSET 8 +#define RTL8367C_RX_IDLE_EEEP_500M_MASK 0xFF00 +#define RTL8367C_RX_MIN_SLP_TMR_500M_OFFSET 0 +#define RTL8367C_RX_MIN_SLP_TMR_500M_MASK 0xFF + +#define RTL8367C_REG_EEEP_TMR_100M 0x190f +#define RTL8367C_RX_IDLE_EEEP_100M_OFFSET 8 +#define RTL8367C_RX_IDLE_EEEP_100M_MASK 0xFF00 +#define RTL8367C_RX_MIN_SLP_TMR_100M_OFFSET 0 +#define RTL8367C_RX_MIN_SLP_TMR_100M_MASK 0xFF + +#define RTL8367C_REG_EEEP_RW_500M_MST_SLV 0x1910 +#define RTL8367C_EEEP_RW_500M_MST_OFFSET 8 +#define RTL8367C_EEEP_RW_500M_MST_MASK 0xFF00 +#define RTL8367C_EEEP_RW_500M_SLV_OFFSET 0 +#define RTL8367C_EEEP_RW_500M_SLV_MASK 0xFF + +#define RTL8367C_REG_EEEP_500M_CTRL0 0x1911 +#define RTL8367C_EEEP_500M_CTRL0_OFFSET 0 +#define RTL8367C_EEEP_500M_CTRL0_MASK 0xFF + +#define RTL8367C_REG_EEEP_500M_CTRL1 0x1912 +#define RTL8367C_EEEP_TW_500M_OFFSET 8 +#define RTL8367C_EEEP_TW_500M_MASK 0xFF00 +#define RTL8367C_EEEP_TP_500M_OFFSET 0 +#define RTL8367C_EEEP_TP_500M_MASK 0xFF + +#define RTL8367C_REG_EEEP_500M_CTRL2 0x1913 +#define RTL8367C_EEEP_TXEN_500M_OFFSET 12 +#define RTL8367C_EEEP_TXEN_500M_MASK 0x1000 +#define RTL8367C_EEEP_TU_500M_OFFSET 8 +#define RTL8367C_EEEP_TU_500M_MASK 0x300 +#define RTL8367C_EEEP_TS_500M_OFFSET 0 +#define RTL8367C_EEEP_TS_500M_MASK 0xFF + +#define RTL8367C_REG_EEE_NEW_CTRL0 0x1914 +#define RTL8367C_LINK_UP_DELAY_OFFSET 3 +#define RTL8367C_LINK_UP_DELAY_MASK 0x18 +#define RTL8367C_EEE_TXLPI_ORI_OFFSET 2 +#define RTL8367C_EEE_TXLPI_ORI_MASK 0x4 +#define RTL8367C_REALTX_SEL_OFFSET 1 +#define RTL8367C_REALTX_SEL_MASK 0x2 +#define RTL8367C_EN_FC_EFCT_OFFSET 0 +#define RTL8367C_EN_FC_EFCT_MASK 0x1 + +#define RTL8367C_REG_EEE_LONGIDLE_100M 0x1915 +#define RTL8367C_EEE_LONGIDLE_100M_OFFSET 0 +#define RTL8367C_EEE_LONGIDLE_100M_MASK 0x3FF + +#define RTL8367C_REG_EEE_LONGIDLE_500M 0x1916 +#define RTL8367C_EEE_LONGIDLE_500M_OFFSET 0 +#define RTL8367C_EEE_LONGIDLE_500M_MASK 0x3FF + +#define RTL8367C_REG_EEE_LONGIDLE_GIGA 0x1917 +#define RTL8367C_EEE_LONGIDLE_GIGA_OFFSET 0 +#define RTL8367C_EEE_LONGIDLE_GIGA_MASK 0x3FF + +#define RTL8367C_REG_EEE_MINIPG_100M 0x1918 + +#define RTL8367C_REG_EEE_MINIPG_500M 0x1919 + +#define RTL8367C_REG_EEE_MINIPG_GIGA 0x191A + +#define RTL8367C_REG_EEE_LONGIDLE_CTRL0 0x191B +#define RTL8367C_TX_IDLEN_REQ_100M_OFFSET 10 +#define RTL8367C_TX_IDLEN_REQ_100M_MASK 0x400 +#define RTL8367C_TX_IDLEN_REQ_500M_OFFSET 9 +#define RTL8367C_TX_IDLEN_REQ_500M_MASK 0x200 +#define RTL8367C_TX_IDLEN_REQ_GIGA_OFFSET 8 +#define RTL8367C_TX_IDLEN_REQ_GIGA_MASK 0x100 +#define RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_OFFSET 0 +#define RTL8367C_EEE_LONGIDLE_CTRL0_TX_LPI_MINIPG_100M_MASK 0xFF + +#define RTL8367C_REG_EEE_LONGIDLE_CTRL1 0x191C +#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_OFFSET 8 +#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GELITE_MASK 0xFF00 +#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_OFFSET 0 +#define RTL8367C_EEE_LONGIDLE_CTRL1_TX_LPI_MINIPG_GIGA_MASK 0xFF + +#define RTL8367C_REG_EEE_TD_CTRL_H 0x191d +#define RTL8367C_REF_RXLPI_OFFSET 8 +#define RTL8367C_REF_RXLPI_MASK 0x100 +#define RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_OFFSET 4 +#define RTL8367C_LOW_Q_TX_DELAY_GE_500M_H_MASK 0xF0 +#define RTL8367C_LOW_Q_TX_DELAY_FE_H_OFFSET 0 +#define RTL8367C_LOW_Q_TX_DELAY_FE_H_MASK 0xF + +/* (16'h1a00)nic_reg */ + +#define RTL8367C_REG_NIC_RXRDRL 0x1a04 +#define RTL8367C_NIC_RXRDRL_OFFSET 0 +#define RTL8367C_NIC_RXRDRL_MASK 0xFF + +#define RTL8367C_REG_NIC_RXRDRH 0x1a05 +#define RTL8367C_NIC_RXRDRH_OFFSET 0 +#define RTL8367C_NIC_RXRDRH_MASK 0xFF + +#define RTL8367C_REG_NIC_TXASRL 0x1a08 +#define RTL8367C_NIC_TXASRL_OFFSET 0 +#define RTL8367C_NIC_TXASRL_MASK 0xFF + +#define RTL8367C_REG_NIC_TXASRH 0x1a09 +#define RTL8367C_NIC_TXASRH_OFFSET 0 +#define RTL8367C_NIC_TXASRH_MASK 0xFF + +#define RTL8367C_REG_NIC_RXCMDR 0x1a0c +#define RTL8367C_NIC_RXCMDR_OFFSET 0 +#define RTL8367C_NIC_RXCMDR_MASK 0x1 + +#define RTL8367C_REG_NIC_TXCMDR 0x1a0d +#define RTL8367C_NIC_TXCMDR_OFFSET 0 +#define RTL8367C_NIC_TXCMDR_MASK 0x1 + +#define RTL8367C_REG_NIC_IMS 0x1a0e +#define RTL8367C_NIC_RXIS_OFFSET 7 +#define RTL8367C_NIC_RXIS_MASK 0x80 +#define RTL8367C_NIC_TXIS_OFFSET 6 +#define RTL8367C_NIC_TXIS_MASK 0x40 +#define RTL8367C_NIC_TXES_OFFSET 5 +#define RTL8367C_NIC_TXES_MASK 0x20 +#define RTL8367C_NIC_IMS_DMY_OFFSET 4 +#define RTL8367C_NIC_IMS_DMY_MASK 0x10 +#define RTL8367C_NIC_RXBUS_OFFSET 3 +#define RTL8367C_NIC_RXBUS_MASK 0x8 +#define RTL8367C_NIC_TXBOS_OFFSET 2 +#define RTL8367C_NIC_TXBOS_MASK 0x4 +#define RTL8367C_NIC_RXMIS_OFFSET 1 +#define RTL8367C_NIC_RXMIS_MASK 0x2 +#define RTL8367C_NIC_TXNLS_OFFSET 0 +#define RTL8367C_NIC_TXNLS_MASK 0x1 + +#define RTL8367C_REG_NIC_IMR 0x1a0f +#define RTL8367C_NIC_RXIE_OFFSET 7 +#define RTL8367C_NIC_RXIE_MASK 0x80 +#define RTL8367C_NIC_TXIE_OFFSET 6 +#define RTL8367C_NIC_TXIE_MASK 0x40 +#define RTL8367C_NIC_TXEE_OFFSET 5 +#define RTL8367C_NIC_TXEE_MASK 0x20 +#define RTL8367C_NIC_IMR_DMY_OFFSET 4 +#define RTL8367C_NIC_IMR_DMY_MASK 0x10 +#define RTL8367C_NIC_RXBUE_OFFSET 3 +#define RTL8367C_NIC_RXBUE_MASK 0x8 +#define RTL8367C_NIC_TXBOE_OFFSET 2 +#define RTL8367C_NIC_TXBOE_MASK 0x4 +#define RTL8367C_NIC_RXMIE_OFFSET 1 +#define RTL8367C_NIC_RXMIE_MASK 0x2 +#define RTL8367C_NIC_TXNLE_OFFSET 0 +#define RTL8367C_NIC_TXNLE_MASK 0x1 + +#define RTL8367C_REG_NIC_RXCR0 0x1a14 +#define RTL8367C_NIC_HFPPE_OFFSET 7 +#define RTL8367C_NIC_HFPPE_MASK 0x80 +#define RTL8367C_NIC_HFMPE_OFFSET 6 +#define RTL8367C_NIC_HFMPE_MASK 0x40 +#define RTL8367C_NIC_RXBPE_OFFSET 5 +#define RTL8367C_NIC_RXBPE_MASK 0x20 +#define RTL8367C_NIC_RXMPE_OFFSET 4 +#define RTL8367C_NIC_RXMPE_MASK 0x10 +#define RTL8367C_NIC_RXPPS_OFFSET 2 +#define RTL8367C_NIC_RXPPS_MASK 0xC +#define RTL8367C_NIC_RXAPE_OFFSET 1 +#define RTL8367C_NIC_RXAPE_MASK 0x2 +#define RTL8367C_NIC_ARPPE_OFFSET 0 +#define RTL8367C_NIC_ARPPE_MASK 0x1 + +#define RTL8367C_REG_NIC_RXCR1 0x1a15 +#define RTL8367C_NIC_RL4CEPE_OFFSET 4 +#define RTL8367C_NIC_RL4CEPE_MASK 0x10 +#define RTL8367C_NIC_RL3CEPE_OFFSET 3 +#define RTL8367C_NIC_RL3CEPE_MASK 0x8 +#define RTL8367C_NIC_RCRCEPE_OFFSET 2 +#define RTL8367C_NIC_RCRCEPE_MASK 0x4 +#define RTL8367C_NIC_RMCRC_OFFSET 1 +#define RTL8367C_NIC_RMCRC_MASK 0x2 +#define RTL8367C_NIC_RXENABLE_OFFSET 0 +#define RTL8367C_NIC_RXENABLE_MASK 0x1 + +#define RTL8367C_REG_NIC_TXCR 0x1a16 +#define RTL8367C_NIC_LBE_OFFSET 2 +#define RTL8367C_NIC_LBE_MASK 0x4 +#define RTL8367C_NIC_TXMFM_OFFSET 1 +#define RTL8367C_NIC_TXMFM_MASK 0x2 +#define RTL8367C_NIC_TXENABLE_OFFSET 0 +#define RTL8367C_NIC_TXENABLE_MASK 0x1 + +#define RTL8367C_REG_NIC_GCR 0x1a17 +#define RTL8367C_DUMMY_7_6_OFFSET 6 +#define RTL8367C_DUMMY_7_6_MASK 0xC0 +#define RTL8367C_NIC_RXMTU_OFFSET 4 +#define RTL8367C_NIC_RXMTU_MASK 0x30 +#define RTL8367C_NIC_GCR_DUMMY_0_OFFSET 0 +#define RTL8367C_NIC_GCR_DUMMY_0_MASK 0x1 + +#define RTL8367C_REG_NIC_MHR0 0x1a24 +#define RTL8367C_NIC_MHR0_OFFSET 0 +#define RTL8367C_NIC_MHR0_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR1 0x1a25 +#define RTL8367C_NIC_MHR1_OFFSET 0 +#define RTL8367C_NIC_MHR1_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR2 0x1a26 +#define RTL8367C_NIC_MHR2_OFFSET 0 +#define RTL8367C_NIC_MHR2_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR3 0x1a27 +#define RTL8367C_NIC_MHR3_OFFSET 0 +#define RTL8367C_NIC_MHR3_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR4 0x1a28 +#define RTL8367C_NIC_MHR4_OFFSET 0 +#define RTL8367C_NIC_MHR4_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR5 0x1a29 +#define RTL8367C_NIC_MHR5_OFFSET 0 +#define RTL8367C_NIC_MHR5_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR6 0x1a2a +#define RTL8367C_NIC_MHR6_OFFSET 0 +#define RTL8367C_NIC_MHR6_MASK 0xFF + +#define RTL8367C_REG_NIC_MHR7 0x1a2b +#define RTL8367C_NIC_MHR7_OFFSET 0 +#define RTL8367C_NIC_MHR7_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR0 0x1a2c +#define RTL8367C_NIC_PAHR0_OFFSET 0 +#define RTL8367C_NIC_PAHR0_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR1 0x1a2d +#define RTL8367C_NIC_PAHR1_OFFSET 0 +#define RTL8367C_NIC_PAHR1_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR2 0x1a2e +#define RTL8367C_NIC_PAHR2_OFFSET 0 +#define RTL8367C_NIC_PAHR2_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR3 0x1a2f +#define RTL8367C_NIC_PAHR3_OFFSET 0 +#define RTL8367C_NIC_PAHR3_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR4 0x1a30 +#define RTL8367C_NIC_PAHR4_OFFSET 0 +#define RTL8367C_NIC_PAHR4_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR5 0x1a31 +#define RTL8367C_NIC_PAHR5_OFFSET 0 +#define RTL8367C_NIC_PAHR5_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR6 0x1a32 +#define RTL8367C_NIC_PAHR6_OFFSET 0 +#define RTL8367C_NIC_PAHR6_MASK 0xFF + +#define RTL8367C_REG_NIC_PAHR7 0x1a33 +#define RTL8367C_NIC_PAHR7_OFFSET 0 +#define RTL8367C_NIC_PAHR7_MASK 0xFF + +#define RTL8367C_REG_NIC_TXSTOPRL 0x1a44 +#define RTL8367C_NIC_TXSTOPRL_OFFSET 0 +#define RTL8367C_NIC_TXSTOPRL_MASK 0xFF + +#define RTL8367C_REG_NIC_TXSTOPRH 0x1a45 +#define RTL8367C_NIC_TXSTOPRH_OFFSET 0 +#define RTL8367C_NIC_TXSTOPRH_MASK 0x3 + +#define RTL8367C_REG_NIC_RXSTOPRL 0x1a46 +#define RTL8367C_NIC_RXSTOPRL_OFFSET 0 +#define RTL8367C_NIC_RXSTOPRL_MASK 0xFF + +#define RTL8367C_REG_NIC_RXSTOPRH 0x1a47 +#define RTL8367C_NIC_RXSTOPRH_OFFSET 0 +#define RTL8367C_NIC_RXSTOPRH_MASK 0x3 + +#define RTL8367C_REG_NIC_RXFSTR 0x1a48 +#define RTL8367C_NIC_RXFSTR_OFFSET 0 +#define RTL8367C_NIC_RXFSTR_MASK 0xFF + +#define RTL8367C_REG_NIC_RXMBTRL 0x1a4c +#define RTL8367C_NIC_RXMBTRL_OFFSET 0 +#define RTL8367C_NIC_RXMBTRL_MASK 0xFF + +#define RTL8367C_REG_NIC_RXMBTRH 0x1a4d +#define RTL8367C_NIC_RXMBTRH_OFFSET 0 +#define RTL8367C_NIC_RXMBTRH_MASK 0x7F + +#define RTL8367C_REG_NIC_RXMPTR 0x1a4e +#define RTL8367C_NIC_RXMPTR_OFFSET 0 +#define RTL8367C_NIC_RXMPTR_MASK 0xFF + +#define RTL8367C_REG_NIC_T0TR 0x1a4f +#define RTL8367C_NIC_T0TR_OFFSET 0 +#define RTL8367C_NIC_T0TR_MASK 0xFF + +#define RTL8367C_REG_NIC_CRXCPRL 0x1a50 +#define RTL8367C_NIC_CRXCPRL_OFFSET 0 +#define RTL8367C_NIC_CRXCPRL_MASK 0xFF + +#define RTL8367C_REG_NIC_CRXCPRH 0x1a51 +#define RTL8367C_NIC_CRXCPRH_OFFSET 0 +#define RTL8367C_NIC_CRXCPRH_MASK 0xFF + +#define RTL8367C_REG_NIC_CTXCPRL 0x1a52 +#define RTL8367C_NIC_CTXCPRL_OFFSET 0 +#define RTL8367C_NIC_CTXCPRL_MASK 0xFF + +#define RTL8367C_REG_NIC_CTXPCRH 0x1a53 +#define RTL8367C_NIC_CTXPCRH_OFFSET 0 +#define RTL8367C_NIC_CTXPCRH_MASK 0xFF + +#define RTL8367C_REG_NIC_SRXCURPKTRL 0x1a54 +#define RTL8367C_NIC_SRXCURPKTRL_OFFSET 0 +#define RTL8367C_NIC_SRXCURPKTRL_MASK 0xFF + +#define RTL8367C_REG_NIC_SRXCURPKTRH 0x1a55 +#define RTL8367C_NIC_SRXCURPKTRH_OFFSET 0 +#define RTL8367C_NIC_SRXCURPKTRH_MASK 0xFF + +#define RTL8367C_REG_NIC_STXCURPKTRL 0x1a56 +#define RTL8367C_NIC_STXCURPKTRL_OFFSET 0 +#define RTL8367C_NIC_STXCURPKTRL_MASK 0xFF + +#define RTL8367C_REG_NIC_STXCURPKTRH 0x1a57 +#define RTL8367C_NIC_STXCURPKTRH_OFFSET 0 +#define RTL8367C_NIC_STXCURPKTRH_MASK 0xFF + +#define RTL8367C_REG_NIC_STXPKTLENRL 0x1a58 +#define RTL8367C_NIC_STXPKTLENRL_OFFSET 0 +#define RTL8367C_NIC_STXPKTLENRL_MASK 0xFF + +#define RTL8367C_REG_NIC_STXPKTLENRH 0x1a59 +#define RTL8367C_NIC_STXPKTLENRH_OFFSET 0 +#define RTL8367C_NIC_STXPKTLENRH_MASK 0xFF + +#define RTL8367C_REG_NIC_STXCURUNITRL 0x1a5a +#define RTL8367C_NIC_STXCURUNITRL_OFFSET 0 +#define RTL8367C_NIC_STXCURUNITRL_MASK 0xFF + +#define RTL8367C_REG_NIC_STXCURUNITRH 0x1a5b +#define RTL8367C_NIC_STXCURUNITRH_OFFSET 0 +#define RTL8367C_NIC_STXCURUNITRH_MASK 0xFF + +#define RTL8367C_REG_NIC_DROP_MODE 0x1a5c +#define RTL8367C_NIC_RXDV_MODE_OFFSET 1 +#define RTL8367C_NIC_RXDV_MODE_MASK 0x2 +#define RTL8367C_NIC_DROP_MODE_OFFSET 0 +#define RTL8367C_NIC_DROP_MODE_MASK 0x1 + +/* (16'h1b00)LED */ + +#define RTL8367C_REG_LED_SYS_CONFIG 0x1b00 +#define RTL8367C_LED_SYS_CONFIG_DUMMY_15_OFFSET 15 +#define RTL8367C_LED_SYS_CONFIG_DUMMY_15_MASK 0x8000 +#define RTL8367C_LED_SERIAL_OUT_MODE_OFFSET 14 +#define RTL8367C_LED_SERIAL_OUT_MODE_MASK 0x4000 +#define RTL8367C_LED_EEE_LPI_MODE_OFFSET 13 +#define RTL8367C_LED_EEE_LPI_MODE_MASK 0x2000 +#define RTL8367C_LED_EEE_LPI_EN_OFFSET 12 +#define RTL8367C_LED_EEE_LPI_EN_MASK 0x1000 +#define RTL8367C_LED_EEE_LPI_10_OFFSET 11 +#define RTL8367C_LED_EEE_LPI_10_MASK 0x800 +#define RTL8367C_LED_EEE_CAP_10_OFFSET 10 +#define RTL8367C_LED_EEE_CAP_10_MASK 0x400 +#define RTL8367C_LED_LPI_SEL_OFFSET 8 +#define RTL8367C_LED_LPI_SEL_MASK 0x300 +#define RTL8367C_SERI_LED_ACT_LOW_OFFSET 7 +#define RTL8367C_SERI_LED_ACT_LOW_MASK 0x80 +#define RTL8367C_LED_POWERON_2_OFFSET 6 +#define RTL8367C_LED_POWERON_2_MASK 0x40 +#define RTL8367C_LED_POWERON_1_OFFSET 5 +#define RTL8367C_LED_POWERON_1_MASK 0x20 +#define RTL8367C_LED_POWERON_0_OFFSET 4 +#define RTL8367C_LED_POWERON_0_MASK 0x10 +#define RTL8367C_LED_IO_DISABLE_OFFSET 3 +#define RTL8367C_LED_IO_DISABLE_MASK 0x8 +#define RTL8367C_DUMMY_2_2_OFFSET 2 +#define RTL8367C_DUMMY_2_2_MASK 0x4 +#define RTL8367C_LED_SELECT_OFFSET 0 +#define RTL8367C_LED_SELECT_MASK 0x3 + +#define RTL8367C_REG_LED_SYS_CONFIG2 0x1b01 +#define RTL8367C_LED_SYS_CONFIG2_DUMMY_OFFSET 2 +#define RTL8367C_LED_SYS_CONFIG2_DUMMY_MASK 0xFFFC +#define RTL8367C_GATE_LPTD_BYPASS_OFFSET 1 +#define RTL8367C_GATE_LPTD_BYPASS_MASK 0x2 +#define RTL8367C_LED_SPD_MODE_OFFSET 0 +#define RTL8367C_LED_SPD_MODE_MASK 0x1 + +#define RTL8367C_REG_LED_MODE 0x1b02 +#define RTL8367C_DLINK_TIME_OFFSET 15 +#define RTL8367C_DLINK_TIME_MASK 0x8000 +#define RTL8367C_LED_BUZZ_DUTY_OFFSET 14 +#define RTL8367C_LED_BUZZ_DUTY_MASK 0x4000 +#define RTL8367C_BUZZER_RATE_OFFSET 12 +#define RTL8367C_BUZZER_RATE_MASK 0x3000 +#define RTL8367C_LOOP_DETECT_MODE_OFFSET 11 +#define RTL8367C_LOOP_DETECT_MODE_MASK 0x800 +#define RTL8367C_SEL_PWRON_TIME_OFFSET 9 +#define RTL8367C_SEL_PWRON_TIME_MASK 0x600 +#define RTL8367C_EN_DLINK_LED_OFFSET 8 +#define RTL8367C_EN_DLINK_LED_MASK 0x100 +#define RTL8367C_LOOP_DETECT_RATE_OFFSET 6 +#define RTL8367C_LOOP_DETECT_RATE_MASK 0xC0 +#define RTL8367C_FORCE_RATE_OFFSET 4 +#define RTL8367C_FORCE_RATE_MASK 0x30 +#define RTL8367C_SEL_LEDRATE_OFFSET 1 +#define RTL8367C_SEL_LEDRATE_MASK 0xE +#define RTL8367C_SPEED_UP_OFFSET 0 +#define RTL8367C_SPEED_UP_MASK 0x1 + +#define RTL8367C_REG_LED_CONFIGURATION 0x1b03 +#define RTL8367C_LED_CONFIGURATION_DUMMY_OFFSET 15 +#define RTL8367C_LED_CONFIGURATION_DUMMY_MASK 0x8000 +#define RTL8367C_LED_CONFIG_SEL_OFFSET 14 +#define RTL8367C_LED_CONFIG_SEL_MASK 0x4000 +#define RTL8367C_DATA_LED_OFFSET 12 +#define RTL8367C_DATA_LED_MASK 0x3000 +#define RTL8367C_LED2_CFG_OFFSET 8 +#define RTL8367C_LED2_CFG_MASK 0xF00 +#define RTL8367C_LED1_CFG_OFFSET 4 +#define RTL8367C_LED1_CFG_MASK 0xF0 +#define RTL8367C_LED0_CFG_OFFSET 0 +#define RTL8367C_LED0_CFG_MASK 0xF + +#define RTL8367C_REG_RTCT_RESULTS_CFG 0x1b04 +#define RTL8367C_RTCT_2PAIR_FTT_OFFSET 15 +#define RTL8367C_RTCT_2PAIR_FTT_MASK 0x8000 +#define RTL8367C_RTCT_2PAIR_MODE_OFFSET 14 +#define RTL8367C_RTCT_2PAIR_MODE_MASK 0x4000 +#define RTL8367C_BLINK_EN_OFFSET 13 +#define RTL8367C_BLINK_EN_MASK 0x2000 +#define RTL8367C_TIMEOUT_OFFSET 12 +#define RTL8367C_TIMEOUT_MASK 0x1000 +#define RTL8367C_EN_CD_SAME_SHORT_OFFSET 11 +#define RTL8367C_EN_CD_SAME_SHORT_MASK 0x800 +#define RTL8367C_EN_CD_SAME_OPEN_OFFSET 10 +#define RTL8367C_EN_CD_SAME_OPEN_MASK 0x400 +#define RTL8367C_EN_CD_SAME_LINEDRIVER_OFFSET 9 +#define RTL8367C_EN_CD_SAME_LINEDRIVER_MASK 0x200 +#define RTL8367C_EN_CD_SAME_MISMATCH_OFFSET 8 +#define RTL8367C_EN_CD_SAME_MISMATCH_MASK 0x100 +#define RTL8367C_EN_CD_SHORT_OFFSET 7 +#define RTL8367C_EN_CD_SHORT_MASK 0x80 +#define RTL8367C_EN_AB_SHORT_OFFSET 6 +#define RTL8367C_EN_AB_SHORT_MASK 0x40 +#define RTL8367C_EN_CD_OPEN_OFFSET 5 +#define RTL8367C_EN_CD_OPEN_MASK 0x20 +#define RTL8367C_EN_AB_OPEN_OFFSET 4 +#define RTL8367C_EN_AB_OPEN_MASK 0x10 +#define RTL8367C_EN_CD_MISMATCH_OFFSET 3 +#define RTL8367C_EN_CD_MISMATCH_MASK 0x8 +#define RTL8367C_EN_AB_MISMATCH_OFFSET 2 +#define RTL8367C_EN_AB_MISMATCH_MASK 0x4 +#define RTL8367C_EN_CD_LINEDRIVER_OFFSET 1 +#define RTL8367C_EN_CD_LINEDRIVER_MASK 0x2 +#define RTL8367C_EN_AB_LINEDRIVER_OFFSET 0 +#define RTL8367C_EN_AB_LINEDRIVER_MASK 0x1 + +#define RTL8367C_REG_RTCT_LED 0x1b05 +#define RTL8367C_DUMMY_1b05a_OFFSET 12 +#define RTL8367C_DUMMY_1b05a_MASK 0xF000 +#define RTL8367C_RTCT_LED2_OFFSET 8 +#define RTL8367C_RTCT_LED2_MASK 0xF00 +#define RTL8367C_RTCT_LED1_OFFSET 4 +#define RTL8367C_RTCT_LED1_MASK 0xF0 +#define RTL8367C_RTCT_LED0_OFFSET 0 +#define RTL8367C_RTCT_LED0_MASK 0xF + +#define RTL8367C_REG_CPU_FORCE_LED_CFG 0x1b07 +#define RTL8367C_DUMMY_1b07a_OFFSET 8 +#define RTL8367C_DUMMY_1b07a_MASK 0xFF00 +#define RTL8367C_LED_FORCE_MODE_OFFSET 2 +#define RTL8367C_LED_FORCE_MODE_MASK 0xFC +#define RTL8367C_FORCE_MODE_OFFSET 0 +#define RTL8367C_FORCE_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED0_CFG0 0x1b08 +#define RTL8367C_PORT7_LED0_MODE_OFFSET 14 +#define RTL8367C_PORT7_LED0_MODE_MASK 0xC000 +#define RTL8367C_PORT6_LED0_MODE_OFFSET 12 +#define RTL8367C_PORT6_LED0_MODE_MASK 0x3000 +#define RTL8367C_PORT5_LED0_MODE_OFFSET 10 +#define RTL8367C_PORT5_LED0_MODE_MASK 0xC00 +#define RTL8367C_PORT4_LED0_MODE_OFFSET 8 +#define RTL8367C_PORT4_LED0_MODE_MASK 0x300 +#define RTL8367C_PORT3_LED0_MODE_OFFSET 6 +#define RTL8367C_PORT3_LED0_MODE_MASK 0xC0 +#define RTL8367C_PORT2_LED0_MODE_OFFSET 4 +#define RTL8367C_PORT2_LED0_MODE_MASK 0x30 +#define RTL8367C_PORT1_LED0_MODE_OFFSET 2 +#define RTL8367C_PORT1_LED0_MODE_MASK 0xC +#define RTL8367C_PORT0_LED0_MODE_OFFSET 0 +#define RTL8367C_PORT0_LED0_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED0_CFG1 0x1b09 +#define RTL8367C_DUMMY_1b09a_OFFSET 4 +#define RTL8367C_DUMMY_1b09a_MASK 0xFFF0 +#define RTL8367C_PORT9_LED0_MODE_OFFSET 2 +#define RTL8367C_PORT9_LED0_MODE_MASK 0xC +#define RTL8367C_PORT8_LED0_MODE_OFFSET 0 +#define RTL8367C_PORT8_LED0_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED1_CFG0 0x1b0a +#define RTL8367C_PORT7_LED1_MODE_OFFSET 14 +#define RTL8367C_PORT7_LED1_MODE_MASK 0xC000 +#define RTL8367C_PORT6_LED1_MODE_OFFSET 12 +#define RTL8367C_PORT6_LED1_MODE_MASK 0x3000 +#define RTL8367C_PORT5_LED1_MODE_OFFSET 10 +#define RTL8367C_PORT5_LED1_MODE_MASK 0xC00 +#define RTL8367C_PORT4_LED1_MODE_OFFSET 8 +#define RTL8367C_PORT4_LED1_MODE_MASK 0x300 +#define RTL8367C_PORT3_LED1_MODE_OFFSET 6 +#define RTL8367C_PORT3_LED1_MODE_MASK 0xC0 +#define RTL8367C_PORT2_LED1_MODE_OFFSET 4 +#define RTL8367C_PORT2_LED1_MODE_MASK 0x30 +#define RTL8367C_PORT1_LED1_MODE_OFFSET 2 +#define RTL8367C_PORT1_LED1_MODE_MASK 0xC +#define RTL8367C_PORT0_LED1_MODE_OFFSET 0 +#define RTL8367C_PORT0_LED1_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED1_CFG1 0x1b0b +#define RTL8367C_DUMMY_1b0ba_OFFSET 4 +#define RTL8367C_DUMMY_1b0ba_MASK 0xFFF0 +#define RTL8367C_PORT9_LED1_MODE_OFFSET 2 +#define RTL8367C_PORT9_LED1_MODE_MASK 0xC +#define RTL8367C_PORT8_LED1_MODE_OFFSET 0 +#define RTL8367C_PORT8_LED1_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED2_CFG0 0x1b0c +#define RTL8367C_PORT7_LED2_MODE_OFFSET 14 +#define RTL8367C_PORT7_LED2_MODE_MASK 0xC000 +#define RTL8367C_PORT6_LED2_MODE_OFFSET 12 +#define RTL8367C_PORT6_LED2_MODE_MASK 0x3000 +#define RTL8367C_PORT5_LED2_MODE_OFFSET 10 +#define RTL8367C_PORT5_LED2_MODE_MASK 0xC00 +#define RTL8367C_PORT4_LED2_MODE_OFFSET 8 +#define RTL8367C_PORT4_LED2_MODE_MASK 0x300 +#define RTL8367C_PORT3_LED2_MODE_OFFSET 6 +#define RTL8367C_PORT3_LED2_MODE_MASK 0xC0 +#define RTL8367C_PORT2_LED2_MODE_OFFSET 4 +#define RTL8367C_PORT2_LED2_MODE_MASK 0x30 +#define RTL8367C_PORT1_LED2_MODE_OFFSET 2 +#define RTL8367C_PORT1_LED2_MODE_MASK 0xC +#define RTL8367C_PORT0_LED2_MODE_OFFSET 0 +#define RTL8367C_PORT0_LED2_MODE_MASK 0x3 + +#define RTL8367C_REG_CPU_FORCE_LED2_CFG1 0x1b0d +#define RTL8367C_DUMMY_1b0da_OFFSET 4 +#define RTL8367C_DUMMY_1b0da_MASK 0xFFF0 +#define RTL8367C_PORT9_LED2_MODE_OFFSET 2 +#define RTL8367C_PORT9_LED2_MODE_MASK 0xC +#define RTL8367C_PORT8_LED2_MODE_OFFSET 0 +#define RTL8367C_PORT8_LED2_MODE_MASK 0x3 + +#define RTL8367C_REG_LED_ACTIVE_LOW_CFG0 0x1b0e +#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_OFFSET 15 +#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_15_MASK 0x8000 +#define RTL8367C_PORT3_LED_ACTIVE_LOW_OFFSET 12 +#define RTL8367C_PORT3_LED_ACTIVE_LOW_MASK 0x7000 +#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_OFFSET 11 +#define RTL8367C_LED_ACTIVE_LOW_CFG0_DUMMY_11_MASK 0x800 +#define RTL8367C_PORT2_LED_ACTIVE_LOW_OFFSET 8 +#define RTL8367C_PORT2_LED_ACTIVE_LOW_MASK 0x700 +#define RTL8367C_DUMMY_7_OFFSET 7 +#define RTL8367C_DUMMY_7_MASK 0x80 +#define RTL8367C_PORT1_LED_ACTIVE_LOW_OFFSET 4 +#define RTL8367C_PORT1_LED_ACTIVE_LOW_MASK 0x70 +#define RTL8367C_DUMMY_3_OFFSET 3 +#define RTL8367C_DUMMY_3_MASK 0x8 +#define RTL8367C_PORT0_LED_ACTIVE_LOW_OFFSET 0 +#define RTL8367C_PORT0_LED_ACTIVE_LOW_MASK 0x7 + +#define RTL8367C_REG_LED_ACTIVE_LOW_CFG1 0x1b0f +#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_OFFSET 15 +#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_15_MASK 0x8000 +#define RTL8367C_PORT7_LED_ACTIVE_LOW_OFFSET 12 +#define RTL8367C_PORT7_LED_ACTIVE_LOW_MASK 0x7000 +#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_OFFSET 11 +#define RTL8367C_LED_ACTIVE_LOW_CFG1_DUMMY_11_MASK 0x800 +#define RTL8367C_PORT6_LED_ACTIVE_LOW_OFFSET 8 +#define RTL8367C_PORT6_LED_ACTIVE_LOW_MASK 0x700 +#define RTL8367C_DUMMY_1b0f_b_OFFSET 7 +#define RTL8367C_DUMMY_1b0f_b_MASK 0x80 +#define RTL8367C_PORT5_LED_ACTIVE_LOW_OFFSET 4 +#define RTL8367C_PORT5_LED_ACTIVE_LOW_MASK 0x70 +#define RTL8367C_DUMMY_1b0f_a_OFFSET 3 +#define RTL8367C_DUMMY_1b0f_a_MASK 0x8 +#define RTL8367C_PORT4_LED_ACTIVE_LOW_OFFSET 0 +#define RTL8367C_PORT4_LED_ACTIVE_LOW_MASK 0x7 + +#define RTL8367C_REG_LED_ACTIVE_LOW_CFG2 0x1b10 +#define RTL8367C_DUMMY_1b10_b_OFFSET 7 +#define RTL8367C_DUMMY_1b10_b_MASK 0xFF80 +#define RTL8367C_PORT9_LED_ACTIVE_LOW_OFFSET 4 +#define RTL8367C_PORT9_LED_ACTIVE_LOW_MASK 0x70 +#define RTL8367C_DUMMY_1b10_a_OFFSET 3 +#define RTL8367C_DUMMY_1b10_a_MASK 0x8 +#define RTL8367C_PORT8_LED_ACTIVE_LOW_OFFSET 0 +#define RTL8367C_PORT8_LED_ACTIVE_LOW_MASK 0x7 + +#define RTL8367C_REG_SEL_RTCT_PARA 0x1b21 +#define RTL8367C_DO_RTCT_COMMAND_OFFSET 15 +#define RTL8367C_DO_RTCT_COMMAND_MASK 0x8000 +#define RTL8367C_SEL_RTCT_PARA_DUMMY_OFFSET 12 +#define RTL8367C_SEL_RTCT_PARA_DUMMY_MASK 0x7000 +#define RTL8367C_SEL_RTCT_RLSTLED_TIME_OFFSET 10 +#define RTL8367C_SEL_RTCT_RLSTLED_TIME_MASK 0xC00 +#define RTL8367C_SEL_RTCT_TEST_LED_TIME_OFFSET 8 +#define RTL8367C_SEL_RTCT_TEST_LED_TIME_MASK 0x300 +#define RTL8367C_EN_SCAN_RTCT_OFFSET 7 +#define RTL8367C_EN_SCAN_RTCT_MASK 0x80 +#define RTL8367C_EN_RTCT_TIMOUT_OFFSET 6 +#define RTL8367C_EN_RTCT_TIMOUT_MASK 0x40 +#define RTL8367C_EN_ALL_RTCT_OFFSET 5 +#define RTL8367C_EN_ALL_RTCT_MASK 0x20 +#define RTL8367C_SEL_RTCT_PLE_WID_OFFSET 0 +#define RTL8367C_SEL_RTCT_PLE_WID_MASK 0x1F + +#define RTL8367C_REG_RTCT_ENABLE 0x1b22 +#define RTL8367C_RTCT_ENABLE_DUMMY_OFFSET 8 +#define RTL8367C_RTCT_ENABLE_DUMMY_MASK 0xFF00 +#define RTL8367C_RTCT_ENABLE_PORT_MASK_OFFSET 0 +#define RTL8367C_RTCT_ENABLE_PORT_MASK_MASK 0xFF + +#define RTL8367C_REG_RTCT_TIMEOUT 0x1b23 + +#define RTL8367C_REG_PARA_LED_IO_EN1 0x1b24 +#define RTL8367C_LED1_PARA_P07_00_OFFSET 8 +#define RTL8367C_LED1_PARA_P07_00_MASK 0xFF00 +#define RTL8367C_LED0_PARA_P07_00_OFFSET 0 +#define RTL8367C_LED0_PARA_P07_00_MASK 0xFF + +#define RTL8367C_REG_PARA_LED_IO_EN2 0x1b25 +#define RTL8367C_DUMMY_15_8_OFFSET 8 +#define RTL8367C_DUMMY_15_8_MASK 0xFF00 +#define RTL8367C_LED2_PARA_P07_00_OFFSET 0 +#define RTL8367C_LED2_PARA_P07_00_MASK 0xFF + +#define RTL8367C_REG_SCAN0_LED_IO_EN1 0x1b26 +#define RTL8367C_SCAN0_LED_IO_EN1_DUMMY_OFFSET 3 +#define RTL8367C_SCAN0_LED_IO_EN1_DUMMY_MASK 0xFFF8 +#define RTL8367C_LED_LOOP_DET_BUZZER_EN_OFFSET 2 +#define RTL8367C_LED_LOOP_DET_BUZZER_EN_MASK 0x4 +#define RTL8367C_LED_SERI_DATA_EN_OFFSET 1 +#define RTL8367C_LED_SERI_DATA_EN_MASK 0x2 +#define RTL8367C_LED_SERI_CLK_EN_OFFSET 0 +#define RTL8367C_LED_SERI_CLK_EN_MASK 0x1 + +#define RTL8367C_REG_SCAN1_LED_IO_EN2 0x1b27 +#define RTL8367C_LED_SCAN1_BI_PORT_EN_OFFSET 8 +#define RTL8367C_LED_SCAN1_BI_PORT_EN_MASK 0xFF00 +#define RTL8367C_LED_SCAN1_BI_STA_EN_OFFSET 7 +#define RTL8367C_LED_SCAN1_BI_STA_EN_MASK 0x80 +#define RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_OFFSET 6 +#define RTL8367C_SCAN1_LED_IO_EN2_DUMMY_0_MASK 0x40 +#define RTL8367C_LED_SCAN1_SI_PORT_EN_OFFSET 2 +#define RTL8367C_LED_SCAN1_SI_PORT_EN_MASK 0x3C +#define RTL8367C_LED_SCAN1_SI_STA_EN_OFFSET 0 +#define RTL8367C_LED_SCAN1_SI_STA_EN_MASK 0x3 + +#define RTL8367C_REG_LPI_LED_OPT1 0x1b28 +#define RTL8367C_LPI_TAG4_OFFSET 12 +#define RTL8367C_LPI_TAG4_MASK 0xF000 +#define RTL8367C_LPI_TAG3_OFFSET 8 +#define RTL8367C_LPI_TAG3_MASK 0xF00 +#define RTL8367C_LPI_TAG2_OFFSET 4 +#define RTL8367C_LPI_TAG2_MASK 0xF0 +#define RTL8367C_LPI_TAG1_OFFSET 0 +#define RTL8367C_LPI_TAG1_MASK 0xF + +#define RTL8367C_REG_LPI_LED_OPT2 0x1b29 +#define RTL8367C_LPI_LED_OPT2_DUMMY_OFFSET 15 +#define RTL8367C_LPI_LED_OPT2_DUMMY_MASK 0x8000 +#define RTL8367C_LPI_LED2_WEAK_OFFSET 14 +#define RTL8367C_LPI_LED2_WEAK_MASK 0x4000 +#define RTL8367C_LPI_LED1_WEAK_OFFSET 13 +#define RTL8367C_LPI_LED1_WEAK_MASK 0x2000 +#define RTL8367C_LPI_LED0_WEAK_OFFSET 12 +#define RTL8367C_LPI_LED0_WEAK_MASK 0x1000 +#define RTL8367C_LPI_LED2_OFFSET 11 +#define RTL8367C_LPI_LED2_MASK 0x800 +#define RTL8367C_LPI_LED1_OFFSET 10 +#define RTL8367C_LPI_LED1_MASK 0x400 +#define RTL8367C_LPI_LED0_OFFSET 9 +#define RTL8367C_LPI_LED0_MASK 0x200 +#define RTL8367C_LPI_TAG8_OFFSET 8 +#define RTL8367C_LPI_TAG8_MASK 0x100 +#define RTL8367C_LPI_TAG7_OFFSET 6 +#define RTL8367C_LPI_TAG7_MASK 0xC0 +#define RTL8367C_LPI_TAG6_OFFSET 4 +#define RTL8367C_LPI_TAG6_MASK 0x30 +#define RTL8367C_LPI_TAG5_OFFSET 0 +#define RTL8367C_LPI_TAG5_MASK 0xF + +#define RTL8367C_REG_LPI_LED_OPT3 0x1b2a +#define RTL8367C_LPI_LED_OPT3_DUMMY_OFFSET 3 +#define RTL8367C_LPI_LED_OPT3_DUMMY_MASK 0xFFF8 +#define RTL8367C_RESTORE_LED_RATE_SEL_OFFSET 1 +#define RTL8367C_RESTORE_LED_RATE_SEL_MASK 0x6 +#define RTL8367C_RESTORE_LED_SEL_OFFSET 0 +#define RTL8367C_RESTORE_LED_SEL_MASK 0x1 + +#define RTL8367C_REG_P0_LED_MUX 0x1b2b +#define RTL8367C_CFG_P0_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P0_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P0_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P0_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P0_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P0_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P1_LED_MUX 0x1b2c +#define RTL8367C_CFG_P1_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P1_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P1_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P1_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P1_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P1_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P2_LED_MUX 0x1b2d +#define RTL8367C_CFG_P2_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P2_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P2_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P2_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P2_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P2_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P3_LED_MUX 0x1b2e +#define RTL8367C_CFG_P3_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P3_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P3_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P3_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P3_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P3_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P4_LED_MUX 0x1b2f +#define RTL8367C_CFG_P4_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P4_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P4_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P4_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P4_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P4_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_LED0_DATA_CTRL 0x1b30 +#define RTL8367C_CFG_DATA_LED0_SEL_OFFSET 6 +#define RTL8367C_CFG_DATA_LED0_SEL_MASK 0x40 +#define RTL8367C_CFG_DATA_LED0_ACT_OFFSET 4 +#define RTL8367C_CFG_DATA_LED0_ACT_MASK 0x30 +#define RTL8367C_CFG_DATA_LED0_SPD_OFFSET 0 +#define RTL8367C_CFG_DATA_LED0_SPD_MASK 0xF + +#define RTL8367C_REG_LED1_DATA_CTRL 0x1b31 +#define RTL8367C_CFG_DATA_LED1_SEL_OFFSET 6 +#define RTL8367C_CFG_DATA_LED1_SEL_MASK 0x40 +#define RTL8367C_CFG_DATA_LED1_ACT_OFFSET 4 +#define RTL8367C_CFG_DATA_LED1_ACT_MASK 0x30 +#define RTL8367C_CFG_DATA_LED1_SPD_OFFSET 0 +#define RTL8367C_CFG_DATA_LED1_SPD_MASK 0xF + +#define RTL8367C_REG_LED2_DATA_CTRL 0x1b32 +#define RTL8367C_CFG_DATA_LED2_SEL_OFFSET 6 +#define RTL8367C_CFG_DATA_LED2_SEL_MASK 0x40 +#define RTL8367C_CFG_DATA_LED2_ACT_OFFSET 4 +#define RTL8367C_CFG_DATA_LED2_ACT_MASK 0x30 +#define RTL8367C_CFG_DATA_LED2_SPD_OFFSET 0 +#define RTL8367C_CFG_DATA_LED2_SPD_MASK 0xF + +#define RTL8367C_REG_PARA_LED_IO_EN3 0x1b33 +#define RTL8367C_dummy_1b33a_OFFSET 6 +#define RTL8367C_dummy_1b33a_MASK 0xFFC0 +#define RTL8367C_LED2_PARA_P09_08_OFFSET 4 +#define RTL8367C_LED2_PARA_P09_08_MASK 0x30 +#define RTL8367C_LED1_PARA_P09_08_OFFSET 2 +#define RTL8367C_LED1_PARA_P09_08_MASK 0xC +#define RTL8367C_LED0_PARA_P09_08_OFFSET 0 +#define RTL8367C_LED0_PARA_P09_08_MASK 0x3 + +#define RTL8367C_REG_SCAN1_LED_IO_EN3 0x1b34 +#define RTL8367C_dummy_1b34a_OFFSET 3 +#define RTL8367C_dummy_1b34a_MASK 0xFFF8 +#define RTL8367C_LED_SCAN1_BI_PORT9_8_EN_OFFSET 1 +#define RTL8367C_LED_SCAN1_BI_PORT9_8_EN_MASK 0x6 +#define RTL8367C_LED_SCAN1_SI_PORT9_8_EN_OFFSET 0 +#define RTL8367C_LED_SCAN1_SI_PORT9_8_EN_MASK 0x1 + +#define RTL8367C_REG_P5_LED_MUX 0x1b35 +#define RTL8367C_CFG_P5_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P5_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P5_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P5_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P5_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P5_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P6_LED_MUX 0x1b36 +#define RTL8367C_CFG_P6_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P6_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P6_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P6_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P6_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P6_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P7_LED_MUX 0x1b37 +#define RTL8367C_CFG_P7_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P7_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P7_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P7_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P7_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P7_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P8_LED_MUX 0x1b38 +#define RTL8367C_CFG_P8_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P8_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P8_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P8_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P8_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P8_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_P9_LED_MUX 0x1b39 +#define RTL8367C_CFG_P9_LED2_MUX_OFFSET 10 +#define RTL8367C_CFG_P9_LED2_MUX_MASK 0x7C00 +#define RTL8367C_CFG_P9_LED1_MUX_OFFSET 5 +#define RTL8367C_CFG_P9_LED1_MUX_MASK 0x3E0 +#define RTL8367C_CFG_P9_LED0_MUX_OFFSET 0 +#define RTL8367C_CFG_P9_LED0_MUX_MASK 0x1F + +#define RTL8367C_REG_SERIAL_LED_CTRL 0x1b3a +#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_OFFSET 13 +#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_MASK 0x6000 +#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_OFFSET 12 +#define RTL8367C_SERIAL_LED_SHIFT_SEQUENCE_EN_MASK 0x1000 +#define RTL8367C_SERIAL_LED_GROUP_NUM_OFFSET 10 +#define RTL8367C_SERIAL_LED_GROUP_NUM_MASK 0xC00 +#define RTL8367C_SERIAL_LED_PORT_EN_OFFSET 0 +#define RTL8367C_SERIAL_LED_PORT_EN_MASK 0x3FF + +/* (16'h1c00)IGMP_EAV */ + +#define RTL8367C_REG_IGMP_MLD_CFG0 0x1c00 +#define RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET 15 +#define RTL8367C_IGMP_MLD_PORTISO_LEAKY_MASK 0x8000 +#define RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET 14 +#define RTL8367C_IGMP_MLD_VLAN_LEAKY_MASK 0x4000 +#define RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET 13 +#define RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_MASK 0x2000 +#define RTL8367C_REPORT_FORWARD_OFFSET 12 +#define RTL8367C_REPORT_FORWARD_MASK 0x1000 +#define RTL8367C_ROBUSTNESS_VAR_OFFSET 9 +#define RTL8367C_ROBUSTNESS_VAR_MASK 0xE00 +#define RTL8367C_LEAVE_SUPPRESSION_OFFSET 8 +#define RTL8367C_LEAVE_SUPPRESSION_MASK 0x100 +#define RTL8367C_REPORT_SUPPRESSION_OFFSET 7 +#define RTL8367C_REPORT_SUPPRESSION_MASK 0x80 +#define RTL8367C_LEAVE_TIMER_OFFSET 4 +#define RTL8367C_LEAVE_TIMER_MASK 0x70 +#define RTL8367C_FAST_LEAVE_EN_OFFSET 3 +#define RTL8367C_FAST_LEAVE_EN_MASK 0x8 +#define RTL8367C_CKS_ERR_OP_OFFSET 1 +#define RTL8367C_CKS_ERR_OP_MASK 0x6 +#define RTL8367C_IGMP_MLD_EN_OFFSET 0 +#define RTL8367C_IGMP_MLD_EN_MASK 0x1 + +#define RTL8367C_REG_IGMP_MLD_CFG1 0x1c01 +#define RTL8367C_DROP_LEAVE_ZERO_OFFSET 2 +#define RTL8367C_DROP_LEAVE_ZERO_MASK 0x4 +#define RTL8367C_TABLE_FULL_OP_OFFSET 0 +#define RTL8367C_TABLE_FULL_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_MLD_CFG2 0x1c02 + +#define RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT 0x1c03 +#define RTL8367C_D_ROUTER_PORT_2_OFFSET 11 +#define RTL8367C_D_ROUTER_PORT_2_MASK 0x7800 +#define RTL8367C_D_ROUTER_PORT_TMR_2_OFFSET 8 +#define RTL8367C_D_ROUTER_PORT_TMR_2_MASK 0x700 +#define RTL8367C_D_ROUTER_PORT_1_OFFSET 3 +#define RTL8367C_D_ROUTER_PORT_1_MASK 0x78 +#define RTL8367C_D_ROUTER_PORT_TMR_1_OFFSET 0 +#define RTL8367C_D_ROUTER_PORT_TMR_1_MASK 0x7 + +#define RTL8367C_REG_IGMP_STATIC_ROUTER_PORT 0x1c04 +#define RTL8367C_IGMP_STATIC_ROUTER_PORT_OFFSET 0 +#define RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK 0x7FF + +#define RTL8367C_REG_IGMP_PORT0_CONTROL 0x1c05 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT1_CONTROL 0x1c06 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT1_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT1_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT1_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT1_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT2_CONTROL 0x1c07 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT2_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT2_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT2_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT2_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT3_CONTROL 0x1c08 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT3_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT3_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT3_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT3_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT4_CONTROL 0x1c09 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT4_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT4_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT4_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT4_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT5_CONTROL 0x1c0a +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT5_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT5_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT5_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT5_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT6_CONTROL 0x1c0b +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT6_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT6_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT6_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT6_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT7_CONTROL 0x1c0c +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT7_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT7_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT7_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT7_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT01_MAX_GROUP 0x1c0d +#define RTL8367C_PORT1_MAX_GROUP_OFFSET 8 +#define RTL8367C_PORT1_MAX_GROUP_MASK 0xFF00 +#define RTL8367C_PORT0_MAX_GROUP_OFFSET 0 +#define RTL8367C_PORT0_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT23_MAX_GROUP 0x1c0e +#define RTL8367C_PORT3_MAX_GROUP_OFFSET 8 +#define RTL8367C_PORT3_MAX_GROUP_MASK 0xFF00 +#define RTL8367C_PORT2_MAX_GROUP_OFFSET 0 +#define RTL8367C_PORT2_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT45_MAX_GROUP 0x1c0f +#define RTL8367C_PORT5_MAX_GROUP_OFFSET 8 +#define RTL8367C_PORT5_MAX_GROUP_MASK 0xFF00 +#define RTL8367C_PORT4_MAX_GROUP_OFFSET 0 +#define RTL8367C_PORT4_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT67_MAX_GROUP 0x1c10 +#define RTL8367C_PORT7_MAX_GROUP_OFFSET 8 +#define RTL8367C_PORT7_MAX_GROUP_MASK 0xFF00 +#define RTL8367C_PORT6_MAX_GROUP_OFFSET 0 +#define RTL8367C_PORT6_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP 0x1c11 +#define RTL8367C_PORT1_CURRENT_GROUP_OFFSET 8 +#define RTL8367C_PORT1_CURRENT_GROUP_MASK 0xFF00 +#define RTL8367C_PORT0_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_PORT0_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT23_CURRENT_GROUP 0x1c12 +#define RTL8367C_PORT3_CURRENT_GROUP_OFFSET 8 +#define RTL8367C_PORT3_CURRENT_GROUP_MASK 0xFF00 +#define RTL8367C_PORT2_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_PORT2_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT45_CURRENT_GROUP 0x1c13 +#define RTL8367C_PORT5_CURRENT_GROUP_OFFSET 8 +#define RTL8367C_PORT5_CURRENT_GROUP_MASK 0xFF00 +#define RTL8367C_PORT4_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_PORT4_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT67_CURRENT_GROUP 0x1c14 +#define RTL8367C_PORT7_CURRENT_GROUP_OFFSET 8 +#define RTL8367C_PORT7_CURRENT_GROUP_MASK 0xFF00 +#define RTL8367C_PORT6_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_PORT6_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_MLD_CFG3 0x1c15 +#define RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET 5 +#define RTL8367C_IGMP_MLD_IP6_BYPASS_MASK 0x20 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET 4 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_MASK 0x10 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET 3 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_MASK 0x8 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET 2 +#define RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_MASK 0x4 +#define RTL8367C_REPORT_LEAVE_FORWARD_OFFSET 0 +#define RTL8367C_REPORT_LEAVE_FORWARD_MASK 0x3 + +#define RTL8367C_REG_IGMP_MLD_CFG4 0x1c16 +#define RTL8367C_IGMP_MLD_CFG4_OFFSET 0 +#define RTL8367C_IGMP_MLD_CFG4_MASK 0x7FF + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST0 0x1c20 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST1 0x1c21 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST2 0x1c22 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST3 0x1c23 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST4 0x1c24 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST5 0x1c25 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST6 0x1c26 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST7 0x1c27 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST8 0x1c28 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST9 0x1c29 + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST10 0x1c2a + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST11 0x1c2b + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST12 0x1c2c + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST13 0x1c2d + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST14 0x1c2e + +#define RTL8367C_REG_IGMP_GROUP_USAGE_LIST15 0x1c2f + +#define RTL8367C_REG_EAV_CTRL0 0x1c30 +#define RTL8367C_EAV_CTRL0_OFFSET 0 +#define RTL8367C_EAV_CTRL0_MASK 0xFF + +#define RTL8367C_REG_EAV_CTRL1 0x1c31 +#define RTL8367C_REMAP_EAV_PRI3_REGEN_OFFSET 9 +#define RTL8367C_REMAP_EAV_PRI3_REGEN_MASK 0xE00 +#define RTL8367C_REMAP_EAV_PRI2_REGEN_OFFSET 6 +#define RTL8367C_REMAP_EAV_PRI2_REGEN_MASK 0x1C0 +#define RTL8367C_REMAP_EAV_PRI1_REGEN_OFFSET 3 +#define RTL8367C_REMAP_EAV_PRI1_REGEN_MASK 0x38 +#define RTL8367C_REMAP_EAV_PRI0_REGEN_OFFSET 0 +#define RTL8367C_REMAP_EAV_PRI0_REGEN_MASK 0x7 + +#define RTL8367C_REG_EAV_CTRL2 0x1c32 +#define RTL8367C_REMAP_EAV_PRI7_REGEN_OFFSET 9 +#define RTL8367C_REMAP_EAV_PRI7_REGEN_MASK 0xE00 +#define RTL8367C_REMAP_EAV_PRI6_REGEN_OFFSET 6 +#define RTL8367C_REMAP_EAV_PRI6_REGEN_MASK 0x1C0 +#define RTL8367C_REMAP_EAV_PRI5_REGEN_OFFSET 3 +#define RTL8367C_REMAP_EAV_PRI5_REGEN_MASK 0x38 +#define RTL8367C_REMAP_EAV_PRI4_REGEN_OFFSET 0 +#define RTL8367C_REMAP_EAV_PRI4_REGEN_MASK 0x7 + +#define RTL8367C_REG_SYS_TIME_FREQ 0x1c43 + +#define RTL8367C_REG_SYS_TIME_OFFSET_L 0x1c44 + +#define RTL8367C_REG_SYS_TIME_OFFSET_H 0x1c45 + +#define RTL8367C_REG_SYS_TIME_OFFSET_512NS_L 0x1c46 + +#define RTL8367C_REG_SYS_TIME_OFFSET_512NS_H 0x1c47 +#define RTL8367C_SYS_TIME_OFFSET_TUNE_OFFSET 5 +#define RTL8367C_SYS_TIME_OFFSET_TUNE_MASK 0x20 +#define RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_OFFSET 0 +#define RTL8367C_SYS_TIME_OFFSET_512NS_H_SYS_TIME_OFFSET_512NS_MASK 0x1F + +#define RTL8367C_REG_SYS_TIME_SEC_TRANSIT 0x1c48 +#define RTL8367C_SYS_TIME_SEC_TRANSIT_OFFSET 0 +#define RTL8367C_SYS_TIME_SEC_TRANSIT_MASK 0x1 + +#define RTL8367C_REG_SYS_TIME_SEC_HIGH_L 0x1c49 + +#define RTL8367C_REG_SYS_TIME_SEC_HIGH_H 0x1c4a + +#define RTL8367C_REG_SYS_TIME_512NS_L 0x1c4b + +#define RTL8367C_REG_SYS_TIME_512NS_H 0x1c4c +#define RTL8367C_SYS_TIME_512NS_H_OFFSET 0 +#define RTL8367C_SYS_TIME_512NS_H_MASK 0x1F + +#define RTL8367C_REG_FALLBACK_CTRL 0x1c70 +#define RTL8367C_FALLBACK_PL_DEC_EN_OFFSET 15 +#define RTL8367C_FALLBACK_PL_DEC_EN_MASK 0x8000 +#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_OFFSET 14 +#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_IGNORE_MASK 0x4000 +#define RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_OFFSET 11 +#define RTL8367C_FALLBACK_ERROR_RATIO_THRESHOLD_MASK 0x3800 +#define RTL8367C_FALLBACK_MONITORMAX_OFFSET 8 +#define RTL8367C_FALLBACK_MONITORMAX_MASK 0x700 +#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_OFFSET 0 +#define RTL8367C_FALLBACK_MONITOR_TIMEOUT_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT0_CFG0 0x1c71 +#define RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT0_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT0_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT0_CFG1 0x1c72 + +#define RTL8367C_REG_FALLBACK_PORT0_CFG2 0x1c73 +#define RTL8367C_FALLBACK_PORT0_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT0_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT0_CFG3 0x1c74 +#define RTL8367C_FALLBACK_PORT0_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT0_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT1_CFG0 0x1c75 +#define RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT1_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT1_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT1_CFG1 0x1c76 + +#define RTL8367C_REG_FALLBACK_PORT1_CFG2 0x1c77 +#define RTL8367C_FALLBACK_PORT1_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT1_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT1_CFG3 0x1c78 +#define RTL8367C_FALLBACK_PORT1_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT1_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT2_CFG0 0x1c79 +#define RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT2_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT2_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT2_CFG1 0x1c7a + +#define RTL8367C_REG_FALLBACK_PORT2_CFG2 0x1c7b +#define RTL8367C_FALLBACK_PORT2_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT2_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT2_CFG3 0x1c7c +#define RTL8367C_FALLBACK_PORT2_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT2_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT3_CFG0 0x1c7d +#define RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT3_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT3_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT3_CFG1 0x1c7e + +#define RTL8367C_REG_FALLBACK_PORT3_CFG2 0x1c7f +#define RTL8367C_FALLBACK_PORT3_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT3_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT3_CFG3 0x1c80 +#define RTL8367C_FALLBACK_PORT3_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT3_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT4_CFG0 0x1c81 +#define RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT4_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT4_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT4_CFG1 0x1c82 + +#define RTL8367C_REG_FALLBACK_PORT4_CFG2 0x1c83 +#define RTL8367C_FALLBACK_PORT4_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT4_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT4_CFG3 0x1c84 +#define RTL8367C_FALLBACK_PORT4_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT4_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_CTRL1 0x1c85 +#define RTL8367C_FALLBACK_VALIDFLOW_OFFSET 8 +#define RTL8367C_FALLBACK_VALIDFLOW_MASK 0xFF00 +#define RTL8367C_FALLBACK_STOP_TMR_OFFSET 0 +#define RTL8367C_FALLBACK_STOP_TMR_MASK 0x1 + +#define RTL8367C_REG_FALLBACK_CPL 0x1c86 +#define RTL8367C_PORT4_CPL_OFFSET 4 +#define RTL8367C_PORT4_CPL_MASK 0x10 +#define RTL8367C_PORT3_CPL_OFFSET 3 +#define RTL8367C_PORT3_CPL_MASK 0x8 +#define RTL8367C_PORT2_CPL_OFFSET 2 +#define RTL8367C_PORT2_CPL_MASK 0x4 +#define RTL8367C_PORT1_CPL_OFFSET 1 +#define RTL8367C_PORT1_CPL_MASK 0x2 +#define RTL8367C_PORT0_CPL_OFFSET 0 +#define RTL8367C_PORT0_CPL_MASK 0x1 + +#define RTL8367C_REG_FALLBACK_PHY_PAGE 0x1c87 +#define RTL8367C_FALLBACK_PHY_PAGE_OFFSET 0 +#define RTL8367C_FALLBACK_PHY_PAGE_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PHY_REG 0x1c88 +#define RTL8367C_FALLBACK_PHY_REG_OFFSET 0 +#define RTL8367C_FALLBACK_PHY_REG_MASK 0x1F + +#define RTL8367C_REG_AFBK_INFO_X0 0x1c89 + +#define RTL8367C_REG_AFBK_INFO_X1 0x1c8a + +#define RTL8367C_REG_AFBK_INFO_X2 0x1c8b + +#define RTL8367C_REG_AFBK_INFO_X3 0x1c8c + +#define RTL8367C_REG_AFBK_INFO_X4 0x1c8d + +#define RTL8367C_REG_AFBK_INFO_X5 0x1c8e + +#define RTL8367C_REG_AFBK_INFO_X6 0x1c8f + +#define RTL8367C_REG_AFBK_INFO_X7 0x1c90 + +#define RTL8367C_REG_AFBK_INFO_X8 0x1c91 + +#define RTL8367C_REG_AFBK_INFO_X9 0x1c92 + +#define RTL8367C_REG_AFBK_INFO_X10 0x1c93 + +#define RTL8367C_REG_AFBK_INFO_X11 0x1c94 + +#define RTL8367C_REG_FALLBACK_PORT5_CFG0 0x1ca0 +#define RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT5_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT5_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT5_CFG1 0x1ca1 + +#define RTL8367C_REG_FALLBACK_PORT5_CFG2 0x1ca2 +#define RTL8367C_FALLBACK_PORT5_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT5_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT5_CFG3 0x1ca3 +#define RTL8367C_FALLBACK_PORT5_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT5_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT6_CFG0 0x1ca4 +#define RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT6_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT6_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT6_CFG1 0x1ca5 + +#define RTL8367C_REG_FALLBACK_PORT6_CFG2 0x1ca6 +#define RTL8367C_FALLBACK_PORT6_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT6_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT6_CFG3 0x1ca7 +#define RTL8367C_FALLBACK_PORT6_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT6_CFG3_MASK 0xFF + +#define RTL8367C_REG_FALLBACK_PORT7_CFG0 0x1ca8 +#define RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_OFFSET 15 +#define RTL8367C_FALLBACK_PORT7_CFG0_RESET_POWER_LEVEL_MASK 0x8000 +#define RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_OFFSET 14 +#define RTL8367C_FALLBACK_PORT7_CFG0_ENABLE_MASK 0x4000 + +#define RTL8367C_REG_FALLBACK_PORT7_CFG1 0x1ca9 + +#define RTL8367C_REG_FALLBACK_PORT7_CFG2 0x1caa +#define RTL8367C_FALLBACK_PORT7_CFG2_OFFSET 0 +#define RTL8367C_FALLBACK_PORT7_CFG2_MASK 0xFFF + +#define RTL8367C_REG_FALLBACK_PORT7_CFG3 0x1cab +#define RTL8367C_FALLBACK_PORT7_CFG3_OFFSET 0 +#define RTL8367C_FALLBACK_PORT7_CFG3_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT8_CONTROL 0x1cb0 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT8_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT8_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT8_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT8_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT9_CONTROL 0x1cb1 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT9_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT9_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT9_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT9_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT10_CONTROL 0x1cb2 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_OFFSET 14 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_QUERY_MASK 0x4000 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_OFFSET 13 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_REPORT_MASK 0x2000 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_OFFSET 12 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_LEAVE_MASK 0x1000 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_OFFSET 11 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MRP_MASK 0x800 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_OFFSET 10 +#define RTL8367C_IGMP_PORT10_CONTROL_ALLOW_MC_DATA_MASK 0x400 +#define RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_OFFSET 8 +#define RTL8367C_IGMP_PORT10_CONTROL_MLDv2_OP_MASK 0x300 +#define RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_OFFSET 6 +#define RTL8367C_IGMP_PORT10_CONTROL_MLDv1_OP_MASK 0xC0 +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_OFFSET 4 +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV3_OP_MASK 0x30 +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_OFFSET 2 +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV2_OP_MASK 0xC +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_OFFSET 0 +#define RTL8367C_IGMP_PORT10_CONTROL_IGMPV1_OP_MASK 0x3 + +#define RTL8367C_REG_IGMP_PORT89_MAX_GROUP 0x1cb3 +#define RTL8367C_PORT9_MAX_GROUP_OFFSET 8 +#define RTL8367C_PORT9_MAX_GROUP_MASK 0xFF00 +#define RTL8367C_PORT8_MAX_GROUP_OFFSET 0 +#define RTL8367C_PORT8_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT10_MAX_GROUP 0x1cb4 +#define RTL8367C_IGMP_PORT10_MAX_GROUP_OFFSET 0 +#define RTL8367C_IGMP_PORT10_MAX_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP 0x1cb5 +#define RTL8367C_PORT9_CURRENT_GROUP_OFFSET 8 +#define RTL8367C_PORT9_CURRENT_GROUP_MASK 0xFF00 +#define RTL8367C_PORT8_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_PORT8_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_PORT10_CURRENT_GROUP 0x1cb6 +#define RTL8367C_IGMP_PORT10_CURRENT_GROUP_OFFSET 0 +#define RTL8367C_IGMP_PORT10_CURRENT_GROUP_MASK 0xFF + +#define RTL8367C_REG_IGMP_L3_CHECKSUM_CHECK 0x1cb7 +#define RTL8367C_IGMP_L3_CHECKSUM_CHECK_OFFSET 0 +#define RTL8367C_IGMP_L3_CHECKSUM_CHECK_MASK 0x1 + +/* (16'h1d00)chip_70b_reg */ + +#define RTL8367C_REG_PCSXF_CFG 0x1d00 +#define RTL8367C_PCSXF_CFG_Reserved_OFFSET 15 +#define RTL8367C_PCSXF_CFG_Reserved_MASK 0x8000 +#define RTL8367C_CFG_RST_RXFIFO_P7_5_OFFSET 12 +#define RTL8367C_CFG_RST_RXFIFO_P7_5_MASK 0x7000 +#define RTL8367C_CFG_PCSXF_OFFSET 8 +#define RTL8367C_CFG_PCSXF_MASK 0xF00 +#define RTL8367C_CFG_RST_RXFIFO_OFFSET 3 +#define RTL8367C_CFG_RST_RXFIFO_MASK 0xF8 +#define RTL8367C_CFG_COL2RXDV_OFFSET 2 +#define RTL8367C_CFG_COL2RXDV_MASK 0x4 +#define RTL8367C_CFG_PHY_SDET_OFFSET 0 +#define RTL8367C_CFG_PHY_SDET_MASK 0x3 + +#define RTL8367C_REG_PHYID_CFG0 0x1d01 +#define RTL8367C_CFG_PHY_BRD_MODE_P7_5_OFFSET 11 +#define RTL8367C_CFG_PHY_BRD_MODE_P7_5_MASK 0x3800 +#define RTL8367C_CFG_PHYAD_14C_OFFSET 10 +#define RTL8367C_CFG_PHYAD_14C_MASK 0x400 +#define RTL8367C_CFG_PHY_BRD_MODE_OFFSET 5 +#define RTL8367C_CFG_PHY_BRD_MODE_MASK 0x3E0 +#define RTL8367C_CFG_BRD_PHYAD_OFFSET 0 +#define RTL8367C_CFG_BRD_PHYAD_MASK 0x1F + +#define RTL8367C_REG_PHYID_CFG1 0x1d02 +#define RTL8367C_CFG_MSK_MDI_OFFSET 5 +#define RTL8367C_CFG_MSK_MDI_MASK 0x1FE0 +#define RTL8367C_CFG_BASE_PHYAD_OFFSET 0 +#define RTL8367C_CFG_BASE_PHYAD_MASK 0x1F + +#define RTL8367C_REG_PHY_POLL_CFG0 0x1d03 +#define RTL8367C_CFG_HOTCMD_PRD_EN_OFFSET 15 +#define RTL8367C_CFG_HOTCMD_PRD_EN_MASK 0x8000 +#define RTL8367C_CFG_HOTCMD_EN_OFFSET 12 +#define RTL8367C_CFG_HOTCMD_EN_MASK 0x7000 +#define RTL8367C_CFG_POLL_PERIOD_OFFSET 8 +#define RTL8367C_CFG_POLL_PERIOD_MASK 0xF00 +#define RTL8367C_CFG_PERI_CMDS_RD_OFFSET 4 +#define RTL8367C_CFG_PERI_CMDS_RD_MASK 0xF0 +#define RTL8367C_CFG_PERI_CMDS_WR_OFFSET 0 +#define RTL8367C_CFG_PERI_CMDS_WR_MASK 0xF + +#define RTL8367C_REG_PHY_POLL_CFG1 0x1d04 + +#define RTL8367C_REG_PHY_POLL_CFG2 0x1d05 + +#define RTL8367C_REG_PHY_POLL_CFG3 0x1d06 + +#define RTL8367C_REG_PHY_POLL_CFG4 0x1d07 + +#define RTL8367C_REG_PHY_POLL_CFG5 0x1d08 + +#define RTL8367C_REG_PHY_POLL_CFG6 0x1d09 + +#define RTL8367C_REG_PHY_POLL_CFG7 0x1d0a + +#define RTL8367C_REG_PHY_POLL_CFG8 0x1d0b + +#define RTL8367C_REG_PHY_POLL_CFG9 0x1d0c + +#define RTL8367C_REG_PHY_POLL_CFG10 0x1d0d + +#define RTL8367C_REG_PHY_POLL_CFG11 0x1d0e + +#define RTL8367C_REG_PHY_POLL_CFG12 0x1d0f + +#define RTL8367C_REG_EFUSE_MISC 0x1d10 +#define RTL8367C_CFG_SA_SEL_OFFSET 5 +#define RTL8367C_CFG_SA_SEL_MASK 0x20 +#define RTL8367C_CFG_PHYAD00_OFFSET 0 +#define RTL8367C_CFG_PHYAD00_MASK 0x1F + +#define RTL8367C_REG_SDS_MISC 0x1d11 +#define RTL8367C_CFG_SGMII_RXFC_OFFSET 14 +#define RTL8367C_CFG_SGMII_RXFC_MASK 0x4000 +#define RTL8367C_CFG_SGMII_TXFC_OFFSET 13 +#define RTL8367C_CFG_SGMII_TXFC_MASK 0x2000 +#define RTL8367C_INB_ARB_OFFSET 12 +#define RTL8367C_INB_ARB_MASK 0x1000 +#define RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET 11 +#define RTL8367C_CFG_MAC8_SEL_HSGMII_MASK 0x800 +#define RTL8367C_CFG_SGMII_FDUP_OFFSET 10 +#define RTL8367C_CFG_SGMII_FDUP_MASK 0x400 +#define RTL8367C_CFG_SGMII_LINK_OFFSET 9 +#define RTL8367C_CFG_SGMII_LINK_MASK 0x200 +#define RTL8367C_CFG_SGMII_SPD_OFFSET 7 +#define RTL8367C_CFG_SGMII_SPD_MASK 0x180 +#define RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET 6 +#define RTL8367C_CFG_MAC8_SEL_SGMII_MASK 0x40 +#define RTL8367C_CFG_INB_SEL_OFFSET 3 +#define RTL8367C_CFG_INB_SEL_MASK 0x38 +#define RTL8367C_CFG_SDS_MODE_18C_OFFSET 0 +#define RTL8367C_CFG_SDS_MODE_18C_MASK 0x7 + +#define RTL8367C_REG_FIFO_CTRL 0x1d12 +#define RTL8367C_CFG_LINK_DOWN_CLR_FIFO_OFFSET 11 +#define RTL8367C_CFG_LINK_DOWN_CLR_FIFO_MASK 0x800 +#define RTL8367C_CFG_LPBK_OFFSET 10 +#define RTL8367C_CFG_LPBK_MASK 0x400 +#define RTL8367C_CFG_NOT_FF_OUT_OFFSET 9 +#define RTL8367C_CFG_NOT_FF_OUT_MASK 0x200 +#define RTL8367C_CFG_WATER_LEVEL_FD_OFFSET 6 +#define RTL8367C_CFG_WATER_LEVEL_FD_MASK 0x1C0 +#define RTL8367C_CFG_WATER_LEVEL_Y2X_OFFSET 3 +#define RTL8367C_CFG_WATER_LEVEL_Y2X_MASK 0x38 +#define RTL8367C_CFG_WATER_LEVEL_X2Y_OFFSET 0 +#define RTL8367C_CFG_WATER_LEVEL_X2Y_MASK 0x7 + +#define RTL8367C_REG_BCAM_SETTING 0x1d13 +#define RTL8367C_CFG_BCAM_MDS_OFFSET 3 +#define RTL8367C_CFG_BCAM_MDS_MASK 0x18 +#define RTL8367C_CFG_BCAM_RDS_OFFSET 0 +#define RTL8367C_CFG_BCAM_RDS_MASK 0x7 + +#define RTL8367C_REG_GPHY_ACS_MISC 0x1d14 +#define RTL8367C_CFG_SEL_GPHY_SMI_OFFSET 3 +#define RTL8367C_CFG_SEL_GPHY_SMI_MASK 0x8 +#define RTL8367C_CFG_BRD_PHYIDX_OFFSET 0 +#define RTL8367C_CFG_BRD_PHYIDX_MASK 0x7 + +#define RTL8367C_REG_GPHY_OCP_MSB_0 0x1d15 +#define RTL8367C_CFG_CPU_OCPADR_MSB_OFFSET 6 +#define RTL8367C_CFG_CPU_OCPADR_MSB_MASK 0xFC0 +#define RTL8367C_CFG_DW8051_OCPADR_MSB_OFFSET 0 +#define RTL8367C_CFG_DW8051_OCPADR_MSB_MASK 0x3F + +#define RTL8367C_REG_GPHY_OCP_MSB_1 0x1d16 +#define RTL8367C_CFG_PATCH_OCPADR_MSB_OFFSET 6 +#define RTL8367C_CFG_PATCH_OCPADR_MSB_MASK 0xFC0 +#define RTL8367C_CFG_PHYSTS_OCPADR_MSB_OFFSET 0 +#define RTL8367C_CFG_PHYSTS_OCPADR_MSB_MASK 0x3F + +#define RTL8367C_REG_GPHY_OCP_MSB_2 0x1d17 +#define RTL8367C_CFG_RRCP_OCPADR_MSB_OFFSET 6 +#define RTL8367C_CFG_RRCP_OCPADR_MSB_MASK 0xFC0 +#define RTL8367C_CFG_RTCT_OCPADR_MSB_OFFSET 0 +#define RTL8367C_CFG_RTCT_OCPADR_MSB_MASK 0x3F + +#define RTL8367C_REG_GPHY_OCP_MSB_3 0x1d18 +#define RTL8367C_GPHY_OCP_MSB_3_OFFSET 0 +#define RTL8367C_GPHY_OCP_MSB_3_MASK 0x3F + +#define RTL8367C_REG_GPIO_67C_I_X0 0x1d19 + +#define RTL8367C_REG_GPIO_67C_I_X1 0x1d1a + +#define RTL8367C_REG_GPIO_67C_I_X2 0x1d1b + +#define RTL8367C_REG_GPIO_67C_I_X3 0x1d1c +#define RTL8367C_GPIO_67C_I_X3_OFFSET 0 +#define RTL8367C_GPIO_67C_I_X3_MASK 0x3FFF + +#define RTL8367C_REG_GPIO_67C_O_X0 0x1d1d + +#define RTL8367C_REG_GPIO_67C_O_X1 0x1d1e + +#define RTL8367C_REG_GPIO_67C_O_X2 0x1d1f + +#define RTL8367C_REG_GPIO_67C_O_X3 0x1d20 +#define RTL8367C_GPIO_67C_O_X3_OFFSET 0 +#define RTL8367C_GPIO_67C_O_X3_MASK 0x3FFF + +#define RTL8367C_REG_GPIO_67C_OE_X0 0x1d21 + +#define RTL8367C_REG_GPIO_67C_OE_X1 0x1d22 + +#define RTL8367C_REG_GPIO_67C_OE_X2 0x1d23 + +#define RTL8367C_REG_GPIO_67C_OE_X3 0x1d24 +#define RTL8367C_GPIO_67C_OE_X3_OFFSET 0 +#define RTL8367C_GPIO_67C_OE_X3_MASK 0x3FFF + +#define RTL8367C_REG_GPIO_MODE_67C_X0 0x1d25 + +#define RTL8367C_REG_GPIO_MODE_67C_X1 0x1d26 + +#define RTL8367C_REG_GPIO_MODE_67C_X2 0x1d27 + +#define RTL8367C_REG_GPIO_MODE_67C_X3 0x1d28 +#define RTL8367C_GPIO_MODE_67C_X3_OFFSET 0 +#define RTL8367C_GPIO_MODE_67C_X3_MASK 0x3FFF + +#define RTL8367C_REG_WGPHY_MISC_0 0x1d29 +#define RTL8367C_CFG_INIPHY_DISGIGA_P7_5_OFFSET 13 +#define RTL8367C_CFG_INIPHY_DISGIGA_P7_5_MASK 0xE000 +#define RTL8367C_CFG_INIPHY_PWRUP_OFFSET 5 +#define RTL8367C_CFG_INIPHY_PWRUP_MASK 0x1FE0 +#define RTL8367C_CFG_INIPHY_DISGIGA_OFFSET 0 +#define RTL8367C_CFG_INIPHY_DISGIGA_MASK 0x1F + +#define RTL8367C_REG_WGPHY_MISC_1 0x1d2a +#define RTL8367C_WGPHY_MISC_1_OFFSET 0 +#define RTL8367C_WGPHY_MISC_1_MASK 0xFF + +#define RTL8367C_REG_WGPHY_MISC_2 0x1d2b +#define RTL8367C_WGPHY_MISC_2_OFFSET 0 +#define RTL8367C_WGPHY_MISC_2_MASK 0x3FF + +#define RTL8367C_REG_CFG_AFBK_GPHY_0 0x1d2c +#define RTL8367C_CFG_AFBK_GPHY_0_OFFSET 0 +#define RTL8367C_CFG_AFBK_GPHY_0_MASK 0x1F + +#define RTL8367C_REG_CFG_AFBK_GPHY_1 0x1d2d +#define RTL8367C_CFG_AFBK_GPHY_1_OFFSET 0 +#define RTL8367C_CFG_AFBK_GPHY_1_MASK 0xFFF + +#define RTL8367C_REG_EF_SLV_CTRL_0 0x1d2e +#define RTL8367C_EF_SLV_BUSY_OFFSET 11 +#define RTL8367C_EF_SLV_BUSY_MASK 0x800 +#define RTL8367C_EF_SLV_ACK_OFFSET 10 +#define RTL8367C_EF_SLV_ACK_MASK 0x400 +#define RTL8367C_EF_SLV_A_OFFSET 2 +#define RTL8367C_EF_SLV_A_MASK 0x3FC +#define RTL8367C_EF_SLV_WE_OFFSET 1 +#define RTL8367C_EF_SLV_WE_MASK 0x2 +#define RTL8367C_EF_SLV_CE_OFFSET 0 +#define RTL8367C_EF_SLV_CE_MASK 0x1 + +#define RTL8367C_REG_EF_SLV_CTRL_1 0x1d2f + +#define RTL8367C_REG_EF_SLV_CTRL_2 0x1d30 + +#define RTL8367C_REG_EFUSE_MISC_1 0x1d31 +#define RTL8367C_EF_EN_EFUSE_OFFSET 10 +#define RTL8367C_EF_EN_EFUSE_MASK 0x400 +#define RTL8367C_EF_MODEL_ID_OFFSET 6 +#define RTL8367C_EF_MODEL_ID_MASK 0x3C0 +#define RTL8367C_EF_RSVD_OFFSET 2 +#define RTL8367C_EF_RSVD_MASK 0x3C +#define RTL8367C_EF_SYS_CLK_OFFSET 0 +#define RTL8367C_EF_SYS_CLK_MASK 0x3 + +#define RTL8367C_REG_IO_MISC_FUNC 0x1d32 +#define RTL8367C_TST_MODE_OFFSET 3 +#define RTL8367C_TST_MODE_MASK 0x8 +#define RTL8367C_UART_EN_OFFSET 2 +#define RTL8367C_UART_EN_MASK 0x4 +#define RTL8367C_INT_EN_OFFSET 1 +#define RTL8367C_INT_EN_MASK 0x2 +#define RTL8367C_BUZ_EN_OFFSET 0 +#define RTL8367C_BUZ_EN_MASK 0x1 + +#define RTL8367C_REG_HTRAM_DVS 0x1d33 +#define RTL8367C_HTRAM_DVS_OFFSET 0 +#define RTL8367C_HTRAM_DVS_MASK 0x1 + +#define RTL8367C_REG_EF_SLV_CTRL_3 0x1d34 +#define RTL8367C_EF_SLV_CTRL_3_OFFSET 0 +#define RTL8367C_EF_SLV_CTRL_3_MASK 0x1 + +#define RTL8367C_REG_INBAND_EN14C 0x1d35 +#define RTL8367C_INBAND_EN14C_OFFSET 0 +#define RTL8367C_INBAND_EN14C_MASK 0x1 + +#define RTL8367C_REG_CFG_SWR_L 0x1d36 +#define RTL8367C_ANARG_RDY_SWR_L_OFFSET 14 +#define RTL8367C_ANARG_RDY_SWR_L_MASK 0x4000 +#define RTL8367C_ANARG_VALID_SWR_L_OFFSET 13 +#define RTL8367C_ANARG_VALID_SWR_L_MASK 0x2000 +#define RTL8367C_SAW_SWR_L_OFFSET 9 +#define RTL8367C_SAW_SWR_L_MASK 0x1E00 +#define RTL8367C_SAW_VALID_SWR_L_OFFSET 8 +#define RTL8367C_SAW_VALID_SWR_L_MASK 0x100 +#define RTL8367C_UPS_DBGO_L_OFFSET 0 +#define RTL8367C_UPS_DBGO_L_MASK 0xFF + +#define RTL8367C_REG_BTCAM_CTRL 0x1d37 +#define RTL8367C_TCAM_RDS_OFFSET 2 +#define RTL8367C_TCAM_RDS_MASK 0x1C +#define RTL8367C_TCAM_MDS_OFFSET 0 +#define RTL8367C_TCAM_MDS_MASK 0x3 + +#define RTL8367C_REG_PBRAM_BISR_CTRL 0x1d38 +#define RTL8367C_HAS_HLDRMP_MD_OFFSET 9 +#define RTL8367C_HAS_HLDRMP_MD_MASK 0x200 +#define RTL8367C_PB_HLDRMP_MD_OFFSET 8 +#define RTL8367C_PB_HLDRMP_MD_MASK 0x100 +#define RTL8367C_HAS_BISR_BIRSTN_OFFSET 7 +#define RTL8367C_HAS_BISR_BIRSTN_MASK 0x80 +#define RTL8367C_SEC_RUN_HSA_OFFSET 6 +#define RTL8367C_SEC_RUN_HSA_MASK 0x40 +#define RTL8367C_HAS_HLDRMP_VAL_OFFSET 5 +#define RTL8367C_HAS_HLDRMP_VAL_MASK 0x20 +#define RTL8367C_HAS_BISR_PWRSTN_OFFSET 4 +#define RTL8367C_HAS_BISR_PWRSTN_MASK 0x10 +#define RTL8367C_SEC_RUN_PB_OFFSET 3 +#define RTL8367C_SEC_RUN_PB_MASK 0x8 +#define RTL8367C_PB_HLDRMP_VAL_OFFSET 2 +#define RTL8367C_PB_HLDRMP_VAL_MASK 0x4 +#define RTL8367C_PB_BISR_BIRSTN_OFFSET 1 +#define RTL8367C_PB_BISR_BIRSTN_MASK 0x2 +#define RTL8367C_PB_BISR_PWRSTN_OFFSET 0 +#define RTL8367C_PB_BISR_PWRSTN_MASK 0x1 + +#define RTL8367C_REG_CVLANRAM_BISR_CTRL 0x1d39 +#define RTL8367C_SEC_RUN_CVLAN_OFFSET 4 +#define RTL8367C_SEC_RUN_CVLAN_MASK 0x10 +#define RTL8367C_CVALN_HLDRMP_MD_OFFSET 3 +#define RTL8367C_CVALN_HLDRMP_MD_MASK 0x8 +#define RTL8367C_CVALN_HLDRMP_VAL_OFFSET 2 +#define RTL8367C_CVALN_HLDRMP_VAL_MASK 0x4 +#define RTL8367C_CVLAN_BISR_BIRSTN_OFFSET 1 +#define RTL8367C_CVLAN_BISR_BIRSTN_MASK 0x2 +#define RTL8367C_CVLAN_BISR_PWRSTN_OFFSET 0 +#define RTL8367C_CVLAN_BISR_PWRSTN_MASK 0x1 + +#define RTL8367C_REG_CFG_1588_TIMER_EN_GPI 0x1d3a +#define RTL8367C_CFG_1588_TIMER_EN_GPI_OFFSET 0 +#define RTL8367C_CFG_1588_TIMER_EN_GPI_MASK 0x1 + +#define RTL8367C_REG_MDIO_PRMB_SUPP 0x1d3b +#define RTL8367C_FIB_HIPRI_OFFSET 14 +#define RTL8367C_FIB_HIPRI_MASK 0x4000 +#define RTL8367C_SMT_EN_OFFSET 13 +#define RTL8367C_SMT_EN_MASK 0x2000 +#define RTL8367C_P4_FB_CPL_OFFSET 12 +#define RTL8367C_P4_FB_CPL_MASK 0x1000 +#define RTL8367C_P3_FB_CPL_OFFSET 11 +#define RTL8367C_P3_FB_CPL_MASK 0x800 +#define RTL8367C_P2_FB_CPL_OFFSET 10 +#define RTL8367C_P2_FB_CPL_MASK 0x400 +#define RTL8367C_P1_FB_CPL_OFFSET 9 +#define RTL8367C_P1_FB_CPL_MASK 0x200 +#define RTL8367C_P0_FB_CPL_OFFSET 8 +#define RTL8367C_P0_FB_CPL_MASK 0x100 +#define RTL8367C_DBG_PKG_8367N_OFFSET 7 +#define RTL8367C_DBG_PKG_8367N_MASK 0x80 +#define RTL8367C_DBG_PKG_8367VB_OFFSET 6 +#define RTL8367C_DBG_PKG_8367VB_MASK 0x40 +#define RTL8367C_CFG_DEBUG_EN_OFFSET 5 +#define RTL8367C_CFG_DEBUG_EN_MASK 0x20 +#define RTL8367C_CFG_TMR_ACK_OFFSET 1 +#define RTL8367C_CFG_TMR_ACK_MASK 0x1E +#define RTL8367C_CFG_PRMB_SUPP_OFFSET 0 +#define RTL8367C_CFG_PRMB_SUPP_MASK 0x1 + +#define RTL8367C_REG_BOND4READ 0x1d3c +#define RTL8367C_BOND_BOID0_OFFSET 8 +#define RTL8367C_BOND_BOID0_MASK 0x100 +#define RTL8367C_BOND_SYSCLK_OFFSET 7 +#define RTL8367C_BOND_SYSCLK_MASK 0x80 +#define RTL8367C_BOND_PHYMODE_OFFSET 6 +#define RTL8367C_BOND_PHYMODE_MASK 0x40 +#define RTL8367C_BOND_DIS_PON_BIST_OFFSET 5 +#define RTL8367C_BOND_DIS_PON_BIST_MASK 0x20 +#define RTL8367C_BOND_DIS_TABLE_INIT_OFFSET 4 +#define RTL8367C_BOND_DIS_TABLE_INIT_MASK 0x10 +#define RTL8367C_BOND_BYP_AFE_PLL_OFFSET 3 +#define RTL8367C_BOND_BYP_AFE_PLL_MASK 0x8 +#define RTL8367C_BOND_BYP_AFE_POR_OFFSET 2 +#define RTL8367C_BOND_BYP_AFE_POR_MASK 0x4 +#define RTL8367C_BOND_BISR_COND_OFFSET 1 +#define RTL8367C_BOND_BISR_COND_MASK 0x2 +#define RTL8367C_BOND_EF_EN_OFFSET 0 +#define RTL8367C_BOND_EF_EN_MASK 0x1 + +#define RTL8367C_REG_REG_TO_ECO0 0x1d3d + +#define RTL8367C_REG_REG_TO_ECO1 0x1d3e + +#define RTL8367C_REG_REG_TO_ECO2 0x1d3f + +#define RTL8367C_REG_REG_TO_ECO3 0x1d40 + +#define RTL8367C_REG_REG_TO_ECO4 0x1d41 + +#define RTL8367C_REG_PHYSTS_CTRL0 0x1d42 +#define RTL8367C_MACRX_DUPDET_EN_OFFSET 5 +#define RTL8367C_MACRX_DUPDET_EN_MASK 0x20 +#define RTL8367C_LNKUP_DLY_EN_OFFSET 4 +#define RTL8367C_LNKUP_DLY_EN_MASK 0x10 +#define RTL8367C_GE_100M_LNKUP_DLY_OFFSET 2 +#define RTL8367C_GE_100M_LNKUP_DLY_MASK 0xC +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_OFFSET 0 +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_MASK 0x3 + +#define RTL8367C_REG_SSC_CTRL0_0 0x1d44 +#define RTL8367C_SSC_CTRL0_0_SSC_TYPE_OFFSET 13 +#define RTL8367C_SSC_CTRL0_0_SSC_TYPE_MASK 0x2000 +#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_OFFSET 5 +#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_SEL_MASK 0x1FE0 +#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_OFFSET 4 +#define RTL8367C_SSC_CTRL0_0_PHASE_LIM_EN_MASK 0x10 +#define RTL8367C_SSC_CTRL0_0_DLL_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL0_0_DLL_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL0_0_SSC_EN_OFFSET 1 +#define RTL8367C_SSC_CTRL0_0_SSC_EN_MASK 0x2 +#define RTL8367C_SSC_CTRL0_0_SSC_MODE_OFFSET 0 +#define RTL8367C_SSC_CTRL0_0_SSC_MODE_MASK 0x1 + +#define RTL8367C_REG_SSC_RDM_SEED 0x1d45 + +#define RTL8367C_REG_SSC_PN_POLY_SEL 0x1d46 + +#define RTL8367C_REG_SSC_CTRL0_3 0x1d47 +#define RTL8367C_SSC_CTRL0_3_PHSFT_CNT_OFFSET 8 +#define RTL8367C_SSC_CTRL0_3_PHSFT_CNT_MASK 0x7F00 +#define RTL8367C_SSC_CTRL0_3_PHSFT_A_OFFSET 7 +#define RTL8367C_SSC_CTRL0_3_PHSFT_A_MASK 0x80 +#define RTL8367C_SSC_CTRL0_3_PHSFT_B_OFFSET 6 +#define RTL8367C_SSC_CTRL0_3_PHSFT_B_MASK 0x40 +#define RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_OFFSET 5 +#define RTL8367C_SSC_CTRL0_3_PHSFT_UPDN_MASK 0x20 +#define RTL8367C_SSC_CTRL0_3_PHSFT_PRD_OFFSET 4 +#define RTL8367C_SSC_CTRL0_3_PHSFT_PRD_MASK 0x10 +#define RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_OFFSET 0 +#define RTL8367C_SSC_CTRL0_3_PN_POLY_DEG_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL0_4 0x1d48 +#define RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_OFFSET 15 +#define RTL8367C_SSC_CTRL0_4_SSC_UP1DN0_MASK 0x8000 +#define RTL8367C_SSC_CTRL0_4_SSC_PERIOD_OFFSET 8 +#define RTL8367C_SSC_CTRL0_4_SSC_PERIOD_MASK 0x7F00 +#define RTL8367C_SSC_CTRL0_4_SSC_OFFSET_OFFSET 0 +#define RTL8367C_SSC_CTRL0_4_SSC_OFFSET_MASK 0xFF + +#define RTL8367C_REG_SSC_CTRL0_5 0x1d49 +#define RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_OFFSET 15 +#define RTL8367C_SSC_CTRL0_5_PH_OFS_TOG_MASK 0x8000 +#define RTL8367C_SSC_CTRL0_5_PH_OFS_OFFSET 10 +#define RTL8367C_SSC_CTRL0_5_PH_OFS_MASK 0x7C00 +#define RTL8367C_SSC_CTRL0_5_SSC_STEP_OFFSET 4 +#define RTL8367C_SSC_CTRL0_5_SSC_STEP_MASK 0x3F0 +#define RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL0_5_SSC_TEST_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_OFFSET 0 +#define RTL8367C_SSC_CTRL0_5_SSC_PH_CFG_MASK 0x3 + +#define RTL8367C_REG_SSC_STS0 0x1d4a +#define RTL8367C_SSC_STS0_OFS_BUSY_OFFSET 13 +#define RTL8367C_SSC_STS0_OFS_BUSY_MASK 0x2000 +#define RTL8367C_SSC_STS0_OFS_TOTAL_R_OFFSET 8 +#define RTL8367C_SSC_STS0_OFS_TOTAL_R_MASK 0x1F00 +#define RTL8367C_SSC_STS0_CNT_GRY0_OFFSET 4 +#define RTL8367C_SSC_STS0_CNT_GRY0_MASK 0xF0 +#define RTL8367C_SSC_STS0_OFS_GRY0_OFFSET 0 +#define RTL8367C_SSC_STS0_OFS_GRY0_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL1_0 0x1d4b +#define RTL8367C_SSC_CTRL1_0_SSC_TYPE_OFFSET 13 +#define RTL8367C_SSC_CTRL1_0_SSC_TYPE_MASK 0x2000 +#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_OFFSET 5 +#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_SEL_MASK 0x1FE0 +#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_OFFSET 4 +#define RTL8367C_SSC_CTRL1_0_PHASE_LIM_EN_MASK 0x10 +#define RTL8367C_SSC_CTRL1_0_DLL_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL1_0_DLL_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL1_0_SSC_EN_OFFSET 1 +#define RTL8367C_SSC_CTRL1_0_SSC_EN_MASK 0x2 +#define RTL8367C_SSC_CTRL1_0_SSC_MODE_OFFSET 0 +#define RTL8367C_SSC_CTRL1_0_SSC_MODE_MASK 0x1 + +#define RTL8367C_REG_SSC_RDM_SEED1 0x1d4c + +#define RTL8367C_REG_SSC_PN_POLY_SEL1 0x1d4d + +#define RTL8367C_REG_SSC_CTRL1_3 0x1d4e +#define RTL8367C_SSC_CTRL1_3_PHSFT_CNT_OFFSET 8 +#define RTL8367C_SSC_CTRL1_3_PHSFT_CNT_MASK 0x7F00 +#define RTL8367C_SSC_CTRL1_3_PHSFT_A_OFFSET 7 +#define RTL8367C_SSC_CTRL1_3_PHSFT_A_MASK 0x80 +#define RTL8367C_SSC_CTRL1_3_PHSFT_B_OFFSET 6 +#define RTL8367C_SSC_CTRL1_3_PHSFT_B_MASK 0x40 +#define RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_OFFSET 5 +#define RTL8367C_SSC_CTRL1_3_PHSFT_UPDN_MASK 0x20 +#define RTL8367C_SSC_CTRL1_3_PHSFT_PRD_OFFSET 4 +#define RTL8367C_SSC_CTRL1_3_PHSFT_PRD_MASK 0x10 +#define RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_OFFSET 0 +#define RTL8367C_SSC_CTRL1_3_PN_POLY_DEG_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL1_4 0x1d4f +#define RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_OFFSET 15 +#define RTL8367C_SSC_CTRL1_4_SSC_UP1DN0_MASK 0x8000 +#define RTL8367C_SSC_CTRL1_4_SSC_PERIOD_OFFSET 8 +#define RTL8367C_SSC_CTRL1_4_SSC_PERIOD_MASK 0x7F00 +#define RTL8367C_SSC_CTRL1_4_SSC_OFFSET_OFFSET 0 +#define RTL8367C_SSC_CTRL1_4_SSC_OFFSET_MASK 0xFF + +#define RTL8367C_REG_SSC_CTRL1_5 0x1d50 +#define RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_OFFSET 15 +#define RTL8367C_SSC_CTRL1_5_PH_OFS_TOG_MASK 0x8000 +#define RTL8367C_SSC_CTRL1_5_PH_OFS_OFFSET 10 +#define RTL8367C_SSC_CTRL1_5_PH_OFS_MASK 0x7C00 +#define RTL8367C_SSC_CTRL1_5_SSC_STEP_OFFSET 4 +#define RTL8367C_SSC_CTRL1_5_SSC_STEP_MASK 0x3F0 +#define RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL1_5_SSC_TEST_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_OFFSET 0 +#define RTL8367C_SSC_CTRL1_5_SSC_PH_CFG_MASK 0x3 + +#define RTL8367C_REG_SSC_STS1 0x1d51 +#define RTL8367C_SSC_STS1_OFS_BUSY_OFFSET 13 +#define RTL8367C_SSC_STS1_OFS_BUSY_MASK 0x2000 +#define RTL8367C_SSC_STS1_OFS_TOTAL_R_OFFSET 8 +#define RTL8367C_SSC_STS1_OFS_TOTAL_R_MASK 0x1F00 +#define RTL8367C_SSC_STS1_CNT_GRY0_OFFSET 4 +#define RTL8367C_SSC_STS1_CNT_GRY0_MASK 0xF0 +#define RTL8367C_SSC_STS1_OFS_GRY0_OFFSET 0 +#define RTL8367C_SSC_STS1_OFS_GRY0_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL2_0 0x1d52 +#define RTL8367C_SSC_CTRL2_0_SSC_TYPE_OFFSET 13 +#define RTL8367C_SSC_CTRL2_0_SSC_TYPE_MASK 0x2000 +#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_OFFSET 5 +#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_SEL_MASK 0x1FE0 +#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_OFFSET 4 +#define RTL8367C_SSC_CTRL2_0_PHASE_LIM_EN_MASK 0x10 +#define RTL8367C_SSC_CTRL2_0_DLL_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL2_0_DLL_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL2_0_SSC_EN_OFFSET 1 +#define RTL8367C_SSC_CTRL2_0_SSC_EN_MASK 0x2 +#define RTL8367C_SSC_CTRL2_0_SSC_MODE_OFFSET 0 +#define RTL8367C_SSC_CTRL2_0_SSC_MODE_MASK 0x1 + +#define RTL8367C_REG_SSC_RDM_SEED2 0x1d53 + +#define RTL8367C_REG_SSC_PN_POLY_SEL2 0x1d54 + +#define RTL8367C_REG_SSC_CTRL2_3 0x1d55 +#define RTL8367C_SSC_CTRL2_3_PHSFT_CNT_OFFSET 8 +#define RTL8367C_SSC_CTRL2_3_PHSFT_CNT_MASK 0x7F00 +#define RTL8367C_SSC_CTRL2_3_PHSFT_A_OFFSET 7 +#define RTL8367C_SSC_CTRL2_3_PHSFT_A_MASK 0x80 +#define RTL8367C_SSC_CTRL2_3_PHSFT_B_OFFSET 6 +#define RTL8367C_SSC_CTRL2_3_PHSFT_B_MASK 0x40 +#define RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_OFFSET 5 +#define RTL8367C_SSC_CTRL2_3_PHSFT_UPDN_MASK 0x20 +#define RTL8367C_SSC_CTRL2_3_PHSFT_PRD_OFFSET 4 +#define RTL8367C_SSC_CTRL2_3_PHSFT_PRD_MASK 0x10 +#define RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_OFFSET 0 +#define RTL8367C_SSC_CTRL2_3_PN_POLY_DEG_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL2_4 0x1d56 +#define RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_OFFSET 15 +#define RTL8367C_SSC_CTRL2_4_SSC_UP1DN0_MASK 0x8000 +#define RTL8367C_SSC_CTRL2_4_SSC_PERIOD_OFFSET 8 +#define RTL8367C_SSC_CTRL2_4_SSC_PERIOD_MASK 0x7F00 +#define RTL8367C_SSC_CTRL2_4_SSC_OFFSET_OFFSET 0 +#define RTL8367C_SSC_CTRL2_4_SSC_OFFSET_MASK 0xFF + +#define RTL8367C_REG_SSC_CTRL2_5 0x1d57 +#define RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_OFFSET 15 +#define RTL8367C_SSC_CTRL2_5_PH_OFS_TOG_MASK 0x8000 +#define RTL8367C_SSC_CTRL2_5_PH_OFS_OFFSET 10 +#define RTL8367C_SSC_CTRL2_5_PH_OFS_MASK 0x7C00 +#define RTL8367C_SSC_CTRL2_5_SSC_STEP_OFFSET 4 +#define RTL8367C_SSC_CTRL2_5_SSC_STEP_MASK 0x3F0 +#define RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL2_5_SSC_TEST_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_OFFSET 0 +#define RTL8367C_SSC_CTRL2_5_SSC_PH_CFG_MASK 0x3 + +#define RTL8367C_REG_SSC_STS2 0x1d58 +#define RTL8367C_SSC_STS2_OFS_BUSY_OFFSET 13 +#define RTL8367C_SSC_STS2_OFS_BUSY_MASK 0x2000 +#define RTL8367C_SSC_STS2_OFS_TOTAL_R_OFFSET 8 +#define RTL8367C_SSC_STS2_OFS_TOTAL_R_MASK 0x1F00 +#define RTL8367C_SSC_STS2_CNT_GRY0_OFFSET 4 +#define RTL8367C_SSC_STS2_CNT_GRY0_MASK 0xF0 +#define RTL8367C_SSC_STS2_OFS_GRY0_OFFSET 0 +#define RTL8367C_SSC_STS2_OFS_GRY0_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL3_0 0x1d59 +#define RTL8367C_SSC_CTRL3_0_SSC_TYPE_OFFSET 13 +#define RTL8367C_SSC_CTRL3_0_SSC_TYPE_MASK 0x2000 +#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_OFFSET 5 +#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_SEL_MASK 0x1FE0 +#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_OFFSET 4 +#define RTL8367C_SSC_CTRL3_0_PHASE_LIM_EN_MASK 0x10 +#define RTL8367C_SSC_CTRL3_0_DLL_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL3_0_DLL_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL3_0_SSC_EN_OFFSET 1 +#define RTL8367C_SSC_CTRL3_0_SSC_EN_MASK 0x2 +#define RTL8367C_SSC_CTRL3_0_SSC_MODE_OFFSET 0 +#define RTL8367C_SSC_CTRL3_0_SSC_MODE_MASK 0x1 + +#define RTL8367C_REG_SSC_RDM_SEED3 0x1d5a + +#define RTL8367C_REG_SSC_PN_POLY_SEL3 0x1d5b + +#define RTL8367C_REG_SSC_CTRL3_3 0x1d5c +#define RTL8367C_SSC_CTRL3_3_PHSFT_CNT_OFFSET 8 +#define RTL8367C_SSC_CTRL3_3_PHSFT_CNT_MASK 0x7F00 +#define RTL8367C_SSC_CTRL3_3_PHSFT_A_OFFSET 7 +#define RTL8367C_SSC_CTRL3_3_PHSFT_A_MASK 0x80 +#define RTL8367C_SSC_CTRL3_3_PHSFT_B_OFFSET 6 +#define RTL8367C_SSC_CTRL3_3_PHSFT_B_MASK 0x40 +#define RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_OFFSET 5 +#define RTL8367C_SSC_CTRL3_3_PHSFT_UPDN_MASK 0x20 +#define RTL8367C_SSC_CTRL3_3_PHSFT_PRD_OFFSET 4 +#define RTL8367C_SSC_CTRL3_3_PHSFT_PRD_MASK 0x10 +#define RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_OFFSET 0 +#define RTL8367C_SSC_CTRL3_3_PN_POLY_DEG_MASK 0xF + +#define RTL8367C_REG_SSC_CTRL3_4 0x1d5d +#define RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_OFFSET 15 +#define RTL8367C_SSC_CTRL3_4_SSC_UP1DN0_MASK 0x8000 +#define RTL8367C_SSC_CTRL3_4_SSC_PERIOD_OFFSET 8 +#define RTL8367C_SSC_CTRL3_4_SSC_PERIOD_MASK 0x7F00 +#define RTL8367C_SSC_CTRL3_4_SSC_OFFSET_OFFSET 0 +#define RTL8367C_SSC_CTRL3_4_SSC_OFFSET_MASK 0xFF + +#define RTL8367C_REG_SSC_CTRL3_5 0x1d5e +#define RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_OFFSET 15 +#define RTL8367C_SSC_CTRL3_5_PH_OFS_TOG_MASK 0x8000 +#define RTL8367C_SSC_CTRL3_5_PH_OFS_OFFSET 10 +#define RTL8367C_SSC_CTRL3_5_PH_OFS_MASK 0x7C00 +#define RTL8367C_SSC_CTRL3_5_SSC_STEP_OFFSET 4 +#define RTL8367C_SSC_CTRL3_5_SSC_STEP_MASK 0x3F0 +#define RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_OFFSET 2 +#define RTL8367C_SSC_CTRL3_5_SSC_TEST_MODE_MASK 0xC +#define RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_OFFSET 0 +#define RTL8367C_SSC_CTRL3_5_SSC_PH_CFG_MASK 0x3 + +#define RTL8367C_REG_SSC_STS3 0x1d5f +#define RTL8367C_SSC_STS3_OFS_BUSY_OFFSET 13 +#define RTL8367C_SSC_STS3_OFS_BUSY_MASK 0x2000 +#define RTL8367C_SSC_STS3_OFS_TOTAL_R_OFFSET 8 +#define RTL8367C_SSC_STS3_OFS_TOTAL_R_MASK 0x1F00 +#define RTL8367C_SSC_STS3_CNT_GRY0_OFFSET 4 +#define RTL8367C_SSC_STS3_CNT_GRY0_MASK 0xF0 +#define RTL8367C_SSC_STS3_OFS_GRY0_OFFSET 0 +#define RTL8367C_SSC_STS3_OFS_GRY0_MASK 0xF + +#define RTL8367C_REG_PHY_POLL_CFG13 0x1d60 + +#define RTL8367C_REG_PHY_POLL_CFG14 0x1d61 + +#define RTL8367C_REG_FRC_SYS_CLK 0x1d62 +#define RTL8367C_SYSCLK_FRC_MD_OFFSET 1 +#define RTL8367C_SYSCLK_FRC_MD_MASK 0x2 +#define RTL8367C_SYSCLK_FRC_VAL_OFFSET 0 +#define RTL8367C_SYSCLK_FRC_VAL_MASK 0x1 + +#define RTL8367C_REG_AFE_SSC_CTRL 0x1d63 +#define RTL8367C_PH_RSTB_TXD1_OFFSET 9 +#define RTL8367C_PH_RSTB_TXD1_MASK 0x200 +#define RTL8367C_PH_RSTB_TXC1_OFFSET 8 +#define RTL8367C_PH_RSTB_TXC1_MASK 0x100 +#define RTL8367C_PH_RSTB_TXD0_OFFSET 7 +#define RTL8367C_PH_RSTB_TXD0_MASK 0x80 +#define RTL8367C_PH_RSTB_TXC0_OFFSET 6 +#define RTL8367C_PH_RSTB_TXC0_MASK 0x40 +#define RTL8367C_PH_RSTBSYS_OFFSET 5 +#define RTL8367C_PH_RSTBSYS_MASK 0x20 +#define RTL8367C_PH_RSTB8051_OFFSET 4 +#define RTL8367C_PH_RSTB8051_MASK 0x10 +#define RTL8367C_OREG_SSC_OFFSET 0 +#define RTL8367C_OREG_SSC_MASK 0xF + +#define RTL8367C_REG_BUFF_RST_CTRL0 0x1d64 +#define RTL8367C_BUFFRST_TXESD_EN_OFFSET 13 +#define RTL8367C_BUFFRST_TXESD_EN_MASK 0x2000 +#define RTL8367C_BUFF_RST_TIME_LONG_OFFSET 8 +#define RTL8367C_BUFF_RST_TIME_LONG_MASK 0x1F00 +#define RTL8367C_BUFF_RST_TIME_SHORT_OFFSET 3 +#define RTL8367C_BUFF_RST_TIME_SHORT_MASK 0xF8 +#define RTL8367C_SW_BUFF_RST_OFFSET 2 +#define RTL8367C_SW_BUFF_RST_MASK 0x4 +#define RTL8367C_IMS_BUFF_RST_OFFSET 1 +#define RTL8367C_IMS_BUFF_RST_MASK 0x2 +#define RTL8367C_IMR_BUFF_RST_OFFSET 0 +#define RTL8367C_IMR_BUFF_RST_MASK 0x1 + +#define RTL8367C_REG_BUFF_RST_CTRL1 0x1d65 +#define RTL8367C_BUFFRST_SYSOVER_EN_OFFSET 10 +#define RTL8367C_BUFFRST_SYSOVER_EN_MASK 0x400 +#define RTL8367C_BUFFRST_SYSOVER_THR_OFFSET 0 +#define RTL8367C_BUFFRST_SYSOVER_THR_MASK 0x3FF + +#define RTL8367C_REG_BUFF_RST_CTRL2 0x1d66 +#define RTL8367C_BUFFRST_QOVER_EN_OFFSET 10 +#define RTL8367C_BUFFRST_QOVER_EN_MASK 0x400 +#define RTL8367C_BUFFRST_QOVER_THR_OFFSET 0 +#define RTL8367C_BUFFRST_QOVER_THR_MASK 0x3FF + +#define RTL8367C_REG_BUFF_RST_CTRL3 0x1d67 +#define RTL8367C_DSC_TIMER_OFFSET 11 +#define RTL8367C_DSC_TIMER_MASK 0x7800 +#define RTL8367C_BUFFRST_DSCOVER_THR_OFFSET 1 +#define RTL8367C_BUFFRST_DSCOVER_THR_MASK 0x7FE +#define RTL8367C_BUFFRST_DSCOVER_EN_OFFSET 0 +#define RTL8367C_BUFFRST_DSCOVER_EN_MASK 0x1 + +#define RTL8367C_REG_BUFF_RST_CTRL4 0x1d68 +#define RTL8367C_INDSC_TIMER_OFFSET 11 +#define RTL8367C_INDSC_TIMER_MASK 0x7800 +#define RTL8367C_BUFFRST_INDSCOVER_THR_OFFSET 1 +#define RTL8367C_BUFFRST_INDSCOVER_THR_MASK 0x7FE +#define RTL8367C_BUFFRST_INDSCOVER_EN_OFFSET 0 +#define RTL8367C_BUFFRST_INDSCOVER_EN_MASK 0x1 + +#define RTL8367C_REG_BUFF_RST_CTRL5 0x1d69 +#define RTL8367C_TX_ESD_MODE_OFFSET 8 +#define RTL8367C_TX_ESD_MODE_MASK 0x100 +#define RTL8367C_TX_ESD_LVL_OFFSET 0 +#define RTL8367C_TX_ESD_LVL_MASK 0xFF + +#define RTL8367C_REG_TOP_CON0 0x1d70 +#define RTL8367C_TOP_CON0_SDS_PWR_ISO_1_OFFSET 15 +#define RTL8367C_TOP_CON0_SDS_PWR_ISO_1_MASK 0x8000 +#define RTL8367C_OCP_TIMEOUT_P7_5_OFFSET 12 +#define RTL8367C_OCP_TIMEOUT_P7_5_MASK 0x7000 +#define RTL8367C_FIB_EEE_AB_OFFSET 11 +#define RTL8367C_FIB_EEE_AB_MASK 0x800 +#define RTL8367C_ADCCKIEN_OFFSET 10 +#define RTL8367C_ADCCKIEN_MASK 0x400 +#define RTL8367C_OCP_TIMEOUT_OFFSET 5 +#define RTL8367C_OCP_TIMEOUT_MASK 0x3E0 +#define RTL8367C_TOP_CON0_SDS_PWR_ISO_OFFSET 4 +#define RTL8367C_TOP_CON0_SDS_PWR_ISO_MASK 0x10 +#define RTL8367C_RG2_TXC_SEL_OFFSET 3 +#define RTL8367C_RG2_TXC_SEL_MASK 0x8 +#define RTL8367C_RG1TXC_SEL_OFFSET 2 +#define RTL8367C_RG1TXC_SEL_MASK 0x4 +#define RTL8367C_SYNC_1588_EN_OFFSET 1 +#define RTL8367C_SYNC_1588_EN_MASK 0x2 +#define RTL8367C_LS_MODE_OFFSET 0 +#define RTL8367C_LS_MODE_MASK 0x1 + +#define RTL8367C_REG_TOP_CON1 0x1d71 +#define RTL8367C_TA_CHK_EN_OFFSET 2 +#define RTL8367C_TA_CHK_EN_MASK 0x4 +#define RTL8367C_SLV_EG_SEL_OFFSET 1 +#define RTL8367C_SLV_EG_SEL_MASK 0x2 +#define RTL8367C_IIC_OP_DRAIN_OFFSET 0 +#define RTL8367C_IIC_OP_DRAIN_MASK 0x1 + +#define RTL8367C_REG_SWR_FPWM 0x1d72 +#define RTL8367C_SWR_FPWM_OFFSET 0 +#define RTL8367C_SWR_FPWM_MASK 0x1 + +#define RTL8367C_REG_EEEP_CTRL_500M 0x1d73 + +#define RTL8367C_REG_SHORT_PRMB 0x1d74 +#define RTL8367C_SHORT_PRMB_OFFSET 0 +#define RTL8367C_SHORT_PRMB_MASK 0x1 + +#define RTL8367C_REG_INDSC_THR_CTRL 0x1d75 +#define RTL8367C_INDSC_THR_CTRL_OFFSET 0 +#define RTL8367C_INDSC_THR_CTRL_MASK 0x7FF + +#define RTL8367C_REG_SET_PAD_CTRL_NEW 0x1d80 +#define RTL8367C_SET_PAD_CTRL_NEW_OFFSET 0 +#define RTL8367C_SET_PAD_CTRL_NEW_MASK 0x1 + +#define RTL8367C_REG_SET_PAD_DRI_0 0x1d81 + +#define RTL8367C_REG_SET_PAD_DRI_1 0x1d82 + +#define RTL8367C_REG_SET_PAD_DRI_2 0x1d83 + +#define RTL8367C_REG_SET_PAD_SLEW_0 0x1d84 + +#define RTL8367C_REG_SET_PAD_SLEW_1 0x1d85 + +#define RTL8367C_REG_SET_PAD_SLEW_2 0x1d86 + +#define RTL8367C_REG_SET_PAD_SMT_0 0x1d87 + +#define RTL8367C_REG_SET_PAD_SMT_1 0x1d88 + +#define RTL8367C_REG_SET_PAD_SMT_2 0x1d89 + +#define RTL8367C_REG_M_I2C_CTL_STA_REG 0x1d8a +#define RTL8367C_TX_RX_DATA_OFFSET 8 +#define RTL8367C_TX_RX_DATA_MASK 0xFF00 +#define RTL8367C_DUMB_RW_ERR_OFFSET 7 +#define RTL8367C_DUMB_RW_ERR_MASK 0x80 +#define RTL8367C_SLV_ACK_FLAG_OFFSET 6 +#define RTL8367C_SLV_ACK_FLAG_MASK 0x40 +#define RTL8367C_M_I2C_BUS_IDLE_OFFSET 5 +#define RTL8367C_M_I2C_BUS_IDLE_MASK 0x20 +#define RTL8367C_I2C_CMD_TYPE_OFFSET 1 +#define RTL8367C_I2C_CMD_TYPE_MASK 0x1E +#define RTL8367C_I2C_CMD_EXEC_OFFSET 0 +#define RTL8367C_I2C_CMD_EXEC_MASK 0x1 + +#define RTL8367C_REG_M_I2C_DUMB_RW_ADDR_0 0x1d8b + +#define RTL8367C_REG_M_I2C_DUMB_RW_ADDR_1 0x1d8c + +#define RTL8367C_REG_M_I2C_DUMB_RW_DATA_0 0x1d8d + +#define RTL8367C_REG_M_I2C_DUMB_RW_DATA_1 0x1d8e + +#define RTL8367C_REG_M_I2C_DUMB_RW_CTL 0x1d8f +#define RTL8367C_DUMB_I2C_CTL_CODE_OFFSET 8 +#define RTL8367C_DUMB_I2C_CTL_CODE_MASK 0x7F00 +#define RTL8367C_DUMB_RW_I2C_FORMAT_OFFSET 4 +#define RTL8367C_DUMB_RW_I2C_FORMAT_MASK 0x10 +#define RTL8367C_DUMB_RW_DATA_MODE_OFFSET 2 +#define RTL8367C_DUMB_RW_DATA_MODE_MASK 0xC +#define RTL8367C_DUMB_RW_ADDR_MODE_OFFSET 0 +#define RTL8367C_DUMB_RW_ADDR_MODE_MASK 0x3 + +#define RTL8367C_REG_M_I2C_SYS_CTL 0x1d90 +#define RTL8367C_M_I2C_SCL_IO_MUX_OFFSET 12 +#define RTL8367C_M_I2C_SCL_IO_MUX_MASK 0x3000 +#define RTL8367C_M_I2C_SDA_IO_MUX_OFFSET 10 +#define RTL8367C_M_I2C_SDA_IO_MUX_MASK 0xC00 +#define RTL8367C_M_I2C_SDA_OD_EN_OFFSET 9 +#define RTL8367C_M_I2C_SDA_OD_EN_MASK 0x200 +#define RTL8367C_M_I2C_SCL_OD_EN_OFFSET 8 +#define RTL8367C_M_I2C_SCL_OD_EN_MASK 0x100 +#define RTL8367C_M_I2C_SCL_F_DIV_OFFSET 0 +#define RTL8367C_M_I2C_SCL_F_DIV_MASK 0xFF + +#define RTL8367C_REG_HT_PB_SRAM_CTRL 0x1da0 +#define RTL8367C_HTPB_RW_OFFSET 2 +#define RTL8367C_HTPB_RW_MASK 0x4 +#define RTL8367C_HTPB_SEL_OFFSET 1 +#define RTL8367C_HTPB_SEL_MASK 0x2 +#define RTL8367C_HTPB_CE_OFFSET 0 +#define RTL8367C_HTPB_CE_MASK 0x1 + +#define RTL8367C_REG_HT_PB_SRAM_ADDR 0x1da1 + +#define RTL8367C_REG_HT_PB_SRAM_DIN0 0x1da2 + +#define RTL8367C_REG_HT_PB_SRAM_DIN1 0x1da3 + +#define RTL8367C_REG_HT_PB_SRAM_DOUT0 0x1da4 + +#define RTL8367C_REG_HT_PB_SRAM_DOUT1 0x1da5 + +#define RTL8367C_REG_PHY_STAT_0 0x1db0 + +#define RTL8367C_REG_PHY_STAT_1 0x1db1 + +#define RTL8367C_REG_PHY_STAT_2 0x1db2 + +#define RTL8367C_REG_PHY_STAT_3 0x1db3 + +#define RTL8367C_REG_PHY_STAT_4 0x1db4 + +#define RTL8367C_REG_PHY_STAT_5 0x1db5 + +#define RTL8367C_REG_PHY_STAT_6 0x1db6 + +#define RTL8367C_REG_PHY_STAT_7 0x1db7 + +#define RTL8367C_REG_SDS_STAT_0 0x1db8 + +#define RTL8367C_REG_SDS_STAT_1 0x1db9 + +#define RTL8367C_REG_MAC_LINK_STAT_0 0x1dba +#define RTL8367C_MAC_LINK_STAT_CUR_0_OFFSET 8 +#define RTL8367C_MAC_LINK_STAT_CUR_0_MASK 0xFF00 +#define RTL8367C_MAC_LINK_STAT_LATCH_0_OFFSET 0 +#define RTL8367C_MAC_LINK_STAT_LATCH_0_MASK 0xFF + +#define RTL8367C_REG_MAC_LINK_STAT_1 0x1dbb +#define RTL8367C_MAC_LINK_STAT_1_Reserved_OFFSET 6 +#define RTL8367C_MAC_LINK_STAT_1_Reserved_MASK 0xFFC0 +#define RTL8367C_MAC_LINK_STAT_CUR_1_OFFSET 3 +#define RTL8367C_MAC_LINK_STAT_CUR_1_MASK 0x38 +#define RTL8367C_MAC_LINK_STAT_LATCH_1_OFFSET 0 +#define RTL8367C_MAC_LINK_STAT_LATCH_1_MASK 0x7 + +#define RTL8367C_REG_MISC_CONTROL_1 0x1dc0 +#define RTL8367C_P7_FB_CPL_OFFSET 2 +#define RTL8367C_P7_FB_CPL_MASK 0x4 +#define RTL8367C_P6_FB_CPL_OFFSET 1 +#define RTL8367C_P6_FB_CPL_MASK 0x2 +#define RTL8367C_P5_FB_CPL_OFFSET 0 +#define RTL8367C_P5_FB_CPL_MASK 0x1 + +#define RTL8367C_REG_SDS_MISC_1 0x1dc1 +#define RTL8367C_CFG_SGMII_RXFC_1_OFFSET 14 +#define RTL8367C_CFG_SGMII_RXFC_1_MASK 0x4000 +#define RTL8367C_CFG_SGMII_TXFC_1_OFFSET 13 +#define RTL8367C_CFG_SGMII_TXFC_1_MASK 0x2000 +#define RTL8367C_CFG_MAC9_SEL_HSGMII_OFFSET 11 +#define RTL8367C_CFG_MAC9_SEL_HSGMII_MASK 0x800 +#define RTL8367C_CFG_SGMII_FDUP_1_OFFSET 10 +#define RTL8367C_CFG_SGMII_FDUP_1_MASK 0x400 +#define RTL8367C_CFG_SGMII_LINK_1_OFFSET 9 +#define RTL8367C_CFG_SGMII_LINK_1_MASK 0x200 +#define RTL8367C_CFG_SGMII_SPD_1_OFFSET 7 +#define RTL8367C_CFG_SGMII_SPD_1_MASK 0x180 +#define RTL8367C_CFG_MAC9_SEL_SGMII_OFFSET 6 +#define RTL8367C_CFG_MAC9_SEL_SGMII_MASK 0x40 +#define RTL8367C_CFG_SDS_MODE_14C_1_OFFSET 0 +#define RTL8367C_CFG_SDS_MODE_14C_1_MASK 0x7 + +#define RTL8367C_REG_FIBER_CFG_2_1 0x1dc2 +#define RTL8367C_SDS_RX_DISABLE_1_OFFSET 6 +#define RTL8367C_SDS_RX_DISABLE_1_MASK 0xC0 +#define RTL8367C_SDS_TX_DISABLE_1_OFFSET 4 +#define RTL8367C_SDS_TX_DISABLE_1_MASK 0x30 +#define RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_OFFSET 2 +#define RTL8367C_FIBER_CFG_2_1_SDS_PWR_ISO_1_MASK 0xC +#define RTL8367C_SDS_FRC_LD_1_OFFSET 0 +#define RTL8367C_SDS_FRC_LD_1_MASK 0x3 + +#define RTL8367C_REG_FIBER_CFG_1_1 0x1dc3 +#define RTL8367C_SDS_FRC_REG4_1_OFFSET 12 +#define RTL8367C_SDS_FRC_REG4_1_MASK 0x1000 +#define RTL8367C_SDS_FRC_REG4_FIB100_1_OFFSET 11 +#define RTL8367C_SDS_FRC_REG4_FIB100_1_MASK 0x800 +#define RTL8367C_SDS_FRC_MODE_1_OFFSET 3 +#define RTL8367C_SDS_FRC_MODE_1_MASK 0x8 +#define RTL8367C_SDS_MODE_1_OFFSET 0 +#define RTL8367C_SDS_MODE_1_MASK 0x7 + +#define RTL8367C_REG_PHYSTS_CTRL0_1 0x1dc4 +#define RTL8367C_LNKUP_DLY_EN_EXT2_OFFSET 9 +#define RTL8367C_LNKUP_DLY_EN_EXT2_MASK 0x200 +#define RTL8367C_GE_100M_LNKUP_DLY_EXT2_OFFSET 7 +#define RTL8367C_GE_100M_LNKUP_DLY_EXT2_MASK 0x180 +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_OFFSET 5 +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT2_MASK 0x60 +#define RTL8367C_LNKUP_DLY_EN_EXT1_OFFSET 4 +#define RTL8367C_LNKUP_DLY_EN_EXT1_MASK 0x10 +#define RTL8367C_GE_100M_LNKUP_DLY_EXT1_OFFSET 2 +#define RTL8367C_GE_100M_LNKUP_DLY_EXT1_MASK 0xC +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_OFFSET 0 +#define RTL8367C_PHYSTS_10M_LNKUP_DLY_EXT1_MASK 0x3 + +#define RTL8367C_REG_FIBER_CFG_3_1 0x1dc5 +#define RTL8367C_FIBER_CFG_3_1_OFFSET 0 +#define RTL8367C_FIBER_CFG_3_1_MASK 0xFFF + +#define RTL8367C_REG_FIBER_CFG_4_1 0x1dc6 + +#define RTL8367C_REG_BUFF_RST_CTRL2_2 0x1dc7 +#define RTL8367C_Cfg_buffrst_sysover_thr_1_OFFSET 3 +#define RTL8367C_Cfg_buffrst_sysover_thr_1_MASK 0x8 +#define RTL8367C_Cfg_buffrst_qover_thr_OFFSET 2 +#define RTL8367C_Cfg_buffrst_qover_thr_MASK 0x4 +#define RTL8367C_Cfg_buffrst_indscover_thr_1_OFFSET 1 +#define RTL8367C_Cfg_buffrst_indscover_thr_1_MASK 0x2 +#define RTL8367C_Cfg_buffrst_dscover_thr_1_OFFSET 0 +#define RTL8367C_Cfg_buffrst_dscover_thr_1_MASK 0x1 + +#define RTL8367C_REG_PHY_DEBUG_CNT_CTRL 0x1dc8 +#define RTL8367C_PHY_MIB_RST_7_OFFSET 15 +#define RTL8367C_PHY_MIB_RST_7_MASK 0x8000 +#define RTL8367C_PHY_MIB_RST_6_OFFSET 14 +#define RTL8367C_PHY_MIB_RST_6_MASK 0x4000 +#define RTL8367C_PHY_MIB_RST_5_OFFSET 13 +#define RTL8367C_PHY_MIB_RST_5_MASK 0x2000 +#define RTL8367C_PHY_MIB_RST_4_OFFSET 12 +#define RTL8367C_PHY_MIB_RST_4_MASK 0x1000 +#define RTL8367C_PHY_MIB_RST_3_OFFSET 11 +#define RTL8367C_PHY_MIB_RST_3_MASK 0x800 +#define RTL8367C_PHY_MIB_RST_2_OFFSET 10 +#define RTL8367C_PHY_MIB_RST_2_MASK 0x400 +#define RTL8367C_PHY_MIB_RST_1_OFFSET 9 +#define RTL8367C_PHY_MIB_RST_1_MASK 0x200 +#define RTL8367C_PHY_MIB_RST_0_OFFSET 8 +#define RTL8367C_PHY_MIB_RST_0_MASK 0x100 +#define RTL8367C_PHY_MIB_EN_7_OFFSET 7 +#define RTL8367C_PHY_MIB_EN_7_MASK 0x80 +#define RTL8367C_PHY_MIB_EN_6_OFFSET 6 +#define RTL8367C_PHY_MIB_EN_6_MASK 0x40 +#define RTL8367C_PHY_MIB_EN_5_OFFSET 5 +#define RTL8367C_PHY_MIB_EN_5_MASK 0x20 +#define RTL8367C_PHY_MIB_EN_4_OFFSET 4 +#define RTL8367C_PHY_MIB_EN_4_MASK 0x10 +#define RTL8367C_PHY_MIB_EN_3_OFFSET 3 +#define RTL8367C_PHY_MIB_EN_3_MASK 0x8 +#define RTL8367C_PHY_MIB_EN_2_OFFSET 2 +#define RTL8367C_PHY_MIB_EN_2_MASK 0x4 +#define RTL8367C_PHY_MIB_EN_1_OFFSET 1 +#define RTL8367C_PHY_MIB_EN_1_MASK 0x2 +#define RTL8367C_PHY_MIB_EN_0_OFFSET 0 +#define RTL8367C_PHY_MIB_EN_0_MASK 0x1 + +#define RTL8367C_REG_TXPKT_CNT_L_0 0x1dc9 + +#define RTL8367C_REG_TXPKT_CNT_H_0 0x1dca + +#define RTL8367C_REG_RXPKT_CNT_L_0 0x1dcb + +#define RTL8367C_REG_RXPKT_CNT_H_0 0x1dcc + +#define RTL8367C_REG_TX_CRC_0 0x1dcd + +#define RTL8367C_REG_RX_CRC_0 0x1dce + +#define RTL8367C_REG_TXPKT_CNT_L_1 0x1dcf + +#define RTL8367C_REG_TXPKT_CNT_H_1 0x1dd0 + +#define RTL8367C_REG_RXPKT_CNT_L_1 0x1dd1 + +#define RTL8367C_REG_RXPKT_CNT_H_1 0x1dd2 + +#define RTL8367C_REG_TX_CRC_1 0x1dd3 + +#define RTL8367C_REG_RX_CRC_1 0x1dd4 + +#define RTL8367C_REG_TXPKT_CNT_L_2 0x1dd5 + +#define RTL8367C_REG_TXPKT_CNT_H_2 0x1dd6 + +#define RTL8367C_REG_RXPKT_CNT_L_2 0x1dd7 + +#define RTL8367C_REG_RXPKT_CNT_H_2 0x1dd8 + +#define RTL8367C_REG_TX_CRC_2 0x1dd9 + +#define RTL8367C_REG_RX_CRC_2 0x1dda + +#define RTL8367C_REG_TXPKT_CNT_L_3 0x1ddb + +#define RTL8367C_REG_TXPKT_CNT_H_3 0x1ddc + +#define RTL8367C_REG_RXPKT_CNT_L_3 0x1ddd + +#define RTL8367C_REG_RXPKT_CNT_H_3 0x1dde + +#define RTL8367C_REG_TX_CRC_3 0x1ddf + +#define RTL8367C_REG_RX_CRC_3 0x1de0 + +#define RTL8367C_REG_TXPKT_CNT_L_4 0x1de1 + +#define RTL8367C_REG_TXPKT_CNT_H_4 0x1de2 + +#define RTL8367C_REG_RXPKT_CNT_L_4 0x1de3 + +#define RTL8367C_REG_RXPKT_CNT_H_4 0x1de4 + +#define RTL8367C_REG_TX_CRC_4 0x1de5 + +#define RTL8367C_REG_RX_CRC_4 0x1de6 + +#define RTL8367C_REG_TXPKT_CNT_L_5 0x1de7 + +#define RTL8367C_REG_TXPKT_CNT_H_5 0x1de8 + +#define RTL8367C_REG_RXPKT_CNT_L_5 0x1de9 + +#define RTL8367C_REG_RXPKT_CNT_H_5 0x1dea + +#define RTL8367C_REG_TX_CRC_5 0x1deb + +#define RTL8367C_REG_RX_CRC_5 0x1dec + +#define RTL8367C_REG_TXPKT_CNT_L_6 0x1ded + +#define RTL8367C_REG_TXPKT_CNT_H_6 0x1dee + +#define RTL8367C_REG_RXPKT_CNT_L_6 0x1def + +#define RTL8367C_REG_RXPKT_CNT_H_6 0x1df0 + +#define RTL8367C_REG_TX_CRC_6 0x1df1 + +#define RTL8367C_REG_RX_CRC_6 0x1df2 + +#define RTL8367C_REG_TXPKT_CNT_L_7 0x1df3 + +#define RTL8367C_REG_TXPKT_CNT_H_7 0x1df4 + +#define RTL8367C_REG_RXPKT_CNT_L_7 0x1df5 + +#define RTL8367C_REG_RXPKT_CNT_H_7 0x1df6 + +#define RTL8367C_REG_TX_CRC_7 0x1df7 + +#define RTL8367C_REG_RX_CRC_7 0x1df8 + +#define RTL8367C_REG_BOND_DBG_0 0x1df9 + +#define RTL8367C_REG_BOND_DBG_1 0x1dfa + +#define RTL8367C_REG_STRP_DBG_0 0x1dfb + +#define RTL8367C_REG_STRP_DBG_1 0x1dfc + +#define RTL8367C_REG_STRP_DBG_2 0x1dfd + +/* (16'h1f00)patch_reg */ + +#define RTL8367C_REG_INDRECT_ACCESS_CTRL 0x1f00 +#define RTL8367C_RW_OFFSET 1 +#define RTL8367C_RW_MASK 0x2 +#define RTL8367C_CMD_OFFSET 0 +#define RTL8367C_CMD_MASK 0x1 + +#define RTL8367C_REG_INDRECT_ACCESS_STATUS 0x1f01 +#define RTL8367C_INDRECT_ACCESS_STATUS_OFFSET 2 +#define RTL8367C_INDRECT_ACCESS_STATUS_MASK 0x7 + +#define RTL8367C_REG_INDRECT_ACCESS_ADDRESS 0x1f02 + +#define RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA 0x1f03 + +#define RTL8367C_REG_INDRECT_ACCESS_READ_DATA 0x1f04 + +/* (16'h6200)fib_page */ + +#define RTL8367C_REG_FIB0_CFG00 0x6200 +#define RTL8367C_FIB0_CFG00_CFG_FIB_RST_OFFSET 15 +#define RTL8367C_FIB0_CFG00_CFG_FIB_RST_MASK 0x8000 +#define RTL8367C_FIB0_CFG00_CFG_FIB_LPK_OFFSET 14 +#define RTL8367C_FIB0_CFG00_CFG_FIB_LPK_MASK 0x4000 +#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_OFFSET 13 +#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_0_MASK 0x2000 +#define RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_OFFSET 12 +#define RTL8367C_FIB0_CFG00_CFG_FIB_ANEN_MASK 0x1000 +#define RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_OFFSET 11 +#define RTL8367C_FIB0_CFG00_CFG_FIB_PDOWN_MASK 0x800 +#define RTL8367C_FIB0_CFG00_CFG_FIB_ISO_OFFSET 10 +#define RTL8367C_FIB0_CFG00_CFG_FIB_ISO_MASK 0x400 +#define RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_OFFSET 9 +#define RTL8367C_FIB0_CFG00_CFG_FIB_RESTART_MASK 0x200 +#define RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_OFFSET 8 +#define RTL8367C_FIB0_CFG00_CFG_FIB_FULLDUP_MASK 0x100 +#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_OFFSET 6 +#define RTL8367C_FIB0_CFG00_CFG_FIB_SPD_RD_1_MASK 0x40 +#define RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_OFFSET 5 +#define RTL8367C_FIB0_CFG00_CFG_FIB_FRCTX_MASK 0x20 + +#define RTL8367C_REG_FIB0_CFG01 0x6201 +#define RTL8367C_FIB0_CFG01_CAPBILITY_OFFSET 6 +#define RTL8367C_FIB0_CFG01_CAPBILITY_MASK 0xFFC0 +#define RTL8367C_FIB0_CFG01_AN_COMPLETE_OFFSET 5 +#define RTL8367C_FIB0_CFG01_AN_COMPLETE_MASK 0x20 +#define RTL8367C_FIB0_CFG01_R_FAULT_OFFSET 4 +#define RTL8367C_FIB0_CFG01_R_FAULT_MASK 0x10 +#define RTL8367C_FIB0_CFG01_NWAY_ABILITY_OFFSET 3 +#define RTL8367C_FIB0_CFG01_NWAY_ABILITY_MASK 0x8 +#define RTL8367C_FIB0_CFG01_LINK_STATUS_OFFSET 2 +#define RTL8367C_FIB0_CFG01_LINK_STATUS_MASK 0x4 +#define RTL8367C_FIB0_CFG01_JABBER_DETECT_OFFSET 1 +#define RTL8367C_FIB0_CFG01_JABBER_DETECT_MASK 0x2 +#define RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_OFFSET 0 +#define RTL8367C_FIB0_CFG01_EXTENDED_CAPBILITY_MASK 0x1 + +#define RTL8367C_REG_FIB0_CFG02 0x6202 + +#define RTL8367C_REG_FIB0_CFG03 0x6203 +#define RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_OFFSET 10 +#define RTL8367C_FIB0_CFG03_REALTEK_OUI5_0_MASK 0xFC00 +#define RTL8367C_FIB0_CFG03_MODEL_NO_OFFSET 4 +#define RTL8367C_FIB0_CFG03_MODEL_NO_MASK 0x3F0 +#define RTL8367C_FIB0_CFG03_REVISION_NO_OFFSET 0 +#define RTL8367C_FIB0_CFG03_REVISION_NO_MASK 0xF + +#define RTL8367C_REG_FIB0_CFG04 0x6204 + +#define RTL8367C_REG_FIB0_CFG05 0x6205 + +#define RTL8367C_REG_FIB0_CFG06 0x6206 +#define RTL8367C_FIB0_CFG06_FIB_NP_EN_OFFSET 2 +#define RTL8367C_FIB0_CFG06_FIB_NP_EN_MASK 0x4 +#define RTL8367C_FIB0_CFG06_RXPAGE_OFFSET 1 +#define RTL8367C_FIB0_CFG06_RXPAGE_MASK 0x2 + +#define RTL8367C_REG_FIB0_CFG07 0x6207 + +#define RTL8367C_REG_FIB0_CFG08 0x6208 + +#define RTL8367C_REG_FIB0_CFG09 0x6209 + +#define RTL8367C_REG_FIB0_CFG10 0x620a + +#define RTL8367C_REG_FIB0_CFG11 0x620b + +#define RTL8367C_REG_FIB0_CFG12 0x620c + +#define RTL8367C_REG_FIB0_CFG13 0x620d +#define RTL8367C_FIB0_CFG13_INDR_FUNC_OFFSET 14 +#define RTL8367C_FIB0_CFG13_INDR_FUNC_MASK 0xC000 +#define RTL8367C_FIB0_CFG13_DUMMY_OFFSET 5 +#define RTL8367C_FIB0_CFG13_DUMMY_MASK 0x3FE0 +#define RTL8367C_FIB0_CFG13_INDR_DEVAD_OFFSET 0 +#define RTL8367C_FIB0_CFG13_INDR_DEVAD_MASK 0x1F + +#define RTL8367C_REG_FIB0_CFG14 0x620e + +#define RTL8367C_REG_FIB0_CFG15 0x620f + +#define RTL8367C_REG_FIB1_CFG00 0x6210 +#define RTL8367C_FIB1_CFG00_CFG_FIB_RST_OFFSET 15 +#define RTL8367C_FIB1_CFG00_CFG_FIB_RST_MASK 0x8000 +#define RTL8367C_FIB1_CFG00_CFG_FIB_LPK_OFFSET 14 +#define RTL8367C_FIB1_CFG00_CFG_FIB_LPK_MASK 0x4000 +#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_OFFSET 13 +#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_0_MASK 0x2000 +#define RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_OFFSET 12 +#define RTL8367C_FIB1_CFG00_CFG_FIB_ANEN_MASK 0x1000 +#define RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_OFFSET 11 +#define RTL8367C_FIB1_CFG00_CFG_FIB_PDOWN_MASK 0x800 +#define RTL8367C_FIB1_CFG00_CFG_FIB_ISO_OFFSET 10 +#define RTL8367C_FIB1_CFG00_CFG_FIB_ISO_MASK 0x400 +#define RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_OFFSET 9 +#define RTL8367C_FIB1_CFG00_CFG_FIB_RESTART_MASK 0x200 +#define RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_OFFSET 8 +#define RTL8367C_FIB1_CFG00_CFG_FIB_FULLDUP_MASK 0x100 +#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_OFFSET 6 +#define RTL8367C_FIB1_CFG00_CFG_FIB_SPD_RD_1_MASK 0x40 +#define RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_OFFSET 5 +#define RTL8367C_FIB1_CFG00_CFG_FIB_FRCTX_MASK 0x20 + +#define RTL8367C_REG_FIB1_CFG01 0x6211 +#define RTL8367C_FIB1_CFG01_CAPBILITY_OFFSET 6 +#define RTL8367C_FIB1_CFG01_CAPBILITY_MASK 0xFFC0 +#define RTL8367C_FIB1_CFG01_AN_COMPLETE_OFFSET 5 +#define RTL8367C_FIB1_CFG01_AN_COMPLETE_MASK 0x20 +#define RTL8367C_FIB1_CFG01_R_FAULT_OFFSET 4 +#define RTL8367C_FIB1_CFG01_R_FAULT_MASK 0x10 +#define RTL8367C_FIB1_CFG01_NWAY_ABILITY_OFFSET 3 +#define RTL8367C_FIB1_CFG01_NWAY_ABILITY_MASK 0x8 +#define RTL8367C_FIB1_CFG01_LINK_STATUS_OFFSET 2 +#define RTL8367C_FIB1_CFG01_LINK_STATUS_MASK 0x4 +#define RTL8367C_FIB1_CFG01_JABBER_DETECT_OFFSET 1 +#define RTL8367C_FIB1_CFG01_JABBER_DETECT_MASK 0x2 +#define RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_OFFSET 0 +#define RTL8367C_FIB1_CFG01_EXTENDED_CAPBILITY_MASK 0x1 + +#define RTL8367C_REG_FIB1_CFG02 0x6212 + +#define RTL8367C_REG_FIB1_CFG03 0x6213 +#define RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_OFFSET 10 +#define RTL8367C_FIB1_CFG03_REALTEK_OUI5_0_MASK 0xFC00 +#define RTL8367C_FIB1_CFG03_MODEL_NO_OFFSET 4 +#define RTL8367C_FIB1_CFG03_MODEL_NO_MASK 0x3F0 +#define RTL8367C_FIB1_CFG03_REVISION_NO_OFFSET 0 +#define RTL8367C_FIB1_CFG03_REVISION_NO_MASK 0xF + +#define RTL8367C_REG_FIB1_CFG04 0x6214 + +#define RTL8367C_REG_FIB1_CFG05 0x6215 + +#define RTL8367C_REG_FIB1_CFG06 0x6216 +#define RTL8367C_FIB1_CFG06_FIB_NP_EN_OFFSET 2 +#define RTL8367C_FIB1_CFG06_FIB_NP_EN_MASK 0x4 +#define RTL8367C_FIB1_CFG06_RXPAGE_OFFSET 1 +#define RTL8367C_FIB1_CFG06_RXPAGE_MASK 0x2 + +#define RTL8367C_REG_FIB1_CFG07 0x6217 + +#define RTL8367C_REG_FIB1_CFG08 0x6218 + +#define RTL8367C_REG_FIB1_CFG09 0x6219 + +#define RTL8367C_REG_FIB1_CFG10 0x621a + +#define RTL8367C_REG_FIB1_CFG11 0x621b + +#define RTL8367C_REG_FIB1_CFG12 0x621c + +#define RTL8367C_REG_FIB1_CFG13 0x621d +#define RTL8367C_FIB1_CFG13_INDR_FUNC_OFFSET 14 +#define RTL8367C_FIB1_CFG13_INDR_FUNC_MASK 0xC000 +#define RTL8367C_FIB1_CFG13_DUMMY_OFFSET 5 +#define RTL8367C_FIB1_CFG13_DUMMY_MASK 0x3FE0 +#define RTL8367C_FIB1_CFG13_INDR_DEVAD_OFFSET 0 +#define RTL8367C_FIB1_CFG13_INDR_DEVAD_MASK 0x1F + +#define RTL8367C_REG_FIB1_CFG14 0x621e + +#define RTL8367C_REG_FIB1_CFG15 0x621f + +/* (16'h6400)timer_1588 */ + +#define RTL8367C_REG_PTP_TIME_NSEC_L_NSEC 0x6400 + +#define RTL8367C_REG_PTP_TIME_NSEC_H_NSEC 0x6401 +#define RTL8367C_PTP_TIME_NSEC_H_EXEC_OFFSET 15 +#define RTL8367C_PTP_TIME_NSEC_H_EXEC_MASK 0x8000 +#define RTL8367C_PTP_TIME_NSEC_H_CMD_OFFSET 12 +#define RTL8367C_PTP_TIME_NSEC_H_CMD_MASK 0x3000 +#define RTL8367C_PTP_TIME_NSEC_H_NSEC_OFFSET 0 +#define RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK 0x7FF + +#define RTL8367C_REG_PTP_TIME_SEC_L_SEC 0x6402 + +#define RTL8367C_REG_PTP_TIME_SEC_H_SEC 0x6403 + +#define RTL8367C_REG_PTP_TIME_CFG 0x6404 +#define RTL8367C_CFG_TIMER_EN_FRC_OFFSET 2 +#define RTL8367C_CFG_TIMER_EN_FRC_MASK 0x4 +#define RTL8367C_CFG_TIMER_1588_EN_OFFSET 1 +#define RTL8367C_CFG_TIMER_1588_EN_MASK 0x2 +#define RTL8367C_CFG_CLK_SRC_OFFSET 0 +#define RTL8367C_CFG_CLK_SRC_MASK 0x1 + +#define RTL8367C_REG_OTAG_TPID 0x6405 + +#define RTL8367C_REG_ITAG_TPID 0x6406 + +#define RTL8367C_REG_MAC_ADDR_L 0x6407 + +#define RTL8367C_REG_MAC_ADDR_M 0x6408 + +#define RTL8367C_REG_MAC_ADDR_H 0x6409 + +#define RTL8367C_REG_PTP_TIME_NSEC_L_NSEC_RD 0x640a + +#define RTL8367C_REG_PTP_TIME_NSEC_H_NSEC_RD 0x640b +#define RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_OFFSET 0 +#define RTL8367C_PTP_TIME_NSEC_H_NSEC_RD_MASK 0x7FF + +#define RTL8367C_REG_PTP_TIME_SEC_L_SEC_RD 0x640c + +#define RTL8367C_REG_PTP_TIME_SEC_H_SEC_RD 0x640d + +#define RTL8367C_REG_PTP_TIME_CFG2 0x640e +#define RTL8367C_CFG_EN_OFFLOAD_OFFSET 9 +#define RTL8367C_CFG_EN_OFFLOAD_MASK 0x200 +#define RTL8367C_CFG_SAVE_OFF_TS_OFFSET 8 +#define RTL8367C_CFG_SAVE_OFF_TS_MASK 0x100 +#define RTL8367C_CFG_IMR_OFFSET 0 +#define RTL8367C_CFG_IMR_MASK 0xFF + +#define RTL8367C_REG_PTP_INTERRUPT_CFG 0x640f +#define RTL8367C_P9_INTERRUPT_OFFSET 9 +#define RTL8367C_P9_INTERRUPT_MASK 0x200 +#define RTL8367C_P8_INTERRUPT_OFFSET 8 +#define RTL8367C_P8_INTERRUPT_MASK 0x100 +#define RTL8367C_P7_INTERRUPT_OFFSET 7 +#define RTL8367C_P7_INTERRUPT_MASK 0x80 +#define RTL8367C_P6_INTERRUPT_OFFSET 6 +#define RTL8367C_P6_INTERRUPT_MASK 0x40 +#define RTL8367C_P5_INTERRUPT_OFFSET 5 +#define RTL8367C_P5_INTERRUPT_MASK 0x20 +#define RTL8367C_P4_INTERRUPT_OFFSET 4 +#define RTL8367C_P4_INTERRUPT_MASK 0x10 +#define RTL8367C_P3_INTERRUPT_OFFSET 3 +#define RTL8367C_P3_INTERRUPT_MASK 0x8 +#define RTL8367C_P2_INTERRUPT_OFFSET 2 +#define RTL8367C_P2_INTERRUPT_MASK 0x4 +#define RTL8367C_P1_INTERRUPT_OFFSET 1 +#define RTL8367C_P1_INTERRUPT_MASK 0x2 +#define RTL8367C_P0_INTERRUPT_OFFSET 0 +#define RTL8367C_P0_INTERRUPT_MASK 0x1 + +#define RTL8367C_REG_P0_TX_SYNC_SEQ_ID 0x6410 + +#define RTL8367C_REG_P0_TX_DELAY_REQ_SEQ_ID 0x6411 + +#define RTL8367C_REG_P0_TX_PDELAY_REQ_SEQ_ID 0x6412 + +#define RTL8367C_REG_P0_TX_PDELAY_RESP_SEQ_ID 0x6413 + +#define RTL8367C_REG_P0_RX_SYNC_SEQ_ID 0x6414 + +#define RTL8367C_REG_P0_RX_DELAY_REQ_SEQ_ID 0x6415 + +#define RTL8367C_REG_P0_RX_PDELAY_REQ_SEQ_ID 0x6416 + +#define RTL8367C_REG_P0_RX_PDELAY_RESP_SEQ_ID 0x6417 + +#define RTL8367C_REG_P0_PORT_NSEC_15_0 0x6418 + +#define RTL8367C_REG_P0_PORT_NSEC_26_16 0x6419 +#define RTL8367C_P0_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P0_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P0_PORT_SEC_15_0 0x641a + +#define RTL8367C_REG_P0_PORT_SEC_31_16 0x641b + +#define RTL8367C_REG_P0_EAV_CFG 0x641c +#define RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P0_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P0_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P0_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P0_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P0_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P0_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P0_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P0_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P0_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P0_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P0_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P1_TX_SYNC_SEQ_ID 0x6420 + +#define RTL8367C_REG_P1_TX_DELAY_REQ_SEQ_ID 0x6421 + +#define RTL8367C_REG_P1_TX_PDELAY_REQ_SEQ_ID 0x6422 + +#define RTL8367C_REG_P1_TX_PDELAY_RESP_SEQ_ID 0x6423 + +#define RTL8367C_REG_P1_RX_SYNC_SEQ_ID 0x6424 + +#define RTL8367C_REG_P1_RX_DELAY_REQ_SEQ_ID 0x6425 + +#define RTL8367C_REG_P1_RX_PDELAY_REQ_SEQ_ID 0x6426 + +#define RTL8367C_REG_P1_RX_PDELAY_RESP_SEQ_ID 0x6427 + +#define RTL8367C_REG_P1_PORT_NSEC_15_0 0x6428 + +#define RTL8367C_REG_P1_PORT_NSEC_26_16 0x6429 +#define RTL8367C_P1_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P1_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P1_PORT_SEC_15_0 0x642a + +#define RTL8367C_REG_P1_PORT_SEC_31_16 0x642b + +#define RTL8367C_REG_P1_EAV_CFG 0x642c +#define RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P1_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P1_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P1_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P1_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P1_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P1_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P1_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P1_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P1_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P1_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P1_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P2_TX_SYNC_SEQ_ID 0x6430 + +#define RTL8367C_REG_P2_TX_DELAY_REQ_SEQ_ID 0x6431 + +#define RTL8367C_REG_P2_TX_PDELAY_REQ_SEQ_ID 0x6432 + +#define RTL8367C_REG_P2_TX_PDELAY_RESP_SEQ_ID 0x6433 + +#define RTL8367C_REG_P2_RX_SYNC_SEQ_ID 0x6434 + +#define RTL8367C_REG_P2_RX_DELAY_REQ_SEQ_ID 0x6435 + +#define RTL8367C_REG_P2_RX_PDELAY_REQ_SEQ_ID 0x6436 + +#define RTL8367C_REG_P2_RX_PDELAY_RESP_SEQ_ID 0x6437 + +#define RTL8367C_REG_P2_PORT_NSEC_15_0 0x6438 + +#define RTL8367C_REG_P2_PORT_NSEC_26_16 0x6439 +#define RTL8367C_P2_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P2_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P2_PORT_SEC_15_0 0x643a + +#define RTL8367C_REG_P2_PORT_SEC_31_16 0x643b + +#define RTL8367C_REG_P2_EAV_CFG 0x643c +#define RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P2_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P2_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P2_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P2_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P2_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P2_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P2_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P2_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P2_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P2_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P2_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P3_TX_SYNC_SEQ_ID 0x6440 + +#define RTL8367C_REG_P3_TX_DELAY_REQ_SEQ_ID 0x6441 + +#define RTL8367C_REG_P3_TX_PDELAY_REQ_SEQ_ID 0x6442 + +#define RTL8367C_REG_P3_TX_PDELAY_RESP_SEQ_ID 0x6443 + +#define RTL8367C_REG_P3_RX_SYNC_SEQ_ID 0x6444 + +#define RTL8367C_REG_P3_RX_DELAY_REQ_SEQ_ID 0x6445 + +#define RTL8367C_REG_P3_RX_PDELAY_REQ_SEQ_ID 0x6446 + +#define RTL8367C_REG_P3_RX_PDELAY_RESP_SEQ_ID 0x6447 + +#define RTL8367C_REG_P3_PORT_NSEC_15_0 0x6448 + +#define RTL8367C_REG_P3_PORT_NSEC_26_16 0x6449 +#define RTL8367C_P3_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P3_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P3_PORT_SEC_15_0 0x644a + +#define RTL8367C_REG_P3_PORT_SEC_31_16 0x644b + +#define RTL8367C_REG_P3_EAV_CFG 0x644c +#define RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P3_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P3_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P3_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P3_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P3_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P3_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P3_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P3_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P3_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P3_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P3_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P4_TX_SYNC_SEQ_ID 0x6450 + +#define RTL8367C_REG_P4_TX_DELAY_REQ_SEQ_ID 0x6451 + +#define RTL8367C_REG_P4_TX_PDELAY_REQ_SEQ_ID 0x6452 + +#define RTL8367C_REG_P4_TX_PDELAY_RESP_SEQ_ID 0x6453 + +#define RTL8367C_REG_P4_RX_SYNC_SEQ_ID 0x6454 + +#define RTL8367C_REG_P4_RX_DELAY_REQ_SEQ_ID 0x6455 + +#define RTL8367C_REG_P4_RX_PDELAY_REQ_SEQ_ID 0x6456 + +#define RTL8367C_REG_P4_RX_PDELAY_RESP_SEQ_ID 0x6457 + +#define RTL8367C_REG_P4_PORT_NSEC_15_0 0x6458 + +#define RTL8367C_REG_P4_PORT_NSEC_26_16 0x6459 +#define RTL8367C_P4_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P4_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P4_PORT_SEC_15_0 0x645a + +#define RTL8367C_REG_P4_PORT_SEC_31_16 0x645b + +#define RTL8367C_REG_P4_EAV_CFG 0x645c +#define RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P4_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P4_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P4_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P4_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P4_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P4_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P4_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P4_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P4_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P4_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P4_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P6_TX_SYNC_SEQ_ID 0x6460 + +#define RTL8367C_REG_P6_TX_DELAY_REQ_SEQ_ID 0x6461 + +#define RTL8367C_REG_P6_TX_PDELAY_REQ_SEQ_ID 0x6462 + +#define RTL8367C_REG_P6_TX_PDELAY_RESP_SEQ_ID 0x6463 + +#define RTL8367C_REG_P6_RX_SYNC_SEQ_ID 0x6464 + +#define RTL8367C_REG_P6_RX_DELAY_REQ_SEQ_ID 0x6465 + +#define RTL8367C_REG_P6_RX_PDELAY_REQ_SEQ_ID 0x6466 + +#define RTL8367C_REG_P6_RX_PDELAY_RESP_SEQ_ID 0x6467 + +#define RTL8367C_REG_P6_PORT_NSEC_15_0 0x6468 + +#define RTL8367C_REG_P6_PORT_NSEC_26_16 0x6469 +#define RTL8367C_P6_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P6_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P6_PORT_SEC_15_0 0x646a + +#define RTL8367C_REG_P6_PORT_SEC_31_16 0x646b + +#define RTL8367C_REG_P6_EAV_CFG 0x646c +#define RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P6_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P6_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P6_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P6_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P6_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P6_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P6_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P6_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P6_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P6_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P6_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P7_TX_SYNC_SEQ_ID 0x6470 + +#define RTL8367C_REG_P7_TX_DELAY_REQ_SEQ_ID 0x6471 + +#define RTL8367C_REG_P7_TX_PDELAY_REQ_SEQ_ID 0x6472 + +#define RTL8367C_REG_P7_TX_PDELAY_RESP_SEQ_ID 0x6473 + +#define RTL8367C_REG_P7_RX_SYNC_SEQ_ID 0x6474 + +#define RTL8367C_REG_P7_RX_DELAY_REQ_SEQ_ID 0x6475 + +#define RTL8367C_REG_P7_RX_PDELAY_REQ_SEQ_ID 0x6476 + +#define RTL8367C_REG_P7_RX_PDELAY_RESP_SEQ_ID 0x6477 + +#define RTL8367C_REG_P7_PORT_NSEC_15_0 0x6478 + +#define RTL8367C_REG_P7_PORT_NSEC_26_16 0x6479 +#define RTL8367C_P7_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P7_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P7_PORT_SEC_15_0 0x647a + +#define RTL8367C_REG_P7_PORT_SEC_31_16 0x647b + +#define RTL8367C_REG_P7_EAV_CFG 0x647c +#define RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P7_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P7_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P7_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P7_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P7_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P7_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P7_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P7_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P7_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P7_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P7_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P5_TX_SYNC_SEQ_ID 0x6480 + +#define RTL8367C_REG_P5_TX_DELAY_REQ_SEQ_ID 0x6481 + +#define RTL8367C_REG_P5_TX_PDELAY_REQ_SEQ_ID 0x6482 + +#define RTL8367C_REG_P5_TX_PDELAY_RESP_SEQ_ID 0x6483 + +#define RTL8367C_REG_P5_RX_SYNC_SEQ_ID 0x6484 + +#define RTL8367C_REG_P5_RX_DELAY_REQ_SEQ_ID 0x6485 + +#define RTL8367C_REG_P5_RX_PDELAY_REQ_SEQ_ID 0x6486 + +#define RTL8367C_REG_P5_RX_PDELAY_RESP_SEQ_ID 0x6487 + +#define RTL8367C_REG_P5_PORT_NSEC_15_0 0x6488 + +#define RTL8367C_REG_P5_PORT_NSEC_26_16 0x6489 +#define RTL8367C_P5_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P5_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P5_PORT_SEC_15_0 0x648a + +#define RTL8367C_REG_P5_PORT_SEC_31_16 0x648b + +#define RTL8367C_REG_P5_EAV_CFG 0x648c +#define RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P5_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P5_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P5_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P5_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P5_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P5_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P5_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P5_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P5_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P5_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P5_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P8_TX_SYNC_SEQ_ID 0x6490 + +#define RTL8367C_REG_P8_TX_DELAY_REQ_SEQ_ID 0x6491 + +#define RTL8367C_REG_P8_TX_PDELAY_REQ_SEQ_ID 0x6492 + +#define RTL8367C_REG_P8_TX_PDELAY_RESP_SEQ_ID 0x6493 + +#define RTL8367C_REG_P8_RX_SYNC_SEQ_ID 0x6494 + +#define RTL8367C_REG_P8_RX_DELAY_REQ_SEQ_ID 0x6495 + +#define RTL8367C_REG_P8_RX_PDELAY_REQ_SEQ_ID 0x6496 + +#define RTL8367C_REG_P8_RX_PDELAY_RESP_SEQ_ID 0x6497 + +#define RTL8367C_REG_P8_PORT_NSEC_15_0 0x6498 + +#define RTL8367C_REG_P8_PORT_NSEC_26_16 0x6499 +#define RTL8367C_P8_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P8_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P8_PORT_SEC_15_0 0x649a + +#define RTL8367C_REG_P8_PORT_SEC_31_16 0x649b + +#define RTL8367C_REG_P8_EAV_CFG 0x649c +#define RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P8_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P8_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P8_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P8_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P8_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P8_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P8_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P8_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P8_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P8_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P8_EAV_CFG_TX_SYNC_MASK 0x1 + +#define RTL8367C_REG_P9_TX_SYNC_SEQ_ID 0x64a0 + +#define RTL8367C_REG_P9_TX_DELAY_REQ_SEQ_ID 0x64a1 + +#define RTL8367C_REG_P9_TX_PDELAY_REQ_SEQ_ID 0x64a2 + +#define RTL8367C_REG_P9_TX_PDELAY_RESP_SEQ_ID 0x64a3 + +#define RTL8367C_REG_P9_RX_SYNC_SEQ_ID 0x64a4 + +#define RTL8367C_REG_P9_RX_DELAY_REQ_SEQ_ID 0x64a5 + +#define RTL8367C_REG_P9_RX_PDELAY_REQ_SEQ_ID 0x64a6 + +#define RTL8367C_REG_P9_RX_PDELAY_RESP_SEQ_ID 0x64a7 + +#define RTL8367C_REG_P9_PORT_NSEC_15_0 0x64a8 + +#define RTL8367C_REG_P9_PORT_NSEC_26_16 0x64a9 +#define RTL8367C_P9_PORT_NSEC_26_16_OFFSET 0 +#define RTL8367C_P9_PORT_NSEC_26_16_MASK 0x7FF + +#define RTL8367C_REG_P9_PORT_SEC_15_0 0x64aa + +#define RTL8367C_REG_P9_PORT_SEC_31_16 0x64ab + +#define RTL8367C_REG_P9_EAV_CFG 0x64ac +#define RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_OFFSET 8 +#define RTL8367C_P9_EAV_CFG_PTP_PHY_EN_EN_MASK 0x100 +#define RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_OFFSET 7 +#define RTL8367C_P9_EAV_CFG_RX_PDELAY_RESP_MASK 0x80 +#define RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_OFFSET 6 +#define RTL8367C_P9_EAV_CFG_RX_PDELAY_REQ_MASK 0x40 +#define RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_OFFSET 5 +#define RTL8367C_P9_EAV_CFG_RX_DELAY_REQ_MASK 0x20 +#define RTL8367C_P9_EAV_CFG_RX_SYNC_OFFSET 4 +#define RTL8367C_P9_EAV_CFG_RX_SYNC_MASK 0x10 +#define RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_OFFSET 3 +#define RTL8367C_P9_EAV_CFG_TX_PDELAY_RESP_MASK 0x8 +#define RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_OFFSET 2 +#define RTL8367C_P9_EAV_CFG_TX_PDELAY_REQ_MASK 0x4 +#define RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_OFFSET 1 +#define RTL8367C_P9_EAV_CFG_TX_DELAY_REQ_MASK 0x2 +#define RTL8367C_P9_EAV_CFG_TX_SYNC_OFFSET 0 +#define RTL8367C_P9_EAV_CFG_TX_SYNC_MASK 0x1 + +/* (16'h6600)sds_indacs_reg */ + +#define RTL8367C_REG_SDS_INDACS_CMD 0x6600 +#define RTL8367C_SDS_CMD_BUSY_OFFSET 8 +#define RTL8367C_SDS_CMD_BUSY_MASK 0x100 +#define RTL8367C_SDS_CMD_OFFSET 7 +#define RTL8367C_SDS_CMD_MASK 0x80 +#define RTL8367C_SDS_RWOP_OFFSET 6 +#define RTL8367C_SDS_RWOP_MASK 0x40 +#define RTL8367C_SDS_INDEX_OFFSET 0 +#define RTL8367C_SDS_INDEX_MASK 0x3F + +#define RTL8367C_REG_SDS_INDACS_ADR 0x6601 +#define RTL8367C_SDS_PAGE_OFFSET 5 +#define RTL8367C_SDS_PAGE_MASK 0x7E0 +#define RTL8367C_SDS_REGAD_OFFSET 0 +#define RTL8367C_SDS_REGAD_MASK 0x1F + +#define RTL8367C_REG_SDS_INDACS_DATA 0x6602 + + +#endif /*#ifndef _RTL8367C_REG_H_*/ + diff --git a/drivers/net/phy/rtk/rtl8367c/include/smi.h b/drivers/net/phy/rtk/rtl8367c/include/smi.h new file mode 100644 index 000000000000..b77d7607113e --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/smi.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367C switch low-level function for access register + * Feature : SMI related functions + * + */ + +#ifndef __SMI_H__ +#define __SMI_H__ + +#include +#include "rtk_error.h" + +#define MDC_MDIO_CTRL0_REG 31 +#define MDC_MDIO_START_REG 29 +#define MDC_MDIO_CTRL1_REG 21 +#define MDC_MDIO_ADDRESS_REG 23 +#define MDC_MDIO_DATA_WRITE_REG 24 +#define MDC_MDIO_DATA_READ_REG 25 +#define MDC_MDIO_PREAMBLE_LEN 32 + +#define MDC_MDIO_START_OP 0xFFFF +#define MDC_MDIO_ADDR_OP 0x000E +#define MDC_MDIO_READ_OP 0x0001 +#define MDC_MDIO_WRITE_OP 0x0003 + +#define SPI_READ_OP 0x3 +#define SPI_WRITE_OP 0x2 +#define SPI_READ_OP_LEN 0x8 +#define SPI_WRITE_OP_LEN 0x8 +#define SPI_REG_LEN 16 +#define SPI_DATA_LEN 16 + +#define GPIO_DIR_IN 1 +#define GPIO_DIR_OUT 0 + +#define ack_timer 5 + +#define DELAY 10000 +#define CLK_DURATION(clk) { int i; for(i=0; isvid is SVID of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. + */ +extern rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *psvlan_cfg); + +/* Function Name: + * rtk_svlan_memberPortEntry_get + * Description: + * Get SVLAN member Configure. + * Input: + * svid - SVLAN id + * Output: + * pSvlan_cfg - SVLAN member configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted + * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped. + */ +extern rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_uint32 svid_idx, rtk_svlan_memberCfg_t *pSvlan_cfg); + +/* Function Name: + * rtk_svlan_memberPortEntry_adv_set + * Description: + * Configure system SVLAN member by index + * Input: + * idx - Index (0 ~ 63) + * psvlan_cfg - SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. + * Note: + * The API can set system 64 accepted s-tag frame format by index. + * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. + */ +extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg); + +/* Function Name: + * rtk_svlan_memberPortEntry_adv_get + * Description: + * Get SVLAN member Configure by index. + * Input: + * idx - Index (0 ~ 63) + * Output: + * pSvlan_cfg - SVLAN member configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accpeted + * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be droped. + */ +extern rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg); + +/* Function Name: + * rtk_svlan_defaultSvlan_set + * Description: + * Configure default egress SVLAN. + * Input: + * port - Source port + * svid - SVLAN id + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * Note: + * The API can set port n S-tag format index while receiving frame from port n + * is transmit through uplink port with s-tag field + */ +extern rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_defaultSvlan_get + * Description: + * Get the configure default egress SVLAN. + * Input: + * port - Source port + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get port n S-tag format index while receiving frame from port n + * is transmit through uplink port with s-tag field + */ +extern rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_c2s_add + * Description: + * Configure SVLAN C2S table + * Input: + * vid - VLAN ID + * src_port - Ingress Port + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set system C2S configuration. ASIC will check upstream's VID and assign related + * SVID to mathed packet. There are 128 SVLAN C2S configurations. + */ +extern rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_c2s_del + * Description: + * Delete one C2S entry + * Input: + * vid - VLAN ID + * src_port - Ingress Port + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete system C2S configuration. There are 128 SVLAN C2S configurations. + */ +extern rtk_api_ret_t rtk_svlan_c2s_del(rtk_vlan_t vid, rtk_port_t src_port); + +/* Function Name: + * rtk_svlan_c2s_get + * Description: + * Get configure SVLAN C2S table + * Input: + * vid - VLAN ID + * src_port - Ingress Port + * Output: + * pSvid - SVLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get system C2S configuration. There are 128 SVLAN C2S configurations. + */ +extern rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_untag_action_set + * Description: + * Configure Action of downstream Un-Stag packet + * Input: + * action - Action for UnStag + * svid - The SVID assigned to UnStag packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of downstream Un-Stag packet. A SVID assigned + * to the un-stag is also supported by this API. The parameter of svid is + * only referenced when the action is set to UNTAG_ASSIGN + */ +extern rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_untag_action_get + * Description: + * Get Action of downstream Un-Stag packet + * Input: + * None + * Output: + * pAction - Action for UnStag + * pSvid - The SVID assigned to UnStag packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can Get action of downstream Un-Stag packet. A SVID assigned + * to the un-stag is also retrieved by this API. The parameter pSvid is + * only refernced when the action is UNTAG_ASSIGN + */ +extern rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_unmatch_action_set + * Description: + * Configure Action of downstream Unmatch packet + * Input: + * action - Action for Unmatch + * svid - The SVID assigned to Unmatch packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of downstream Un-match packet. A SVID assigned + * to the un-match is also supported by this API. The parameter od svid is + * only refernced when the action is set to UNMATCH_ASSIGN + */ +extern rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_unmatch_action_get + * Description: + * Get Action of downstream Unmatch packet + * Input: + * None + * Output: + * pAction - Action for Unmatch + * pSvid - The SVID assigned to Unmatch packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can Get action of downstream Un-match packet. A SVID assigned + * to the un-match is also retrieved by this API. The parameter pSvid is + * only refernced when the action is UNMATCH_ASSIGN + */ +extern rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_dmac_vidsel_set + * Description: + * Set DMAC CVID selection + * Input: + * port - Port + * enable - state of DMAC CVID Selection + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set DMAC CVID Selection state + */ +extern rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_svlan_dmac_vidsel_get + * Description: + * Get DMAC CVID selection + * Input: + * port - Port + * Output: + * pEnable - state of DMAC CVID Selection + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get DMAC CVID Selection state + */ +extern rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_svlan_ipmc2s_add + * Description: + * add ip multicast address to SVLAN + * Input: + * svid - SVLAN VID + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set IP mutlicast to SVID configuration. If upstream packet is IPv4 multicast + * packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet. + * There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_ipmc2s_del + * Description: + * delete ip multicast address to SVLAN + * Input: + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk); + +/* Function Name: + * rtk_svlan_ipmc2s_get + * Description: + * Get ip multicast address to SVLAN + * Input: + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get IP mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_l2mc2s_add + * Description: + * Add L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set L2 Mutlicast to SVID configuration. If upstream packet is L2 multicast + * packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32 + * SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid); + +/* Function Name: + * rtk_svlan_l2mc2s_del + * Description: + * delete L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete Mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk); + +/* Function Name: + * rtk_svlan_l2mc2s_get + * Description: + * Get L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get L2 mutlicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +extern rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid); + +/* Function Name: + * rtk_svlan_sp2c_add + * Description: + * Add system SP2C configuration + * Input: + * cvid - VLAN ID + * dst_port - Destination port of SVLAN to CVLAN configuration + * svid - SVLAN VID + * + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned + * SVID will be add C-tag with assigned CVID if the output port is the assigned destination port. + * There are 128 SP2C configurations. + */ +extern rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid); + +/* Function Name: + * rtk_svlan_sp2c_get + * Description: + * Get configure system SP2C content + * Input: + * svid - SVLAN VID + * dst_port - Destination port of SVLAN to CVLAN configuration + * Output: + * pCvid - VLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * Note: + * The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. + */ +extern rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid); + +/* Function Name: + * rtk_svlan_sp2c_del + * Description: + * Delete system SP2C configuration + * Input: + * svid - SVLAN VID + * dst_port - Destination port of SVLAN to CVLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. + */ +extern rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port); + + +/* Function Name: + * rtk_svlan_lookupType_set + * Description: + * Set lookup type of SVLAN + * Input: + * type - lookup type + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * none + */ +extern rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type); + +/* Function Name: + * rtk_svlan_lookupType_get + * Description: + * Get lookup type of SVLAN + * Input: + * pType - lookup type + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * none + */ +extern rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType); + +/* Function Name: + * rtk_svlan_trapPri_set + * Description: + * Set svlan trap priority + * Input: + * priority - priority for trap packets + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_INT_PRIORITY + * Note: + * None + */ +extern rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority); + +/* Function Name: + * rtk_svlan_trapPri_get + * Description: + * Get svlan trap priority + * Input: + * None + * Output: + * pPriority - priority for trap packets + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +extern rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority); + +/* Function Name: + * rtk_svlan_unassign_action_set + * Description: + * Configure Action of upstream without svid assign action + * Input: + * action - Action for Un-assign + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of upstream Un-assign svid packet. If action is not + * trap to CPU, the port-based SVID sure be assign as system need + */ +extern rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action); + +/* Function Name: + * rtk_svlan_unassign_action_get + * Description: + * Get action of upstream without svid assignment + * Input: + * None + * Output: + * pAction - Action for Un-assign + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * Note: + * None + */ +extern rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction); + + +/* Function Name: + * rtk_svlan_checkAndCreateMbr + * Description: + * Check and create Member configuration and return index + * Input: + * vid - VLAN id. + * Output: + * pIndex - Member configuration index + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VLAN ID. + * RT_ERR_TBL_FULL - Member Configuration table full + * Note: + * + */ +extern rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex); + + +#endif /* __RTK_API_SVLAN_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/trap.h b/drivers/net/phy/rtk/rtl8367c/include/trap.h new file mode 100644 index 000000000000..0cdb64a77b15 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/trap.h @@ -0,0 +1,757 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Trap module high-layer API defination + * + */ + +#ifndef __RTK_API_TRAP_H__ +#define __RTK_API_TRAP_H__ + + +typedef enum rtk_trap_type_e +{ + TRAP_BRG_GROUP = 0, + TRAP_FD_PAUSE, + TRAP_SP_MCAST, + TRAP_1X_PAE, + TRAP_UNDEF_BRG_04, + TRAP_UNDEF_BRG_05, + TRAP_UNDEF_BRG_06, + TRAP_UNDEF_BRG_07, + TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + TRAP_UNDEF_BRG_09, + TRAP_UNDEF_BRG_0A, + TRAP_UNDEF_BRG_0B, + TRAP_UNDEF_BRG_0C, + TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + TRAP_8021AB, + TRAP_UNDEF_BRG_0F, + TRAP_BRG_MNGEMENT, + TRAP_UNDEFINED_11, + TRAP_UNDEFINED_12, + TRAP_UNDEFINED_13, + TRAP_UNDEFINED_14, + TRAP_UNDEFINED_15, + TRAP_UNDEFINED_16, + TRAP_UNDEFINED_17, + TRAP_UNDEFINED_18, + TRAP_UNDEFINED_19, + TRAP_UNDEFINED_1A, + TRAP_UNDEFINED_1B, + TRAP_UNDEFINED_1C, + TRAP_UNDEFINED_1D, + TRAP_UNDEFINED_1E, + TRAP_UNDEFINED_1F, + TRAP_GMRP, + TRAP_GVRP, + TRAP_UNDEF_GARP_22, + TRAP_UNDEF_GARP_23, + TRAP_UNDEF_GARP_24, + TRAP_UNDEF_GARP_25, + TRAP_UNDEF_GARP_26, + TRAP_UNDEF_GARP_27, + TRAP_UNDEF_GARP_28, + TRAP_UNDEF_GARP_29, + TRAP_UNDEF_GARP_2A, + TRAP_UNDEF_GARP_2B, + TRAP_UNDEF_GARP_2C, + TRAP_UNDEF_GARP_2D, + TRAP_UNDEF_GARP_2E, + TRAP_UNDEF_GARP_2F, + TRAP_CDP, + TRAP_CSSTP, + TRAP_LLDP, + TRAP_END, +}rtk_trap_type_t; + + +typedef enum rtk_mcast_type_e +{ + MCAST_L2 = 0, + MCAST_IPV4, + MCAST_IPV6, + MCAST_END +} rtk_mcast_type_t; + +typedef enum rtk_trap_mcast_action_e +{ + MCAST_ACTION_FORWARD = 0, + MCAST_ACTION_DROP, + MCAST_ACTION_TRAP2CPU, + MCAST_ACTION_ROUTER_PORT, + MCAST_ACTION_DROP_EX_RMA, + MCAST_ACTION_END +} rtk_trap_mcast_action_t; + +typedef enum rtk_trap_rma_action_e +{ + RMA_ACTION_FORWARD = 0, + RMA_ACTION_TRAP2CPU, + RMA_ACTION_DROP, + RMA_ACTION_FORWARD_EXCLUDE_CPU, + RMA_ACTION_END +} rtk_trap_rma_action_t; + +typedef enum rtk_trap_ucast_action_e +{ + UCAST_ACTION_FORWARD_PMASK = 0, + UCAST_ACTION_DROP, + UCAST_ACTION_TRAP2CPU, + UCAST_ACTION_FLOODING, + UCAST_ACTION_END +} rtk_trap_ucast_action_t; + +typedef enum rtk_trap_ucast_type_e +{ + UCAST_UNKNOWNDA = 0, + UCAST_UNKNOWNSA, + UCAST_UNMATCHSA, + UCAST_END +} rtk_trap_ucast_type_t; + +typedef enum rtk_trap_reason_type_e +{ + TRAP_REASON_RMA = 0, + TRAP_REASON_OAM, + TRAP_REASON_1XUNAUTH, + TRAP_REASON_VLANSTACK, + TRAP_REASON_UNKNOWNMC, + TRAP_REASON_END, +} rtk_trap_reason_type_t; + + +/* Function Name: + * rtk_trap_unknownUnicastPktAction_set + * Description: + * Set unknown unicast packet action configuration. + * Input: + * port - ingress port ID for unknown unicast packet + * ucast_action - Unknown unicast action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + * - UCAST_ACTION_FLOODING + */ +rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action); + +/* Function Name: + * rtk_trap_unknownUnicastPktAction_get + * Description: + * Get unknown unicast packet action configuration. + * Input: + * port - ingress port ID for unknown unicast packet + * Output: + * pUcast_action - Unknown unicast action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * This API can get unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + * - UCAST_ACTION_FLOODING + */ +rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action); + +/* Function Name: + * rtk_trap_unknownMacPktAction_set + * Description: + * Set unknown source MAC packet action configuration. + * Input: + * ucast_action - Unknown source MAC action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +extern rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action); + +/* Function Name: + * rtk_trap_unknownMacPktAction_get + * Description: + * Get unknown source MAC packet action configuration. + * Input: + * None. + * Output: + * pUcast_action - Unknown source MAC action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null Pointer. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action); + +/* Function Name: + * rtk_trap_unmatchMacPktAction_set + * Description: + * Set unmatch source MAC packet action configuration. + * Input: + * ucast_action - Unknown source MAC action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action); + +/* Function Name: + * rtk_trap_unmatchMacPktAction_get + * Description: + * Get unmatch source MAC packet action configuration. + * Input: + * None. + * Output: + * pUcast_action - Unknown source MAC action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +extern rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action); + +/* Function Name: + * rtk_trap_unmatchMacMoving_set + * Description: + * Set unmatch source MAC packet moving state. + * Input: + * port - Port ID. + * enable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + */ +extern rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable); + +/* Function Name: + * rtk_trap_unmatchMacMoving_get + * Description: + * Set unmatch source MAC packet moving state. + * Input: + * port - Port ID. + * Output: + * pEnable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + */ +extern rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_trap_unknownMcastPktAction_set + * Description: + * Set behavior of unknown multicast + * Input: + * port - Port id. + * type - unknown multicast packet type. + * mcast_action - unknown multicast action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * When receives an unknown multicast packet, switch may trap, drop or flood this packet + * (1) The unknown multicast packet type is as following: + * - MCAST_L2 + * - MCAST_IPV4 + * - MCAST_IPV6 + * (2) The unknown multicast action is as following: + * - MCAST_ACTION_FORWARD + * - MCAST_ACTION_DROP + * - MCAST_ACTION_TRAP2CPU + */ +extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action); + +/* Function Name: + * rtk_trap_unknownMcastPktAction_get + * Description: + * Get behavior of unknown multicast + * Input: + * type - unknown multicast packet type. + * Output: + * pMcast_action - unknown multicast action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid operation. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * When receives an unknown multicast packet, switch may trap, drop or flood this packet + * (1) The unknown multicast packet type is as following: + * - MCAST_L2 + * - MCAST_IPV4 + * - MCAST_IPV6 + * (2) The unknown multicast action is as following: + * - MCAST_ACTION_FORWARD + * - MCAST_ACTION_DROP + * - MCAST_ACTION_TRAP2CPU + */ +extern rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action); + +/* Function Name: + * rtk_trap_lldpEnable_set + * Description: + * Set LLDP enable. + * Input: + * enabled - LLDP enable, 0: follow RMA, 1: use LLDP action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * - DMAC Assignment + * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP + * - 01:80:c2:00:00:03 ethertype = 0x88CC + * - 01:80:c2:00:00:00 ethertype = 0x88CC + + */ +extern rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_trap_lldpEnable_get + * Description: + * Get LLDP status. + * Input: + * None + * Output: + * pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * LLDP is as following definition. + * - DMAC Assignment + * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP + * - 01:80:c2:00:00:03 ethertype = 0x88CC + * - 01:80:c2:00:00:00 ethertype = 0x88CC + */ +extern rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled); + +/* Function Name: + * rtk_trap_reasonTrapToCpuPriority_set + * Description: + * Set priority value of a packet that trapped to CPU port according to specific reason. + * Input: + * type - reason that trap to CPU port. + * priority - internal priority that is going to be set for specific trap reason. + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - Invalid input parameter + * Note: + * Currently the trap reason that supported are listed as follows: + * - TRAP_REASON_RMA + * - TRAP_REASON_OAM + * - TRAP_REASON_1XUNAUTH + * - TRAP_REASON_VLANSTACK + * - TRAP_REASON_UNKNOWNMC + */ +extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority); + +/* Function Name: + * rtk_trap_reasonTrapToCpuPriority_get + * Description: + * Get priority value of a packet that trapped to CPU port according to specific reason. + * Input: + * type - reason that trap to CPU port. + * Output: + * pPriority - configured internal priority for such reason. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * Currently the trap reason that supported are listed as follows: + * - TRAP_REASON_RMA + * - TRAP_REASON_OAM + * - TRAP_REASON_1XUNAUTH + * - TRAP_REASON_VLANSTACK + * - TRAP_REASON_UNKNOWNMC + */ +extern rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority); + +/* Function Name: + * rtk_trap_rmaAction_set + * Description: + * Set Reserved multicast address action configuration. + * Input: + * type - rma type. + * rma_action - RMA action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid IFG parameter + * Note: + * + * There are 48 types of Reserved Multicast Address frame for application usage. + * (1)They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + * (2) The RMA action is as following: + * - RMA_ACTION_FORWARD + * - RMA_ACTION_TRAP2CPU + * - RMA_ACTION_DROP + * - RMA_ACTION_FORWARD_EXCLUDE_CPU + */ +extern rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action); + +/* Function Name: + * rtk_trap_rmaAction_get + * Description: + * Get Reserved multicast address action configuration. + * Input: + * type - rma type. + * Output: + * pRma_action - RMA action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 48 types of Reserved Multicast Address frame for application usage. + * (1)They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + * (2) The RMA action is as following: + * - RMA_ACTION_FORWARD + * - RMA_ACTION_TRAP2CPU + * - RMA_ACTION_DROP + * - RMA_ACTION_FORWARD_EXCLUDE_CPU + */ +extern rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action); + +/* Function Name: + * rtk_trap_rmaKeepFormat_set + * Description: + * Set Reserved multicast address keep format configuration. + * Input: + * type - rma type. + * enable - enable keep format. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid IFG parameter + * Note: + * + * There are 48 types of Reserved Multicast Address frame for application usage. + * They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + */ +extern rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable); + +/* Function Name: + * rtk_trap_rmaKeepFormat_get + * Description: + * Get Reserved multicast address action configuration. + * Input: + * type - rma type. + * Output: + * pEnable - keep format status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 48 types of Reserved Multicast Address frame for application usage. + * They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + */ +extern rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable); + + +#endif /* __RTK_API_TRAP_H__ */ + + diff --git a/drivers/net/phy/rtk/rtl8367c/include/trunk.h b/drivers/net/phy/rtk/rtl8367c/include/trunk.h new file mode 100644 index 000000000000..dff61769dfd2 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/trunk.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Trunk module high-layer TRUNK defination + * + */ + +#ifndef __RTK_API_TRUNK_H__ +#define __RTK_API_TRUNK_H__ + +/* + * Data Type Declaration + */ +#define RTK_TRUNK_DPORT_HASH_MASK 0x40 +#define RTK_TRUNK_SPORT_HASH_MASK 0x20 +#define RTK_TRUNK_DIP_HASH_MASK 0x10 +#define RTK_TRUNK_SIP_HASH_MASK 0x8 +#define RTK_TRUNK_DMAC_HASH_MASK 0x4 +#define RTK_TRUNK_SMAC_HASH_MASK 0x2 +#define RTK_TRUNK_SPA_HASH_MASK 0x1 + + +#define RTK_MAX_NUM_OF_TRUNK_HASH_VAL 16 + +typedef struct rtk_trunk_hashVal2Port_s +{ + rtk_uint8 value[RTK_MAX_NUM_OF_TRUNK_HASH_VAL]; +} rtk_trunk_hashVal2Port_t; + +typedef enum rtk_trunk_group_e +{ + TRUNK_GROUP0 = 0, + TRUNK_GROUP1, + TRUNK_GROUP2, + TRUNK_GROUP3, + TRUNK_GROUP_END +} rtk_trunk_group_t; + +typedef enum rtk_trunk_separateType_e +{ + SEPARATE_NONE = 0, + SEPARATE_FLOOD, + SEPARATE_END + +} rtk_trunk_separateType_t; + +typedef enum rtk_trunk_mode_e +{ + TRUNK_MODE_NORMAL = 0, + TRUNK_MODE_DUMB, + TRUNK_MODE_END +} rtk_trunk_mode_t; + +/* Function Name: + * rtk_trunk_port_set + * Description: + * Set trunking group available port mask + * Input: + * trk_gid - trunk group id + * pTrunk_member_portmask - Logic trunking member port mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API can set port trunking group port mask. Each port trunking group has max 4 ports. + * If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled. + */ +extern rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask); + +/* Function Name: + * rtk_trunk_port_get + * Description: + * Get trunking group available port mask + * Input: + * trk_gid - trunk group id + * Output: + * pTrunk_member_portmask - Logic trunking member port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * Note: + * The API can get 2 port trunking group. + */ +extern rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask); + +/* Function Name: + * rtk_trunk_distributionAlgorithm_set + * Description: + * Set port trunking hash select sources + * Input: + * trk_gid - trunk group id + * algo_bitmask - Bitmask of the distribution algorithm + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * RT_ERR_LA_HASHMASK - Hash algorithm selection error. + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API can set port trunking hash algorithm sources. + * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} + * - 0b0000001: SPA + * - 0b0000010: SMAC + * - 0b0000100: DMAC + * - 0b0001000: SIP + * - 0b0010000: DIP + * - 0b0100000: TCP/UDP Source Port + * - 0b1000000: TCP/UDP Destination Port + * Example: + * - 0b0000011: SMAC & SPA + * - Note that it could be an arbitrary combination or independent set + */ +extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask); + +/* Function Name: + * rtk_trunk_distributionAlgorithm_get + * Description: + * Get port trunking hash select sources + * Input: + * trk_gid - trunk group id + * Output: + * pAlgo_bitmask - Bitmask of the distribution algorithm + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * Note: + * The API can get port trunking hash algorithm sources. + */ +extern rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask); + +/* Function Name: + * rtk_trunk_trafficSeparate_set + * Description: + * Set the traffic separation setting of a trunk group from the specified device. + * Input: + * trk_gid - trunk group id + * separateType - traffic separation setting + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_LA_HASHMASK - invalid hash mask + * Note: + * SEPARATE_NONE: disable traffic separation + * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic + */ +extern rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType); + +/* Function Name: + * rtk_trunk_trafficSeparate_get + * Description: + * Get the traffic separation setting of a trunk group from the specified device. + * Input: + * trk_gid - trunk group id + * Output: + * pSeparateType - pointer separated traffic type + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * SEPARATE_NONE: disable traffic separation + * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic + */ +extern rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType); + + +/* Function Name: + * rtk_trunk_mode_set + * Description: + * Set the trunk mode to the specified device. + * Input: + * mode - trunk mode + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Note: + * The enum of the trunk mode as following + * - TRUNK_MODE_NORMAL + * - TRUNK_MODE_DUMB + */ +extern rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode); + +/* Function Name: + * rtk_trunk_mode_get + * Description: + * Get the trunk mode from the specified device. + * Input: + * None + * Output: + * pMode - pointer buffer of trunk mode + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * The enum of the trunk mode as following + * - TRUNK_MODE_NORMAL + * - TRUNK_MODE_DUMB + */ +extern rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode); + +/* Function Name: + * rtk_trunk_trafficPause_set + * Description: + * Set the traffic pause setting of a trunk group. + * Input: + * trk_gid - trunk group id + * enable - traffic pause state + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * Note: + * None. + */ +extern rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable); + +/* Function Name: + * rtk_trunk_trafficPause_get + * Description: + * Get the traffic pause setting of a trunk group. + * Input: + * trk_gid - trunk group id + * Output: + * pEnable - pointer of traffic pause state. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None. + */ +extern rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable); + +/* Function Name: + * rtk_trunk_hashMappingTable_set + * Description: + * Set hash value to port array in the trunk group id from the specified device. + * Input: + * trk_gid - trunk group id + * pHash2Port_array - ports associate with the hash value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist + * RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk + * RT_ERR_LA_CPUPORT - CPU port can not be aggregated port + * Note: + * Trunk group 0 & 1 shares the same hash mapping table. + * Trunk group 2 uses a independent table. + */ +extern rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array); + +/* Function Name: + * rtk_trunk_hashMappingTable_get + * Description: + * Get hash value to port array in the trunk group id from the specified device. + * Input: + * trk_gid - trunk group id + * Output: + * pHash2Port_array - pointer buffer of ports associate with the hash value + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * Trunk group 0 & 1 shares the same hash mapping table. + * Trunk group 2 uses a independent table. + */ +extern rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array); + +/* Function Name: + * rtk_trunk_portQueueEmpty_get + * Description: + * Get the port mask which all queues are empty. + * Input: + * None. + * Output: + * pEmpty_portmask - pointer empty port mask + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None. + */ +extern rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask); + +#endif /* __RTK_API_TRUNK_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/include/vlan.h b/drivers/net/phy/rtk/rtl8367c/include/vlan.h new file mode 100644 index 000000000000..8569fc0d40f4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/include/vlan.h @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367/RTL8367C switch high-level API + * + * Feature : The file includes Trap module high-layer VLAN defination + * + */ + +#ifndef __RTK_API_VLAN_H__ +#define __RTK_API_VLAN_H__ + + +/* + * Data Type Declaration + */ +#define RTK_MAX_NUM_OF_PROTO_TYPE 0xFFFF +#define RTK_MAX_NUM_OF_MSTI 0xF +#define RTK_FID_MAX 0xF + +typedef struct rtk_vlan_cfg_s +{ + rtk_portmask_t mbr; + rtk_portmask_t untag; + rtk_uint16 ivl_en; + rtk_uint16 fid_msti; + rtk_uint16 envlanpol; + rtk_uint16 meteridx; + rtk_uint16 vbpen; + rtk_uint16 vbpri; +}rtk_vlan_cfg_t; + +typedef struct rtk_vlan_mbrcfg_s +{ + rtk_uint16 evid; + rtk_portmask_t mbr; + rtk_uint16 fid_msti; + rtk_uint16 envlanpol; + rtk_uint16 meteridx; + rtk_uint16 vbpen; + rtk_uint16 vbpri; +}rtk_vlan_mbrcfg_t; + +typedef rtk_uint32 rtk_stp_msti_id_t; /* MSTI ID */ + +typedef enum rtk_stp_state_e +{ + STP_STATE_DISABLED = 0, + STP_STATE_BLOCKING, + STP_STATE_LEARNING, + STP_STATE_FORWARDING, + STP_STATE_END +} rtk_stp_state_t; + +typedef rtk_uint32 rtk_vlan_proto_type_t; /* protocol and port based VLAN protocol type */ + + +typedef enum rtk_vlan_acceptFrameType_e +{ + ACCEPT_FRAME_TYPE_ALL = 0, /* untagged, priority-tagged and tagged */ + ACCEPT_FRAME_TYPE_TAG_ONLY, /* tagged */ + ACCEPT_FRAME_TYPE_UNTAG_ONLY, /* untagged and priority-tagged */ + ACCEPT_FRAME_TYPE_END +} rtk_vlan_acceptFrameType_t; + + +/* frame type of protocol vlan - reference 802.1v standard */ +typedef enum rtk_vlan_protoVlan_frameType_e +{ + FRAME_TYPE_ETHERNET = 0, + FRAME_TYPE_LLCOTHER, + FRAME_TYPE_RFC1042, + FRAME_TYPE_END +} rtk_vlan_protoVlan_frameType_t; + +/* Protocol-and-port-based Vlan structure */ +typedef struct rtk_vlan_protoAndPortInfo_s +{ + rtk_uint32 proto_type; + rtk_vlan_protoVlan_frameType_t frame_type; + rtk_vlan_t cvid; + rtk_pri_t cpri; +}rtk_vlan_protoAndPortInfo_t; + +/* tagged mode of VLAN - reference realtek private specification */ +typedef enum rtk_vlan_tagMode_e +{ + VLAN_TAG_MODE_ORIGINAL = 0, + VLAN_TAG_MODE_KEEP_FORMAT, + VLAN_TAG_MODE_PRI, + VLAN_TAG_MODE_REAL_KEEP_FORMAT, + VLAN_TAG_MODE_END +} rtk_vlan_tagMode_t; + +typedef enum rtk_vlan_resVidAction_e +{ + RESVID_ACTION_UNTAG = 0, + RESVID_ACTION_TAG, + RESVID_ACTION_END +} +rtk_vlan_resVidAction_t; + +/* Function Name: + * rtk_vlan_init + * Description: + * Initialize VLAN. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * VLAN is disabled by default. User has to call this API to enable VLAN before + * using it. And It will set a default VLAN(vid 1) including all ports and set + * all ports PVID to the default VLAN. + */ +extern rtk_api_ret_t rtk_vlan_init(void); + +/* Function Name: + * rtk_vlan_set + * Description: + * Set a VLAN entry. + * Input: + * vid - VLAN ID to configure. + * pVlanCfg - VLAN Configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_L2_FID - Invalid FID. + * RT_ERR_VLAN_PORT_MBR_EXIST - Invalid member port mask. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg); + +/* Function Name: + * rtk_vlan_get + * Description: + * Get a VLAN entry. + * Input: + * vid - VLAN ID to configure. + * Output: + * pVlanCfg - VLAN Configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg); + +/* Function Name: + * rtk_vlan_egrFilterEnable_set + * Description: + * Set VLAN egress filter. + * Input: + * egrFilter - Egress filtering + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter); + +/* Function Name: + * rtk_vlan_egrFilterEnable_get + * Description: + * Get VLAN egress filter. + * Input: + * pEgrFilter - Egress filtering + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - NULL Pointer. + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter); + +/* Function Name: + * rtk_vlan_mbrCfg_set + * Description: + * Set a VLAN Member Configuration entry by index. + * Input: + * idx - Index of VLAN Member Configuration. + * pMbrcfg - VLAN member Configuration. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * Set a VLAN Member Configuration entry by index. + */ +extern rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg); + +/* Function Name: + * rtk_vlan_mbrCfg_get + * Description: + * Get a VLAN Member Configuration entry by index. + * Input: + * idx - Index of VLAN Member Configuration. + * Output: + * pMbrcfg - VLAN member Configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * Get a VLAN Member Configuration entry by index. + */ +extern rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg); + +/* Function Name: + * rtk_vlan_portPvid_set + * Description: + * Set port to specified VLAN ID(PVID). + * Input: + * port - Port id. + * pvid - Specified VLAN ID. + * priority - 802.1p priority for the PVID. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API is used for Port-based VLAN. The untagged frame received from the + * port will be classified to the specified VLAN and assigned to the specified priority. + */ +extern rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority); + +/* Function Name: + * rtk_vlan_portPvid_get + * Description: + * Get VLAN ID(PVID) on specified port. + * Input: + * port - Port id. + * Output: + * pPvid - Specified VLAN ID. + * pPriority - 802.1p priority for the PVID. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN. + */ +extern rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority); + +/* Function Name: + * rtk_vlan_portIgrFilterEnable_set + * Description: + * Set VLAN ingress for each port. + * Input: + * port - Port id. + * igr_filter - VLAN ingress function enable status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The status of vlan ingress filter is as following: + * - DISABLED + * - ENABLED + * While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member + * ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled. + */ +extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter); + +/* Function Name: + * rtk_vlan_portIgrFilterEnable_get + * Description: + * Get VLAN Ingress Filter + * Input: + * port - Port id. + * Output: + * pIgr_filter - VLAN ingress function enable status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can Get the VLAN ingress filter status. + * The status of vlan ingress filter is as following: + * - DISABLED + * - ENABLED + */ +extern rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter); + +/* Function Name: + * rtk_vlan_portAcceptFrameType_set + * Description: + * Set VLAN accept_frame_type + * Input: + * port - Port id. + * accept_frame_type - accept frame type + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type. + * Note: + * The API is used for checking 802.1Q tagged frames. + * The accept frame type as following: + * - ACCEPT_FRAME_TYPE_ALL + * - ACCEPT_FRAME_TYPE_TAG_ONLY + * - ACCEPT_FRAME_TYPE_UNTAG_ONLY + */ +extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type); + +/* Function Name: + * rtk_vlan_portAcceptFrameType_get + * Description: + * Get VLAN accept_frame_type + * Input: + * port - Port id. + * Output: + * pAccept_frame_type - accept frame type + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can Get the VLAN ingress filter. + * The accept frame type as following: + * - ACCEPT_FRAME_TYPE_ALL + * - ACCEPT_FRAME_TYPE_TAG_ONLY + * - ACCEPT_FRAME_TYPE_UNTAG_ONLY + */ +extern rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type); + +/* Function Name: + * rtk_vlan_tagMode_set + * Description: + * Set CVLAN egress tag mode + * Input: + * port - Port id. + * tag_mode - The egress tag mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set Egress tag mode. There are 4 mode for egress tag: + * - VLAN_TAG_MODE_ORIGINAL, + * - VLAN_TAG_MODE_KEEP_FORMAT, + * - VLAN_TAG_MODE_PRI. + * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, + */ +extern rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode); + +/* Function Name: + * rtk_vlan_tagMode_get + * Description: + * Get CVLAN egress tag mode + * Input: + * port - Port id. + * Output: + * pTag_mode - The egress tag mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get Egress tag mode. There are 4 mode for egress tag: + * - VLAN_TAG_MODE_ORIGINAL, + * - VLAN_TAG_MODE_KEEP_FORMAT, + * - VLAN_TAG_MODE_PRI. + * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, + */ +extern rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode); + +/* Function Name: + * rtk_vlan_transparent_set + * Description: + * Set VLAN transparent mode + * Input: + * egr_port - Egress Port id. + * pIgr_pmask - Ingress Port Mask. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +extern rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); + +/* Function Name: + * rtk_vlan_transparent_get + * Description: + * Get VLAN transparent mode + * Input: + * egr_port - Egress Port id. + * Output: + * pIgr_pmask - Ingress Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +extern rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); + +/* Function Name: + * rtk_vlan_keep_set + * Description: + * Set VLAN egress keep mode + * Input: + * egr_port - Egress Port id. + * pIgr_pmask - Ingress Port Mask. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +extern rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); + +/* Function Name: + * rtk_vlan_keep_get + * Description: + * Get VLAN egress keep mode + * Input: + * egr_port - Egress Port id. + * Output: + * pIgr_pmask - Ingress Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +extern rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask); + +/* Function Name: + * rtk_vlan_stg_set + * Description: + * Set spanning tree group instance of the vlan to the specified device + * Input: + * vid - Specified VLAN ID. + * stg - spanning tree group instance. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MSTI - Invalid msti parameter + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API can set spanning tree group instance of the vlan to the specified device. + */ +extern rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg); + +/* Function Name: + * rtk_vlan_stg_get + * Description: + * Get spanning tree group instance of the vlan to the specified device + * Input: + * vid - Specified VLAN ID. + * Output: + * pStg - spanning tree group instance. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API can get spanning tree group instance of the vlan to the specified device. + */ +extern rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg); + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_add + * Description: + * Add the protocol-and-port-based vlan to the specified port of device. + * Input: + * port - Port id. + * pInfo - Protocol and port based VLAN configuration information. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_TBL_FULL - Table is full. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo); + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_get + * Description: + * Get the protocol-and-port-based vlan to the specified port of device. + * Input: + * port - Port id. + * proto_type - protocol-and-port-based vlan protocol type. + * frame_type - protocol-and-port-based vlan frame type. + * Output: + * pInfo - Protocol and port based VLAN configuration information. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_TBL_FULL - Table is full. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo); + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_del + * Description: + * Delete the protocol-and-port-based vlan from the specified port of device. + * Input: + * port - Port id. + * proto_type - protocol-and-port-based vlan protocol type. + * frame_type - protocol-and-port-based vlan frame type. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_TBL_FULL - Table is full. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type); + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_delAll + * Description: + * Delete all protocol-and-port-based vlans from the specified port of device. + * Input: + * port - Port id. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * Delete all flow table protocol-and-port-based vlan entries. + */ +extern rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port); + +/* Function Name: + * rtk_vlan_portFid_set + * Description: + * Set port-based filtering database + * Input: + * port - Port id. + * enable - ebable port-based FID + * fid - Specified filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid fid. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can set port-based filtering database. If the function is enabled, all input + * packets will be assigned to the port-based fid regardless vlan tag. + */ +extern rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid); + +/* Function Name: + * rtk_vlan_portFid_get + * Description: + * Get port-based filtering database + * Input: + * port - Port id. + * Output: + * pEnable - ebable port-based FID + * pFid - Specified filtering database. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get port-based filtering database status. If the function is enabled, all input + * packets will be assigned to the port-based fid regardless vlan tag. + */ +extern rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid); + +/* Function Name: + * rtk_vlan_UntagDscpPriorityEnable_set + * Description: + * Set Untag DSCP priority assign + * Input: + * enable - state of Untag DSCP priority assign + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid input parameters. + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable); + +/* Function Name: + * rtk_vlan_UntagDscpPriorityEnable_get + * Description: + * Get Untag DSCP priority assign + * Input: + * None + * Output: + * pEnable - state of Untag DSCP priority assign + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable); + + +/*Spanning Tree*/ +/* Function Name: + * rtk_stp_mstpState_set + * Description: + * Configure spanning tree state per each port. + * Input: + * port - Port id + * msti - Multiple spanning tree instance. + * stp_state - Spanning tree state for msti + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MSTI - Invalid msti parameter. + * RT_ERR_MSTP_STATE - Invalid STP state. + * Note: + * System supports per-port multiple spanning tree state for each msti. + * There are four states supported by ASIC. + * - STP_STATE_DISABLED + * - STP_STATE_BLOCKING + * - STP_STATE_LEARNING + * - STP_STATE_FORWARDING + */ +extern rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state); + +/* Function Name: + * rtk_stp_mstpState_get + * Description: + * Get spanning tree state per each port. + * Input: + * port - Port id. + * msti - Multiple spanning tree instance. + * Output: + * pStp_state - Spanning tree state for msti + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MSTI - Invalid msti parameter. + * Note: + * System supports per-port multiple spanning tree state for each msti. + * There are four states supported by ASIC. + * - STP_STATE_DISABLED + * - STP_STATE_BLOCKING + * - STP_STATE_LEARNING + * - STP_STATE_FORWARDING + */ +extern rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state); + +/* Function Name: + * rtk_vlan_checkAndCreateMbr + * Description: + * Check and create Member configuration and return index + * Input: + * vid - VLAN id. + * Output: + * pIndex - Member configuration index + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VLAN ID. + * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found + * RT_ERR_TBL_FULL - Member Configuration table full + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex); + +/* Function Name: + * rtk_vlan_reservedVidAction_set + * Description: + * Set Action of VLAN ID = 0 & 4095 tagged packet + * Input: + * action_vid0 - Action for VID 0. + * action_vid4095 - Action for VID 4095. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095); + +/* Function Name: + * rtk_vlan_reservedVidAction_get + * Description: + * Get Action of VLAN ID = 0 & 4095 tagged packet + * Input: + * pAction_vid0 - Action for VID 0. + * pAction_vid4095 - Action for VID 4095. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - NULL Pointer + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095); + +/* Function Name: + * rtk_vlan_realKeepRemarkEnable_set + * Description: + * Set Real keep 1p remarking feature + * Input: + * enabled - State of 1p remarking at real keep packet + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled); + +/* Function Name: + * rtk_vlan_realKeepRemarkEnable_get + * Description: + * Get Real keep 1p remarking feature + * Input: + * None. + * Output: + * pEnabled - State of 1p remarking at real keep packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +extern rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled); + +/* Function Name: + * rtk_vlan_reset + * Description: + * Reset VLAN + * Input: + * None. + * Output: + * pEnabled - State of 1p remarking at real keep packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_vlan_reset(void); + +#endif /* __RTK_API_VLAN_H__ */ diff --git a/drivers/net/phy/rtk/rtl8367c/interrupt.c b/drivers/net/phy/rtk/rtl8367c/interrupt.c new file mode 100644 index 000000000000..165ee41721b8 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/interrupt.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Interrupt module. + * + */ + +#include +#include +#include +#include + +#include +#include + +/* Function Name: + * rtk_int_polarity_set + * Description: + * Set interrupt polarity configuration. + * Input: + * type - Interruptpolarity type. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set interrupt polarity configuration. + */ +rtk_api_ret_t rtk_int_polarity_set(rtk_int_polarity_t type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(type >= INT_POLAR_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicInterruptPolarity(type)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_int_polarity_get + * Description: + * Get interrupt polarity configuration. + * Input: + * None + * Output: + * pType - Interruptpolarity type. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can get interrupt polarity configuration. + */ +rtk_api_ret_t rtk_int_polarity_get(rtk_int_polarity_t *pType) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pType) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicInterruptPolarity(pType)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_int_control_set + * Description: + * Set interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * enable - Interrupt status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set interrupt status configuration. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS + * - INT_TYPE_METER_EXCEED + * - INT_TYPE_LEARN_LIMIT + * - INT_TYPE_LINK_SPEED + * - INT_TYPE_CONGEST + * - INT_TYPE_GREEN_FEATURE + * - INT_TYPE_LOOP_DETECT + * - INT_TYPE_8051, + * - INT_TYPE_CABLE_DIAG, + * - INT_TYPE_ACL, + * - INT_TYPE_SLIENT + */ +rtk_api_ret_t rtk_int_control_set(rtk_int_type_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 mask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= INT_TYPE_END) + return RT_ERR_INPUT; + + if (type == INT_TYPE_RESERVED) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicInterruptMask(&mask)) != RT_ERR_OK) + return retVal; + + if (ENABLED == enable) + mask = mask | (1<value[0] & (0x0001 << INT_TYPE_RESERVED)) + return RT_ERR_INPUT; + + if(pStatusMask->value[0] >= (0x0001 << INT_TYPE_END)) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicInterruptStatus((rtk_uint32)pStatusMask->value[0]))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_int_status_get + * Description: + * Get interrupt trigger status. + * Input: + * None + * Output: + * pStatusMask - Interrupt status bit mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get interrupt trigger status when interrupt happened. + * The interrupt trigger status is shown in the following: + * - INT_TYPE_LINK_STATUS (value[0] (Bit0)) + * - INT_TYPE_METER_EXCEED (value[0] (Bit1)) + * - INT_TYPE_LEARN_LIMIT (value[0] (Bit2)) + * - INT_TYPE_LINK_SPEED (value[0] (Bit3)) + * - INT_TYPE_CONGEST (value[0] (Bit4)) + * - INT_TYPE_GREEN_FEATURE (value[0] (Bit5)) + * - INT_TYPE_LOOP_DETECT (value[0] (Bit6)) + * - INT_TYPE_8051 (value[0] (Bit7)) + * - INT_TYPE_CABLE_DIAG (value[0] (Bit8)) + * - INT_TYPE_ACL (value[0] (Bit9)) + * - INT_TYPE_SLIENT (value[0] (Bit11)) + * + */ +rtk_api_ret_t rtk_int_status_get(rtk_int_status_t* pStatusMask) +{ + rtk_api_ret_t retVal; + rtk_uint32 ims_mask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pStatusMask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicInterruptStatus(&ims_mask)) != RT_ERR_OK) + return retVal; + + pStatusMask->value[0] = (ims_mask & 0x00000FFF); + return RT_ERR_OK; +} + +#define ADV_NOT_SUPPORT (0xFFFF) +static rtk_api_ret_t _rtk_int_Advidx_get(rtk_int_advType_t adv_type, rtk_uint32 *pAsic_idx) +{ + rtk_uint32 asic_idx[ADV_END] = + { + INTRST_L2_LEARN, + INTRST_SPEED_CHANGE, + INTRST_SPECIAL_CONGESTION, + INTRST_PORT_LINKDOWN, + INTRST_PORT_LINKUP, + ADV_NOT_SUPPORT, + INTRST_RLDP_LOOPED, + INTRST_RLDP_RELEASED, + }; + + if(adv_type >= ADV_END) + return RT_ERR_INPUT; + + if(asic_idx[adv_type] == ADV_NOT_SUPPORT) + return RT_ERR_CHIP_NOT_SUPPORTED; + + *pAsic_idx = asic_idx[adv_type]; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_int_advanceInfo_get + * Description: + * Get interrupt advanced information. + * Input: + * adv_type - Advanced interrupt type. + * Output: + * info - Information per type. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get advanced information when interrupt happened. + * The status will be cleared after execute this API. + */ +rtk_api_ret_t rtk_int_advanceInfo_get(rtk_int_advType_t adv_type, rtk_int_info_t *pInfo) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + rtk_uint32 intAdvType; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(adv_type >= ADV_END) + return RT_ERR_INPUT; + + if(NULL == pInfo) + return RT_ERR_NULL_POINTER; + + if(adv_type != ADV_METER_EXCEED_MASK) + { + if((retVal = _rtk_int_Advidx_get(adv_type, &intAdvType)) != RT_ERR_OK) + return retVal; + } + + switch(adv_type) + { + case ADV_L2_LEARN_PORT_MASK: + /* Get physical portmask */ + if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK) + return retVal; + + /* Clear Advanced Info */ + if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK) + return retVal; + + /* Translate to logical portmask */ + if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK) + return retVal; + + /* Get system learn */ + if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_SYS_LEARN, &data)) != RT_ERR_OK) + return retVal; + + /* Clear system learn */ + if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_SYS_LEARN, 0x0001)) != RT_ERR_OK) + return retVal; + + pInfo->systemLearnOver = data; + break; + case ADV_SPEED_CHANGE_PORT_MASK: + case ADV_SPECIAL_CONGESTION_PORT_MASK: + case ADV_PORT_LINKDOWN_PORT_MASK: + case ADV_PORT_LINKUP_PORT_MASK: + case ADV_RLDP_LOOPED: + case ADV_RLDP_RELEASED: + /* Get physical portmask */ + if((retVal = rtl8367c_getAsicInterruptRelatedStatus(intAdvType, &data)) != RT_ERR_OK) + return retVal; + + /* Clear Advanced Info */ + if((retVal = rtl8367c_setAsicInterruptRelatedStatus(intAdvType, 0xFFFF)) != RT_ERR_OK) + return retVal; + + /* Translate to logical portmask */ + if((retVal = rtk_switch_portmask_P2L_get(data, &(pInfo->portMask))) != RT_ERR_OK) + return retVal; + + break; + case ADV_METER_EXCEED_MASK: + /* Get Meter Mask */ + if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER0_15, &data)) != RT_ERR_OK) + return retVal; + + /* Clear Advanced Info */ + if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER0_15, 0xFFFF)) != RT_ERR_OK) + return retVal; + + pInfo->meterMask = data & 0xFFFF; + + /* Get Meter Mask */ + if((retVal = rtl8367c_getAsicInterruptRelatedStatus(INTRST_METER16_31, &data)) != RT_ERR_OK) + return retVal; + + /* Clear Advanced Info */ + if((retVal = rtl8367c_setAsicInterruptRelatedStatus(INTRST_METER16_31, 0xFFFF)) != RT_ERR_OK) + return retVal; + + pInfo->meterMask = pInfo->meterMask | ((data << 16) & 0xFFFF0000); + + break; + default: + return RT_ERR_INPUT; + } + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/l2.c b/drivers/net/phy/rtk/rtl8367c/l2.c new file mode 100644 index 000000000000..e73199a4e93d --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/l2.c @@ -0,0 +1,2911 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in L2 module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +/* Function Name: + * rtk_l2_init + * Description: + * Initialize l2 module of the specified device. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Initialize l2 module before calling any l2 APIs. + */ +rtk_api_ret_t rtk_l2_init(void) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK) + return retVal; + + /*Enable CAM Usage*/ + if ((retVal = rtl8367c_setAsicLutCamTbUsage(ENABLED)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutAgeTimerSpeed(6,2)) != RT_ERR_OK) + return retVal; + + RTK_SCAN_ALL_LOG_PORT(port) + { + if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), rtk_switch_maxLutAddrNumber_get())) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_l2_addr_add + * Description: + * Add LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * pL2_data - Unicast entry parameter + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the unicast mac address already existed in LUT, it will update the status of the entry. + * Otherwise, it will find an empty or asic auto learned entry to write. If all the entries + * with the same hash value can't be replaced, ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. + */ +rtk_api_ret_t rtk_l2_addr_add(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* must be unicast address */ + if ((pMac == NULL) || (pMac->octet[0] & 0x1)) + return RT_ERR_MAC; + + if(pL2_data == NULL) + return RT_ERR_MAC; + + RTK_CHK_PORT_VALID(pL2_data->port); + + if (pL2_data->ivl >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->cvid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if (pL2_data->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if (pL2_data->is_static>= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->sa_block>= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->da_block>= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->auth>= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->efid> RTL8367C_EFIDMAX) + return RT_ERR_INPUT; + + if (pL2_data->priority > RTL8367C_PRIMAX) + return RT_ERR_INPUT; + + if (pL2_data->sa_pri_en >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pL2_data->fwd_pri_en >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.fid = pL2_data->fid; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.efid = pL2_data->efid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal ) + { + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.fid = pL2_data->fid; + l2Table.efid = pL2_data->efid; + l2Table.spa = rtk_switch_port_L2P_get(pL2_data->port); + l2Table.nosalearn = pL2_data->is_static; + l2Table.sa_block = pL2_data->sa_block; + l2Table.da_block = pL2_data->da_block; + l2Table.l3lookup = 0; + l2Table.auth = pL2_data->auth; + l2Table.age = 6; + l2Table.lut_pri = pL2_data->priority; + l2Table.sa_en = pL2_data->sa_pri_en; + l2Table.fwd_en = pL2_data->fwd_pri_en; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pL2_data->address = l2Table.address; + return RT_ERR_OK; + } + else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal ) + { + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.fid = pL2_data->fid; + l2Table.efid = pL2_data->efid; + l2Table.spa = rtk_switch_port_L2P_get(pL2_data->port); + l2Table.nosalearn = pL2_data->is_static; + l2Table.sa_block = pL2_data->sa_block; + l2Table.da_block = pL2_data->da_block; + l2Table.l3lookup = 0; + l2Table.auth = pL2_data->auth; + l2Table.age = 6; + l2Table.lut_pri = pL2_data->priority; + l2Table.sa_en = pL2_data->sa_pri_en; + l2Table.fwd_en = pL2_data->fwd_pri_en; + + if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pL2_data->address = l2Table.address; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_L2_ENTRY_NOTFOUND == retVal ) + return RT_ERR_L2_INDEXTBL_FULL; + else + return retVal; + } + else + return retVal; + +} + +/* Function Name: + * rtk_l2_addr_get + * Description: + * Get LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * Output: + * pL2_data - Unicast entry parameter + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the unicast mac address existed in LUT, it will return the port and fid where + * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. + */ +rtk_api_ret_t rtk_l2_addr_get(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* must be unicast address */ + if ((pMac == NULL) || (pMac->octet[0] & 0x1)) + return RT_ERR_MAC; + + if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX) + return RT_ERR_L2_FID; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.fid = pL2_data->fid; + l2Table.efid = pL2_data->efid; + method = LUTREADMETHOD_MAC; + + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + memcpy(pL2_data->mac.octet, pMac->octet,ETHER_ADDR_LEN); + pL2_data->port = rtk_switch_port_P2L_get(l2Table.spa); + pL2_data->fid = l2Table.fid; + pL2_data->efid = l2Table.efid; + pL2_data->ivl = l2Table.ivl_svl; + pL2_data->cvid = l2Table.cvid_fid; + pL2_data->is_static = l2Table.nosalearn; + pL2_data->auth = l2Table.auth; + pL2_data->sa_block = l2Table.sa_block; + pL2_data->da_block = l2Table.da_block; + pL2_data->priority = l2Table.lut_pri; + pL2_data->sa_pri_en = l2Table.sa_en; + pL2_data->fwd_pri_en= l2Table.fwd_en; + pL2_data->address = l2Table.address; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_addr_next_get + * Description: + * Get Next LUT unicast entry. + * Input: + * read_method - The reading method. + * port - The port number if the read_metohd is READMETHOD_NEXT_L2UCSPA + * pAddress - The Address ID + * Output: + * pL2_data - Unicast entry parameter + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next unicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all entries is LUT. + */ +rtk_api_ret_t rtk_l2_addr_next_get(rtk_l2_read_method_t read_method, rtk_port_t port, rtk_uint32 *pAddress, rtk_l2_ucastAddr_t *pL2_data) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error Checking */ + if ((pL2_data == NULL) || (pAddress == NULL)) + return RT_ERR_MAC; + + if(read_method == READMETHOD_NEXT_L2UC) + method = LUTREADMETHOD_NEXT_L2UC; + else if(read_method == READMETHOD_NEXT_L2UCSPA) + method = LUTREADMETHOD_NEXT_L2UCSPA; + else + return RT_ERR_INPUT; + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(*pAddress > RTK_MAX_LUT_ADDR_ID ) + return RT_ERR_L2_L2UNI_PARAM; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.address = *pAddress; + + if(read_method == READMETHOD_NEXT_L2UCSPA) + l2Table.spa = rtk_switch_port_L2P_get(port); + + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + if(l2Table.address < *pAddress) + return RT_ERR_L2_ENTRY_NOTFOUND; + + memcpy(pL2_data->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN); + pL2_data->port = rtk_switch_port_P2L_get(l2Table.spa); + pL2_data->fid = l2Table.fid; + pL2_data->efid = l2Table.efid; + pL2_data->ivl = l2Table.ivl_svl; + pL2_data->cvid = l2Table.cvid_fid; + pL2_data->is_static = l2Table.nosalearn; + pL2_data->auth = l2Table.auth; + pL2_data->sa_block = l2Table.sa_block; + pL2_data->da_block = l2Table.da_block; + pL2_data->priority = l2Table.lut_pri; + pL2_data->sa_pri_en = l2Table.sa_en; + pL2_data->fwd_pri_en= l2Table.fwd_en; + pL2_data->address = l2Table.address; + + *pAddress = l2Table.address; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_l2_addr_del + * Description: + * Delete LUT unicast entry. + * Input: + * pMac - 6 bytes unicast(I/G bit is 0) mac address to be written into LUT. + * fid - Filtering database + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. + */ +rtk_api_ret_t rtk_l2_addr_del(rtk_mac_t *pMac, rtk_l2_ucastAddr_t *pL2_data) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* must be unicast address */ + if ((pMac == NULL) || (pMac->octet[0] & 0x1)) + return RT_ERR_MAC; + + if (pL2_data->fid > RTL8367C_FIDMAX || pL2_data->efid > RTL8367C_EFIDMAX) + return RT_ERR_L2_FID; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.fid = pL2_data->fid; + l2Table.efid = pL2_data->efid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + memcpy(l2Table.mac.octet, pMac->octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pL2_data->ivl; + l2Table.cvid_fid = pL2_data->cvid; + l2Table.fid = pL2_data->fid; + l2Table.efid = pL2_data->efid; + l2Table.spa = 0; + l2Table.nosalearn = 0; + l2Table.sa_block = 0; + l2Table.da_block = 0; + l2Table.auth = 0; + l2Table.age = 0; + l2Table.lut_pri = 0; + l2Table.sa_en = 0; + l2Table.fwd_en = 0; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pL2_data->address = l2Table.address; + return RT_ERR_OK; + } + else + return retVal; +} + +/* Function Name: + * rtk_l2_mcastAddr_add + * Description: + * Add LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the multicast mac address already existed in the LUT, it will update the + * port mask of the entry. Otherwise, it will find an empty or asic auto learned + * entry to write. If all the entries with the same hash value can't be replaced, + * ASIC will return a RT_ERR_L2_INDEXTBL_FULL error. + */ +rtk_api_ret_t rtk_l2_mcastAddr_add(rtk_l2_mcastAddr_t *pMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMcastAddr) + return RT_ERR_NULL_POINTER; + + /* must be L2 multicast address */ + if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) + return RT_ERR_MAC; + + RTK_CHK_PORTMASK_VALID(&pMcastAddr->portmask); + + if(pMcastAddr->ivl == 1) + { + if (pMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + } + else if(pMcastAddr->ivl == 0) + { + if (pMcastAddr->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + } + else + return RT_ERR_INPUT; + + if(pMcastAddr->fwd_pri_en >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(pMcastAddr->priority > RTL8367C_PRIMAX) + return RT_ERR_INPUT; + + /* Get physical port mask */ + if ((retVal = rtk_switch_portmask_L2P_get(&pMcastAddr->portmask, &pmask)) != RT_ERR_OK) + return retVal; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 0; + l2Table.lut_pri = pMcastAddr->priority; + l2Table.fwd_en = pMcastAddr->fwd_pri_en; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + { + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 0; + l2Table.lut_pri = pMcastAddr->priority; + l2Table.fwd_en = pMcastAddr->fwd_pri_en; + if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pMcastAddr->address = l2Table.address; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + return RT_ERR_L2_INDEXTBL_FULL; + else + return retVal; + } + else + return retVal; + +} + +/* Function Name: + * rtk_l2_mcastAddr_get + * Description: + * Get LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * pMcastAddr - L2 multicast entry structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the multicast mac address existed in the LUT, it will return the port where + * the mac is learned. Otherwise, it will return a RT_ERR_L2_ENTRY_NOTFOUND error. + */ +rtk_api_ret_t rtk_l2_mcastAddr_get(rtk_l2_mcastAddr_t *pMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMcastAddr) + return RT_ERR_NULL_POINTER; + + /* must be L2 multicast address */ + if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) + return RT_ERR_MAC; + + if(pMcastAddr->ivl == 1) + { + if (pMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + } + else if(pMcastAddr->ivl == 0) + { + if (pMcastAddr->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + } + else + return RT_ERR_INPUT; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + method = LUTREADMETHOD_MAC; + + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + pMcastAddr->priority = l2Table.lut_pri; + pMcastAddr->fwd_pri_en = l2Table.fwd_en; + pMcastAddr->igmp_asic = l2Table.igmp_asic; + pMcastAddr->igmp_index = l2Table.igmpidx; + pMcastAddr->address = l2Table.address; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_mcastAddr_next_get + * Description: + * Get Next L2 Multicast entry. + * Input: + * pAddress - The Address ID + * Output: + * pMcastAddr - L2 multicast entry structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next L2 multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all multicast entries is LUT. + */ +rtk_api_ret_t rtk_l2_mcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_mcastAddr_t *pMcastAddr) +{ + rtk_api_ret_t retVal; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error Checking */ + if ((pAddress == NULL) || (pMcastAddr == NULL)) + return RT_ERR_INPUT; + + if(*pAddress > RTK_MAX_LUT_ADDR_ID ) + return RT_ERR_L2_L2UNI_PARAM; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.address = *pAddress; + + if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L2MC, &l2Table)) != RT_ERR_OK) + return retVal; + + if(l2Table.address < *pAddress) + return RT_ERR_L2_ENTRY_NOTFOUND; + + memcpy(pMcastAddr->mac.octet, l2Table.mac.octet, ETHER_ADDR_LEN); + pMcastAddr->ivl = l2Table.ivl_svl; + + if(pMcastAddr->ivl) + pMcastAddr->vid = l2Table.cvid_fid; + else + pMcastAddr->fid = l2Table.cvid_fid; + + pMcastAddr->priority = l2Table.lut_pri; + pMcastAddr->fwd_pri_en = l2Table.fwd_en; + pMcastAddr->igmp_asic = l2Table.igmp_asic; + pMcastAddr->igmp_index = l2Table.igmpidx; + pMcastAddr->address = l2Table.address; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + *pAddress = l2Table.address; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_mcastAddr_del + * Description: + * Delete LUT multicast entry. + * Input: + * pMcastAddr - L2 multicast entry structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MAC - Invalid MAC address. + * RT_ERR_L2_FID - Invalid FID . + * RT_ERR_L2_VID - Invalid VID . + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * If the mac has existed in the LUT, it will be deleted. Otherwise, it will return RT_ERR_L2_ENTRY_NOTFOUND. + */ +rtk_api_ret_t rtk_l2_mcastAddr_del(rtk_l2_mcastAddr_t *pMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMcastAddr) + return RT_ERR_NULL_POINTER; + + /* must be L2 multicast address */ + if( (pMcastAddr->mac.octet[0] & 0x01) != 0x01) + return RT_ERR_MAC; + + if(pMcastAddr->ivl == 1) + { + if (pMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + } + else if(pMcastAddr->ivl == 0) + { + if (pMcastAddr->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + } + else + return RT_ERR_INPUT; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + + /* fill key (MAC,FID) to get L2 entry */ + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + memcpy(l2Table.mac.octet, pMcastAddr->mac.octet, ETHER_ADDR_LEN); + l2Table.ivl_svl = pMcastAddr->ivl; + + if(pMcastAddr->ivl) + l2Table.cvid_fid = pMcastAddr->vid; + else + l2Table.cvid_fid = pMcastAddr->fid; + + l2Table.mbr = 0; + l2Table.nosalearn = 0; + l2Table.sa_block = 0; + l2Table.l3lookup = 0; + l2Table.lut_pri = 0; + l2Table.fwd_en = 0; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else + return retVal; +} + +/* Function Name: + * rtk_l2_ipMcastAddr_add + * Description: + * Add LUT IP multicast entry + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * System supports L2 entry with IP multicast DIP/SIP to forward IP multicasting frame as user + * desired. If this function is enabled, then system will be looked up L2 IP multicast entry to + * forward IP multicast frame directly without flooding. + */ +rtk_api_ret_t rtk_l2_ipMcastAddr_add(rtk_l2_ipMcastAddr_t *pIpMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pIpMcastAddr) + return RT_ERR_NULL_POINTER; + + /* check port mask */ + RTK_CHK_PORTMASK_VALID(&pIpMcastAddr->portmask); + + if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + if(pIpMcastAddr->fwd_pri_en >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pIpMcastAddr->priority > RTL8367C_PRIMAX) + return RT_ERR_INPUT; + + /* Get Physical port mask */ + if ((retVal = rtk_switch_portmask_L2P_get(&pIpMcastAddr->portmask, &pmask)) != RT_ERR_OK) + return retVal; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + l2Table.lut_pri = pIpMcastAddr->priority; + l2Table.fwd_en = pIpMcastAddr->fwd_pri_en; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + { + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + l2Table.lut_pri = pIpMcastAddr->priority; + l2Table.fwd_en = pIpMcastAddr->fwd_pri_en; + if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpMcastAddr->address = l2Table.address; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + return RT_ERR_L2_INDEXTBL_FULL; + else + return retVal; + + } + else + return retVal; + +} + +/* Function Name: + * rtk_l2_ipMcastAddr_get + * Description: + * Get LUT IP multicast entry. + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * pIpMcastAddr - IP Multicast entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LUT table of IP multicast entry. + */ +rtk_api_ret_t rtk_l2_ipMcastAddr_get(rtk_l2_ipMcastAddr_t *pIpMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pIpMcastAddr) + return RT_ERR_NULL_POINTER; + + if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + method = LUTREADMETHOD_MAC; + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + pIpMcastAddr->priority = l2Table.lut_pri; + pIpMcastAddr->fwd_pri_en = l2Table.fwd_en; + pIpMcastAddr->igmp_asic = l2Table.igmp_asic; + pIpMcastAddr->igmp_index = l2Table.igmpidx; + pIpMcastAddr->address = l2Table.address; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastAddr_next_get + * Description: + * Get Next IP Multicast entry. + * Input: + * pAddress - The Address ID + * Output: + * pIpMcastAddr - IP Multicast entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next IP multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all IP multicast entries is LUT. + */ +rtk_api_ret_t rtk_l2_ipMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipMcastAddr_t *pIpMcastAddr) +{ + rtk_api_ret_t retVal; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error Checking */ + if ((pAddress == NULL) || (pIpMcastAddr == NULL) ) + return RT_ERR_INPUT; + + if(*pAddress > RTK_MAX_LUT_ADDR_ID ) + return RT_ERR_L2_L2UNI_PARAM; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.address = *pAddress; + + do + { + if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK) + return retVal; + + if(l2Table.address < *pAddress) + return RT_ERR_L2_ENTRY_NOTFOUND; + + }while(l2Table.l3vidlookup == 1); + + pIpMcastAddr->sip = l2Table.sip; + pIpMcastAddr->dip = l2Table.dip; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + pIpMcastAddr->priority = l2Table.lut_pri; + pIpMcastAddr->fwd_pri_en = l2Table.fwd_en; + pIpMcastAddr->igmp_asic = l2Table.igmp_asic; + pIpMcastAddr->igmp_index = l2Table.igmpidx; + pIpMcastAddr->address = l2Table.address; + *pAddress = l2Table.address; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastAddr_del + * Description: + * Delete a ip multicast address entry from the specified device. + * Input: + * pIpMcastAddr - IP Multicast entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can delete a IP multicast address entry from the specified device. + */ +rtk_api_ret_t rtk_l2_ipMcastAddr_del(rtk_l2_ipMcastAddr_t *pIpMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error Checking */ + if (pIpMcastAddr == NULL) + return RT_ERR_INPUT; + + if( (pIpMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + l2Table.sip = pIpMcastAddr->sip; + l2Table.dip = pIpMcastAddr->dip; + l2Table.mbr = 0; + l2Table.nosalearn = 0; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 0; + l2Table.lut_pri = 0; + l2Table.fwd_en = 0; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else + return retVal; +} + +/* Function Name: + * rtk_l2_ipVidMcastAddr_add + * Description: + * Add LUT IP multicast+VID entry + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_L2_INDEXTBL_FULL - hashed index is full of entries. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_l2_ipVidMcastAddr_add(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pIpVidMcastAddr) + return RT_ERR_NULL_POINTER; + + /* check port mask */ + RTK_CHK_PORTMASK_VALID(&pIpVidMcastAddr->portmask); + + if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + /* Get Physical port mask */ + if ((retVal = rtk_switch_portmask_L2P_get(&pIpVidMcastAddr->portmask, &pmask)) != RT_ERR_OK) + return retVal; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpVidMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + { + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.mbr = pmask; + l2Table.nosalearn = 1; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + if ((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpVidMcastAddr->address = l2Table.address; + + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_L2_ENTRY_NOTFOUND == retVal) + return RT_ERR_L2_INDEXTBL_FULL; + else + return retVal; + + } + else + return retVal; +} + +/* Function Name: + * rtk_l2_ipVidMcastAddr_get + * Description: + * Get LUT IP multicast+VID entry. + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * pIpVidMcastAddr - IP & VID multicast Entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_l2_ipVidMcastAddr_get(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pIpVidMcastAddr) + return RT_ERR_NULL_POINTER; + + if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + method = LUTREADMETHOD_MAC; + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + pIpVidMcastAddr->address = l2Table.address; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipVidMcastAddr_next_get + * Description: + * Get Next IP Multicast+VID entry. + * Input: + * pAddress - The Address ID + * Output: + * pIpVidMcastAddr - IP & VID multicast Entry + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the next IP multicast entry after the current entry pointed by pAddress. + * The address of next entry is returned by pAddress. User can use (address + 1) + * as pAddress to call this API again for dumping all IP multicast entries is LUT. + */ +rtk_api_ret_t rtk_l2_ipVidMcastAddr_next_get(rtk_uint32 *pAddress, rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) +{ + rtk_api_ret_t retVal; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error Checking */ + if ((pAddress == NULL) || (pIpVidMcastAddr == NULL)) + return RT_ERR_INPUT; + + if(*pAddress > RTK_MAX_LUT_ADDR_ID ) + return RT_ERR_L2_L2UNI_PARAM; + + memset(&l2Table, 0, sizeof(rtl8367c_luttb)); + l2Table.address = *pAddress; + + do + { + if ((retVal = rtl8367c_getAsicL2LookupTb(LUTREADMETHOD_NEXT_L3MC, &l2Table)) != RT_ERR_OK) + return retVal; + + if(l2Table.address < *pAddress) + return RT_ERR_L2_ENTRY_NOTFOUND; + + }while(l2Table.l3vidlookup == 0); + + pIpVidMcastAddr->sip = l2Table.sip; + pIpVidMcastAddr->dip = l2Table.dip; + pIpVidMcastAddr->vid = l2Table.l3_vid; + pIpVidMcastAddr->address = l2Table.address; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &pIpVidMcastAddr->portmask)) != RT_ERR_OK) + return retVal; + + *pAddress = l2Table.address; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipVidMcastAddr_del + * Description: + * Delete a ip multicast+VID address entry from the specified device. + * Input: + * pIpVidMcastAddr - IP & VID multicast Entry + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_ENTRY_NOTFOUND - No such LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_l2_ipVidMcastAddr_del(rtk_l2_ipVidMcastAddr_t *pIpVidMcastAddr) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pIpVidMcastAddr) + return RT_ERR_NULL_POINTER; + + if (pIpVidMcastAddr->vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if( (pIpVidMcastAddr->dip & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + method = LUTREADMETHOD_MAC; + retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table); + if (RT_ERR_OK == retVal) + { + l2Table.sip = pIpVidMcastAddr->sip; + l2Table.dip = pIpVidMcastAddr->dip; + l2Table.mbr= 0; + l2Table.nosalearn = 0; + l2Table.l3lookup = 1; + l2Table.l3vidlookup = 1; + l2Table.l3_vid = pIpVidMcastAddr->vid; + if((retVal = rtl8367c_setAsicL2LookupTb(&l2Table)) != RT_ERR_OK) + return retVal; + + pIpVidMcastAddr->address = l2Table.address; + return RT_ERR_OK; + } + else + return retVal; +} + +/* Function Name: + * rtk_l2_ucastAddr_flush + * Description: + * Flush L2 mac address by type in the specified device (both dynamic and static). + * Input: + * pConfig - flush configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * flushByVid - 1: Flush by VID, 0: Don't flush by VID + * vid - VID (0 ~ 4095) + * flushByFid - 1: Flush by FID, 0: Don't flush by FID + * fid - FID (0 ~ 15) + * flushByPort - 1: Flush by Port, 0: Don't flush by Port + * port - Port ID + * flushByMac - Not Supported + * ucastAddr - Not Supported + * flushStaticAddr - 1: Flush both Static and Dynamic entries, 0: Flush only Dynamic entries + * flushAddrOnAllPorts - 1: Flush VID-matched entries at all ports, 0: Flush VID-matched entries per port. + */ +rtk_api_ret_t rtk_l2_ucastAddr_flush(rtk_l2_flushCfg_t *pConfig) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pConfig == NULL) + return RT_ERR_NULL_POINTER; + + if(pConfig->flushByVid >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->flushByFid >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->flushByPort >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->flushByMac >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->flushStaticAddr >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->flushAddrOnAllPorts >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pConfig->vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if(pConfig->fid > RTL8367C_FIDMAX) + return RT_ERR_INPUT; + + /* check port valid */ + RTK_CHK_PORT_VALID(pConfig->port); + + if(pConfig->flushByVid == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_VID)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutFlushVid(pConfig->vid)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) + return retVal; + + if(pConfig->flushAddrOnAllPorts == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK) + return retVal; + } + else if(pConfig->flushByPort == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + } + else if(pConfig->flushByFid == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_FID)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutFlushFid(pConfig->fid)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) + return retVal; + + if(pConfig->flushAddrOnAllPorts == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutForceFlush(RTL8367C_PORTMASK)) != RT_ERR_OK) + return retVal; + } + else if(pConfig->flushByPort == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + } + else if(pConfig->flushByPort == ENABLED) + { + if ((retVal = rtl8367c_setAsicLutFlushType((pConfig->flushStaticAddr == ENABLED) ? FLUSHTYPE_BOTH : FLUSHTYPE_DYNAMIC)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutFlushMode(FLUSHMDOE_PORT)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutForceFlush(1 << rtk_switch_port_L2P_get(pConfig->port))) != RT_ERR_OK) + return retVal; + } + else if(pConfig->flushByMac == ENABLED) + { + /* Should use API "rtk_l2_addr_del" to remove a specified entry*/ + return RT_ERR_CHIP_NOT_SUPPORTED; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_table_clear + * Description: + * Flush all static & dynamic entries in LUT. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_l2_table_clear(void) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_setAsicLutFlushAll()) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_table_clearStatus_get + * Description: + * Get table clear status + * Input: + * None + * Output: + * pStatus - Clear status, 1:Busy, 0:finish + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_l2_table_clearStatus_get(rtk_l2_clearStatus_t *pStatus) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pStatus) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutFlushAllStatus((rtk_uint32 *)pStatus)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_flushLinkDownPortAddrEnable_set + * Description: + * Set HW flush linkdown port mac configuration of the specified device. + * Input: + * port - Port id. + * enable - link down flush status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The status of flush linkdown port address is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicLutLinkDownForceAging(enable)) != RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_flushLinkDownPortAddrEnable_get + * Description: + * Get HW flush linkdown port mac configuration of the specified device. + * Input: + * port - Port id. + * Output: + * pEnable - link down flush status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The status of flush linkdown port address is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_l2_flushLinkDownPortAddrEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutLinkDownForceAging(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_agingEnable_set + * Description: + * Set L2 LUT aging status per port setting. + * Input: + * port - Port id. + * enable - Aging status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can be used to set L2 LUT aging status per port. + */ +rtk_api_ret_t rtk_l2_agingEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(enable == 1) + enable = 0; + else + enable = 1; + + if ((retVal = rtl8367c_setAsicLutDisableAging(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_agingEnable_get + * Description: + * Get L2 LUT aging status per port setting. + * Input: + * port - Port id. + * Output: + * pEnable - Aging status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can be used to get L2 LUT aging function per port. + */ +rtk_api_ret_t rtk_l2_agingEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutDisableAging(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + if(*pEnable == 1) + *pEnable = 0; + else + *pEnable = 1; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitLearningCnt_set + * Description: + * Set per-Port auto learning limit number + * Input: + * port - Port id. + * mac_cnt - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * The API can set per-port ASIC auto learning limit number from 0(disable learning) + * to 2112. + */ +rtk_api_ret_t rtk_l2_limitLearningCnt_set(rtk_port_t port, rtk_mac_cnt_t mac_cnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if (mac_cnt > rtk_switch_maxLutAddrNumber_get()) + return RT_ERR_LIMITED_L2ENTRY_NUM; + + if ((retVal = rtl8367c_setAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), mac_cnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitLearningCnt_get + * Description: + * Get per-Port auto learning limit number + * Input: + * port - Port id. + * Output: + * pMac_cnt - Auto learning entries limit number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get per-port ASIC auto learning limit number. + */ +rtk_api_ret_t rtk_l2_limitLearningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pMac_cnt) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutLearnLimitNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCnt_set + * Description: + * Set System auto learning limit number + * Input: + * mac_cnt - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * The API can set system ASIC auto learning limit number from 0(disable learning) + * to 2112. + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCnt_set(rtk_mac_cnt_t mac_cnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (mac_cnt > rtk_switch_maxLutAddrNumber_get()) + return RT_ERR_LIMITED_L2ENTRY_NUM; + + if ((retVal = rtl8367c_setAsicSystemLutLearnLimitNo(mac_cnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCnt_get + * Description: + * Get System auto learning limit number + * Input: + * None + * Output: + * pMac_cnt - Auto learning entries limit number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get system ASIC auto learning limit number. + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCnt_get(rtk_mac_cnt_t *pMac_cnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMac_cnt) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSystemLutLearnLimitNo(pMac_cnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitLearningCntAction_set + * Description: + * Configure auto learn over limit number action. + * Input: + * port - Port id. + * action - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * The API can set SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +rtk_api_ret_t rtk_l2_limitLearningCntAction_set(rtk_port_t port, rtk_l2_limitLearnCntAction_t action) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if ( LIMIT_LEARN_CNT_ACTION_DROP == action ) + data = 1; + else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action ) + data = 0; + else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action ) + data = 2; + else + return RT_ERR_NOT_ALLOWED; + + if ((retVal = rtl8367c_setAsicLutLearnOverAct(data)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitLearningCntAction_get + * Description: + * Get auto learn over limit number action. + * Input: + * port - Port id. + * Output: + * pAction - Learn over action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +rtk_api_ret_t rtk_l2_limitLearningCntAction_get(rtk_port_t port, rtk_l2_limitLearnCntAction_t *pAction) +{ + rtk_api_ret_t retVal; + rtk_uint32 action; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutLearnOverAct(&action)) != RT_ERR_OK) + return retVal; + + if ( 1 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_DROP; + else if ( 0 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD; + else if ( 2 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU; + else + *pAction = action; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCntAction_set + * Description: + * Configure system auto learn over limit number action. + * Input: + * port - Port id. + * action - Auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * The API can set SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_set(rtk_l2_limitLearnCntAction_t action) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ( LIMIT_LEARN_CNT_ACTION_DROP == action ) + data = 1; + else if ( LIMIT_LEARN_CNT_ACTION_FORWARD == action ) + data = 0; + else if ( LIMIT_LEARN_CNT_ACTION_TO_CPU == action ) + data = 2; + else + return RT_ERR_NOT_ALLOWED; + + if ((retVal = rtl8367c_setAsicSystemLutLearnOverAct(data)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCntAction_get + * Description: + * Get system auto learn over limit number action. + * Input: + * None. + * Output: + * pAction - Learn over action + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get SA unknown packet action while auto learn limit number is over + * The action symbol as following: + * - LIMIT_LEARN_CNT_ACTION_DROP, + * - LIMIT_LEARN_CNT_ACTION_FORWARD, + * - LIMIT_LEARN_CNT_ACTION_TO_CPU, + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCntAction_get(rtk_l2_limitLearnCntAction_t *pAction) +{ + rtk_api_ret_t retVal; + rtk_uint32 action; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSystemLutLearnOverAct(&action)) != RT_ERR_OK) + return retVal; + + if ( 1 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_DROP; + else if ( 0 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_FORWARD; + else if ( 2 == action ) + *pAction = LIMIT_LEARN_CNT_ACTION_TO_CPU; + else + *pAction = action; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCntPortMask_set + * Description: + * Configure system auto learn portmask + * Input: + * pPortmask - Port Mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + /* Check port mask */ + RTK_CHK_PORTMASK_VALID(pPortmask); + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicSystemLutLearnPortMask(pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_limitSystemLearningCntPortMask_get + * Description: + * get system auto learn portmask + * Input: + * None + * Output: + * pPortmask - Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer. + * Note: + * + */ +rtk_api_ret_t rtk_l2_limitSystemLearningCntPortMask_get(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSystemLutLearnPortMask(&pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_learningCnt_get + * Description: + * Get per-Port current auto learning number + * Input: + * port - Port id. + * Output: + * pMac_cnt - ASIC auto learning entries number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get per-port ASIC auto learning number + */ +rtk_api_ret_t rtk_l2_learningCnt_get(rtk_port_t port, rtk_mac_cnt_t *pMac_cnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pMac_cnt) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutLearnNo(rtk_switch_port_L2P_get(port), pMac_cnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_floodPortMask_set + * Description: + * Set flooding portmask + * Input: + * type - flooding type. + * pFlood_portmask - flooding portmask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set the flooding mask. + * The flooding type is as following: + * - FLOOD_UNKNOWNDA + * - FLOOD_UNKNOWNMC + * - FLOOD_BC + */ +rtk_api_ret_t rtk_l2_floodPortMask_set(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (floood_type >= FLOOD_END) + return RT_ERR_INPUT; + + /* check port valid */ + RTK_CHK_PORTMASK_VALID(pFlood_portmask); + + /* Get Physical port mask */ + if ((retVal = rtk_switch_portmask_L2P_get(pFlood_portmask, &pmask))!=RT_ERR_OK) + return retVal; + + switch (floood_type) + { + case FLOOD_UNKNOWNDA: + if ((retVal = rtl8367c_setAsicPortUnknownDaFloodingPortmask(pmask)) != RT_ERR_OK) + return retVal; + break; + case FLOOD_UNKNOWNMC: + if ((retVal = rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(pmask)) != RT_ERR_OK) + return retVal; + break; + case FLOOD_BC: + if ((retVal = rtl8367c_setAsicPortBcastFloodingPortmask(pmask)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtk_l2_floodPortMask_get + * Description: + * Get flooding portmask + * Input: + * type - flooding type. + * Output: + * pFlood_portmask - flooding portmask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get the flooding mask. + * The flooding type is as following: + * - FLOOD_UNKNOWNDA + * - FLOOD_UNKNOWNMC + * - FLOOD_BC + */ +rtk_api_ret_t rtk_l2_floodPortMask_get(rtk_l2_flood_type_t floood_type, rtk_portmask_t *pFlood_portmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (floood_type >= FLOOD_END) + return RT_ERR_INPUT; + + if(NULL == pFlood_portmask) + return RT_ERR_NULL_POINTER; + + switch (floood_type) + { + case FLOOD_UNKNOWNDA: + if ((retVal = rtl8367c_getAsicPortUnknownDaFloodingPortmask(&pmask)) != RT_ERR_OK) + return retVal; + break; + case FLOOD_UNKNOWNMC: + if ((retVal = rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(&pmask)) != RT_ERR_OK) + return retVal; + break; + case FLOOD_BC: + if ((retVal = rtl8367c_getAsicPortBcastFloodingPortmask(&pmask)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pFlood_portmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_localPktPermit_set + * Description: + * Set permission of frames if source port and destination port are the same. + * Input: + * port - Port id. + * permit - permission status + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid permit value. + * Note: + * This API is set to permit frame if its source port is equal to destination port. + */ +rtk_api_ret_t rtk_l2_localPktPermit_set(rtk_port_t port, rtk_enable_t permit) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if (permit >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortBlockSpa(rtk_switch_port_L2P_get(port), permit)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_localPktPermit_get + * Description: + * Get permission of frames if source port and destination port are the same. + * Input: + * port - Port id. + * Output: + * pPermit - permission status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API is to get permission status for frames if its source port is equal to destination port. + */ +rtk_api_ret_t rtk_l2_localPktPermit_get(rtk_port_t port, rtk_enable_t *pPermit) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pPermit) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortBlockSpa(rtk_switch_port_L2P_get(port), pPermit)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_aging_set + * Description: + * Set LUT ageing out speed + * Input: + * aging_time - Ageing out time. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can set LUT ageing out period for each entry and the range is from 45s to 458s. + */ +rtk_api_ret_t rtk_l2_aging_set(rtk_l2_age_time_t aging_time) +{ + rtk_uint32 i; + CONST_T rtk_uint32 agePara[10][3] = { + {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7}, + {354, 2, 6}, {413, 2, 7}, {458, 3, 7}}; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (aging_time>agePara[9][0]) + return RT_ERR_OUT_OF_RANGE; + + for (i = 0; i<10; i++) + { + if (aging_time<=agePara[i][0]) + { + return rtl8367c_setAsicLutAgeTimerSpeed(agePara[i][2], agePara[i][1]); + } + } + + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_l2_aging_get + * Description: + * Get LUT ageing out time + * Input: + * None + * Output: + * pEnable - Aging status + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get LUT ageing out period for each entry. + */ +rtk_api_ret_t rtk_l2_aging_get(rtk_l2_age_time_t *pAging_time) +{ + rtk_api_ret_t retVal; + rtk_uint32 i,time, speed; + CONST_T rtk_uint32 agePara[10][3] = { + {45, 0, 1}, {88, 0, 2}, {133, 0, 3}, {177, 0, 4}, {221, 0, 5}, {266, 0, 6}, {310, 0, 7}, + {354, 2, 6}, {413, 2, 7}, {458, 3, 7}}; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAging_time) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLutAgeTimerSpeed(&time, &speed)) != RT_ERR_OK) + return retVal; + + for (i = 0; i<10; i++) + { + if (time==agePara[i][2]&&speed==agePara[i][1]) + { + *pAging_time = agePara[i][0]; + return RT_ERR_OK; + } + } + + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_l2_ipMcastAddrLookup_set + * Description: + * Set LUT IP multicast lookup function + * Input: + * type - Lookup type for IPMC packet. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * LOOKUP_MAC - Lookup by MAC address + * LOOKUP_IP - Lookup by IP address + * LOOKUP_IP_VID - Lookup by IP address & VLAN ID + */ +rtk_api_ret_t rtk_l2_ipMcastAddrLookup_set(rtk_l2_ipmc_lookup_type_t type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(type == LOOKUP_MAC) + { + if((retVal = rtl8367c_setAsicLutIpMulticastLookup(DISABLED)) != RT_ERR_OK) + return retVal; + } + else if(type == LOOKUP_IP) + { + if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(DISABLED))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) + return retVal; + } + else if(type == LOOKUP_IP_VID) + { + if((retVal = rtl8367c_setAsicLutIpMulticastLookup(ENABLED)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutIpMulticastVidLookup(ENABLED))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastAddrLookup_get + * Description: + * Get LUT IP multicast lookup function + * Input: + * None. + * Output: + * pType - Lookup type for IPMC packet. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +rtk_api_ret_t rtk_l2_ipMcastAddrLookup_get(rtk_l2_ipmc_lookup_type_t *pType) +{ + rtk_api_ret_t retVal; + rtk_uint32 enabled, vid_lookup; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pType) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicLutIpMulticastLookup(&enabled)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicLutIpMulticastVidLookup(&vid_lookup))!=RT_ERR_OK) + return retVal; + + if(enabled == ENABLED) + { + if(vid_lookup == ENABLED) + *pType = LOOKUP_IP_VID; + else + *pType = LOOKUP_IP; + } + else + *pType = LOOKUP_MAC; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastForwardRouterPort_set + * Description: + * Set IPMC packet forward to router port also or not + * Input: + * enabled - 1: Include router port, 0, exclude router port + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enabled >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if((retVal = rtl8367c_setAsicLutIpmcFwdRouterPort(enabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastForwardRouterPort_get + * Description: + * Get IPMC packet forward to router port also or not + * Input: + * None. + * Output: + * pEnabled - 1: Include router port, 0, exclude router port + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_l2_ipMcastForwardRouterPort_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicLutIpmcFwdRouterPort(pEnabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_add + * Description: + * Add an IP Multicast entry to group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * pPortmask - portmask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Add an entry to IP Multicast Group table. + */ +rtk_api_ret_t rtk_l2_ipMcastGroupEntry_add(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask) +{ + rtk_uint32 empty_idx = 0xFFFF; + rtk_int32 index; + ipaddr_t group_addr; + rtk_uint32 group_vid; + rtk_uint32 pmask; + rtk_uint32 valid; + rtk_uint32 physicalPortmask; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if((ip_addr & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + /* Get Physical port mask */ + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &physicalPortmask))!=RT_ERR_OK) + return retVal; + + for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) + { + if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) + return retVal; + + if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) + { + if(pmask != physicalPortmask) + { + pmask = physicalPortmask; + if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, ip_addr, vid, pmask, valid))!=RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; + } + + if( (valid == DISABLED) && (empty_idx == 0xFFFF) ) /* Unused */ + empty_idx = (rtk_uint32)index; + } + + if(empty_idx == 0xFFFF) + return RT_ERR_TBL_FULL; + + pmask = physicalPortmask; + if ((retVal = rtl8367c_setAsicLutIPMCGroup(empty_idx, ip_addr, vid, pmask, ENABLED))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_del + * Description: + * Delete an entry from IP Multicast group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Delete an entry from IP Multicast group table. + */ +rtk_api_ret_t rtk_l2_ipMcastGroupEntry_del(ipaddr_t ip_addr, rtk_uint32 vid) +{ + rtk_int32 index; + ipaddr_t group_addr; + rtk_uint32 group_vid; + rtk_uint32 pmask; + rtk_uint32 valid; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if((ip_addr & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) + { + if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) + return retVal; + + if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) + { + group_addr = 0xE0000000; + group_vid = 0; + pmask = 0; + if ((retVal = rtl8367c_setAsicLutIPMCGroup(index, group_addr, group_vid, pmask, DISABLED))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_l2_ipMcastGroupEntry_get + * Description: + * get an entry from IP Multicast group table + * Input: + * ip_addr - IP address + * vid - VLAN ID + * Output: + * pPortmask - member port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_TBL_FULL - Table Full + * Note: + * Delete an entry from IP Multicast group table. + */ +rtk_api_ret_t rtk_l2_ipMcastGroupEntry_get(ipaddr_t ip_addr, rtk_uint32 vid, rtk_portmask_t *pPortmask) +{ + rtk_int32 index; + ipaddr_t group_addr; + rtk_uint32 group_vid; + rtk_uint32 valid; + rtk_uint32 pmask; + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if((ip_addr & 0xF0000000) != 0xE0000000) + return RT_ERR_INPUT; + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_L2_VID; + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + for(index = 0; index <= RTL8367C_LUT_IPMCGRP_TABLE_MAX; index++) + { + if ((retVal = rtl8367c_getAsicLutIPMCGroup((rtk_uint32)index, &group_addr, &group_vid, &pmask, &valid))!=RT_ERR_OK) + return retVal; + + if( (valid == ENABLED) && (group_addr == ip_addr) && (group_vid == vid) ) + { + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_l2_entry_get + * Description: + * Get LUT unicast entry. + * Input: + * pL2_entry - Index field in the structure. + * Output: + * pL2_entry - other fields such as MAC, port, age... + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_EMPTY_ENTRY - Empty LUT entry. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API is used to get address by index from 0~2111. + */ +rtk_api_ret_t rtk_l2_entry_get(rtk_l2_addr_table_t *pL2_entry) +{ + rtk_api_ret_t retVal; + rtk_uint32 method; + rtl8367c_luttb l2Table; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (pL2_entry->index >= rtk_switch_maxLutAddrNumber_get()) + return RT_ERR_INPUT; + + memset(&l2Table, 0x00, sizeof(rtl8367c_luttb)); + l2Table.address= pL2_entry->index; + method = LUTREADMETHOD_ADDRESS; + if ((retVal = rtl8367c_getAsicL2LookupTb(method, &l2Table)) != RT_ERR_OK) + return retVal; + + if ((pL2_entry->index>0x800)&&(l2Table.lookup_hit==0)) + return RT_ERR_L2_EMPTY_ENTRY; + + if(l2Table.l3lookup) + { + if(l2Table.l3vidlookup) + { + memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t)); + pL2_entry->is_ipmul = l2Table.l3lookup; + pL2_entry->sip = l2Table.sip; + pL2_entry->dip = l2Table.dip; + pL2_entry->is_static = l2Table.nosalearn; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) + return retVal; + + pL2_entry->fid = 0; + pL2_entry->age = 0; + pL2_entry->auth = 0; + pL2_entry->sa_block = 0; + pL2_entry->is_ipvidmul = 1; + pL2_entry->l3_vid = l2Table.l3_vid; + } + else + { + memset(&pL2_entry->mac, 0, sizeof(rtk_mac_t)); + pL2_entry->is_ipmul = l2Table.l3lookup; + pL2_entry->sip = l2Table.sip; + pL2_entry->dip = l2Table.dip; + pL2_entry->is_static = l2Table.nosalearn; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) + return retVal; + + pL2_entry->fid = 0; + pL2_entry->age = 0; + pL2_entry->auth = 0; + pL2_entry->sa_block = 0; + pL2_entry->is_ipvidmul = 0; + pL2_entry->l3_vid = 0; + } + } + else if(l2Table.mac.octet[0]&0x01) + { + memset(&pL2_entry->sip, 0, sizeof(ipaddr_t)); + memset(&pL2_entry->dip, 0, sizeof(ipaddr_t)); + pL2_entry->mac.octet[0] = l2Table.mac.octet[0]; + pL2_entry->mac.octet[1] = l2Table.mac.octet[1]; + pL2_entry->mac.octet[2] = l2Table.mac.octet[2]; + pL2_entry->mac.octet[3] = l2Table.mac.octet[3]; + pL2_entry->mac.octet[4] = l2Table.mac.octet[4]; + pL2_entry->mac.octet[5] = l2Table.mac.octet[5]; + pL2_entry->is_ipmul = l2Table.l3lookup; + pL2_entry->is_static = l2Table.nosalearn; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(l2Table.mbr, &(pL2_entry->portmask)))!=RT_ERR_OK) + return retVal; + + pL2_entry->ivl = l2Table.ivl_svl; + if(l2Table.ivl_svl == 1) /* IVL */ + { + pL2_entry->cvid = l2Table.cvid_fid; + pL2_entry->fid = 0; + } + else /* SVL*/ + { + pL2_entry->cvid = 0; + pL2_entry->fid = l2Table.cvid_fid; + } + pL2_entry->auth = l2Table.auth; + pL2_entry->sa_block = l2Table.sa_block; + pL2_entry->age = 0; + pL2_entry->is_ipvidmul = 0; + pL2_entry->l3_vid = 0; + } + else if((l2Table.age != 0)||(l2Table.nosalearn == 1)) + { + memset(&pL2_entry->sip, 0, sizeof(ipaddr_t)); + memset(&pL2_entry->dip, 0, sizeof(ipaddr_t)); + pL2_entry->mac.octet[0] = l2Table.mac.octet[0]; + pL2_entry->mac.octet[1] = l2Table.mac.octet[1]; + pL2_entry->mac.octet[2] = l2Table.mac.octet[2]; + pL2_entry->mac.octet[3] = l2Table.mac.octet[3]; + pL2_entry->mac.octet[4] = l2Table.mac.octet[4]; + pL2_entry->mac.octet[5] = l2Table.mac.octet[5]; + pL2_entry->is_ipmul = l2Table.l3lookup; + pL2_entry->is_static = l2Table.nosalearn; + + /* Get Logical port mask */ + if ((retVal = rtk_switch_portmask_P2L_get(1<<(l2Table.spa), &(pL2_entry->portmask)))!=RT_ERR_OK) + return retVal; + + pL2_entry->ivl = l2Table.ivl_svl; + pL2_entry->cvid = l2Table.cvid_fid; + pL2_entry->fid = l2Table.fid; + pL2_entry->auth = l2Table.auth; + pL2_entry->sa_block = l2Table.sa_block; + pL2_entry->age = l2Table.age; + pL2_entry->is_ipvidmul = 0; + pL2_entry->l3_vid = 0; + } + else + return RT_ERR_L2_EMPTY_ENTRY; + + return RT_ERR_OK; +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/leaky.c b/drivers/net/phy/rtk/rtl8367c/leaky.c new file mode 100644 index 000000000000..1b7d50a9e547 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/leaky.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Leaky module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* Function Name: + * rtk_leaky_vlan_set + * Description: + * Set VLAN leaky. + * Input: + * type - Packet type for VLAN leaky. + * enable - Leaky status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input + * Note: + * This API can set VLAN leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +rtk_api_ret_t rtk_leaky_vlan_set(rtk_leaky_type_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= LEAKY_END) + return RT_ERR_INPUT; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.vlan_leaky = enable; + + if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_IPMULTICAST == type) + { + for (port = 0; port <= RTK_PORT_ID_MAX; port++) + { + if ((retVal = rtl8367c_setAsicIpMulticastVlanLeaky(port,enable)) != RT_ERR_OK) + return retVal; + } + } + else if (LEAKY_IGMP == type) + { + if ((retVal = rtl8367c_setAsicIGMPVLANLeaky(enable)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_CDP == type) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.vlan_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_CSSTP == type) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.vlan_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_LLDP == type) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.vlan_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_leaky_vlan_get + * Description: + * Get VLAN leaky. + * Input: + * type - Packet type for VLAN leaky. + * Output: + * pEnable - Leaky status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get VLAN leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +rtk_api_ret_t rtk_leaky_vlan_get(rtk_leaky_type_t type, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port,tmp; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= LEAKY_END) + return RT_ERR_INPUT; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.vlan_leaky; + + } + else if (LEAKY_IPMULTICAST == type) + { + for (port = 0; port <= RTK_PORT_ID_MAX; port++) + { + if ((retVal = rtl8367c_getAsicIpMulticastVlanLeaky(port, &tmp)) != RT_ERR_OK) + return retVal; + if (port>0&&(tmp!=*pEnable)) + return RT_ERR_FAILED; + *pEnable = tmp; + } + } + else if (LEAKY_IGMP == type) + { + if ((retVal = rtl8367c_getAsicIGMPVLANLeaky(&tmp)) != RT_ERR_OK) + return retVal; + + *pEnable = tmp; + } + else if (LEAKY_CDP == type) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.vlan_leaky; + } + else if (LEAKY_CSSTP == type) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.vlan_leaky; + } + else if (LEAKY_LLDP == type) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.vlan_leaky; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_leaky_portIsolation_set + * Description: + * Set port isolation leaky. + * Input: + * type - Packet type for port isolation leaky. + * enable - Leaky status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input + * Note: + * This API can set port isolation leaky for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +rtk_api_ret_t rtk_leaky_portIsolation_set(rtk_leaky_type_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= LEAKY_END) + return RT_ERR_INPUT; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.portiso_leaky = enable; + + if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_IPMULTICAST == type) + { + for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++) + { + if ((retVal = rtl8367c_setAsicIpMulticastPortIsoLeaky(port,enable)) != RT_ERR_OK) + return retVal; + } + } + else if (LEAKY_IGMP == type) + { + if ((retVal = rtl8367c_setAsicIGMPIsoLeaky(enable)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_CDP == type) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.portiso_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_CSSTP == type) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.portiso_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (LEAKY_LLDP == type) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.portiso_leaky = enable; + + if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_leaky_portIsolation_get + * Description: + * Get port isolation leaky. + * Input: + * type - Packet type for port isolation leaky. + * Output: + * pEnable - Leaky status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get port isolation leaky status for RMA ,IGMP/MLD, CDP, CSSTP, and LLDP packets. + * The leaky frame types are as following: + * - LEAKY_BRG_GROUP, + * - LEAKY_FD_PAUSE, + * - LEAKY_SP_MCAST, + * - LEAKY_1X_PAE, + * - LEAKY_UNDEF_BRG_04, + * - LEAKY_UNDEF_BRG_05, + * - LEAKY_UNDEF_BRG_06, + * - LEAKY_UNDEF_BRG_07, + * - LEAKY_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - LEAKY_UNDEF_BRG_09, + * - LEAKY_UNDEF_BRG_0A, + * - LEAKY_UNDEF_BRG_0B, + * - LEAKY_UNDEF_BRG_0C, + * - LEAKY_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - LEAKY_8021AB, + * - LEAKY_UNDEF_BRG_0F, + * - LEAKY_BRG_MNGEMENT, + * - LEAKY_UNDEFINED_11, + * - LEAKY_UNDEFINED_12, + * - LEAKY_UNDEFINED_13, + * - LEAKY_UNDEFINED_14, + * - LEAKY_UNDEFINED_15, + * - LEAKY_UNDEFINED_16, + * - LEAKY_UNDEFINED_17, + * - LEAKY_UNDEFINED_18, + * - LEAKY_UNDEFINED_19, + * - LEAKY_UNDEFINED_1A, + * - LEAKY_UNDEFINED_1B, + * - LEAKY_UNDEFINED_1C, + * - LEAKY_UNDEFINED_1D, + * - LEAKY_UNDEFINED_1E, + * - LEAKY_UNDEFINED_1F, + * - LEAKY_GMRP, + * - LEAKY_GVRP, + * - LEAKY_UNDEF_GARP_22, + * - LEAKY_UNDEF_GARP_23, + * - LEAKY_UNDEF_GARP_24, + * - LEAKY_UNDEF_GARP_25, + * - LEAKY_UNDEF_GARP_26, + * - LEAKY_UNDEF_GARP_27, + * - LEAKY_UNDEF_GARP_28, + * - LEAKY_UNDEF_GARP_29, + * - LEAKY_UNDEF_GARP_2A, + * - LEAKY_UNDEF_GARP_2B, + * - LEAKY_UNDEF_GARP_2C, + * - LEAKY_UNDEF_GARP_2D, + * - LEAKY_UNDEF_GARP_2E, + * - LEAKY_UNDEF_GARP_2F, + * - LEAKY_IGMP, + * - LEAKY_IPMULTICAST. + * - LEAKY_CDP, + * - LEAKY_CSSTP, + * - LEAKY_LLDP. + */ +rtk_api_ret_t rtk_leaky_portIsolation_get(rtk_leaky_type_t type, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port, tmp; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= LEAKY_END) + return RT_ERR_INPUT; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if (type >= 0 && type <= LEAKY_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.portiso_leaky; + + } + else if (LEAKY_IPMULTICAST == type) + { + for (port = 0; port < RTK_MAX_NUM_OF_PORT; port++) + { + if ((retVal = rtl8367c_getAsicIpMulticastPortIsoLeaky(port, &tmp)) != RT_ERR_OK) + return retVal; + if (port > 0 &&(tmp != *pEnable)) + return RT_ERR_FAILED; + *pEnable = tmp; + } + } + else if (LEAKY_IGMP == type) + { + if ((retVal = rtl8367c_getAsicIGMPIsoLeaky(&tmp)) != RT_ERR_OK) + return retVal; + + *pEnable = tmp; + } + else if (LEAKY_CDP == type) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.portiso_leaky; + } + else if (LEAKY_CSSTP == type) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.portiso_leaky; + } + else if (LEAKY_LLDP == type) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.portiso_leaky; + } + + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/led.c b/drivers/net/phy/rtk/rtl8367c/led.c new file mode 100644 index 000000000000..02e0829dc6e6 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/led.c @@ -0,0 +1,792 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in LED module. + * + */ + +#include +#include +#include +#include + +#include +#include + + +/* Function Name: + * rtk_led_enable_set + * Description: + * Set Led enable configuration + * Input: + * group - LED group id. + * pPortmask - LED enable port mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_MASK - Error portmask + * Note: + * The API can be used to enable LED per port per group. + */ +rtk_api_ret_t rtk_led_enable_set(rtk_led_group_t group, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + rtk_port_t port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (group >= LED_GROUP_END) + return RT_ERR_INPUT; + + RTK_CHK_PORTMASK_VALID(pPortmask); + + RTK_PORTMASK_SCAN((*pPortmask), port) + { + if(rtk_switch_isCPUPort(port) == RT_ERR_OK) + return RT_ERR_PORT_MASK; + } + + if((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLedGroupEnable(group, pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_enable_get + * Description: + * Get Led enable configuration + * Input: + * group - LED group id. + * Output: + * pPortmask - LED enable port mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can be used to get LED enable status. + */ +rtk_api_ret_t rtk_led_enable_get(rtk_led_group_t group, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (group >= LED_GROUP_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicLedGroupEnable(group, &pmask)) != RT_ERR_OK) + return retVal; + + if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_led_operation_set + * Description: + * Set Led operation mode + * Input: + * mode - LED operation mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set Led operation mode. + * The modes that can be set are as following: + * - LED_OP_SCAN, + * - LED_OP_PARALLEL, + * - LED_OP_SERIAL, + */ +rtk_api_ret_t rtk_led_operation_set(rtk_led_operation_t mode) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ( mode >= LED_OP_END) + return RT_ERR_INPUT; + + switch (mode) + { + case LED_OP_PARALLEL: + regData = LEDOP_PARALLEL; + break; + case LED_OP_SERIAL: + regData = LEDOP_SERIAL; + break; + default: + return RT_ERR_CHIP_NOT_SUPPORTED; + break; + } + + if ((retVal = rtl8367c_setAsicLedOperationMode(regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_operation_get + * Description: + * Get Led operation mode + * Input: + * None + * Output: + * pMode - Support LED operation mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get Led operation mode. + * The modes that can be set are as following: + * - LED_OP_SCAN, + * - LED_OP_PARALLEL, + * - LED_OP_SERIAL, + */ +rtk_api_ret_t rtk_led_operation_get(rtk_led_operation_t *pMode) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMode) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedOperationMode(®Data)) != RT_ERR_OK) + return retVal; + + if (regData == LEDOP_SERIAL) + *pMode = LED_OP_SERIAL; + else if (regData ==LEDOP_PARALLEL) + *pMode = LED_OP_PARALLEL; + else + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_modeForce_set + * Description: + * Set Led group to configuration force mode + * Input: + * port - port ID + * group - Support LED group id. + * mode - Support LED force mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Error Port ID + * Note: + * The API can force to one force mode. + * The force modes that can be set are as following: + * - LED_FORCE_NORMAL, + * - LED_FORCE_BLINK, + * - LED_FORCE_OFF, + * - LED_FORCE_ON. + */ +rtk_api_ret_t rtk_led_modeForce_set(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t mode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /* No LED for CPU port */ + if(rtk_switch_isCPUPort(port) == RT_ERR_OK) + return RT_ERR_PORT_ID; + + if (group >= LED_GROUP_END) + return RT_ERR_INPUT; + + if (mode >= LED_FORCE_END) + return RT_ERR_NOT_ALLOWED; + + if ((retVal = rtl8367c_setAsicForceLed(rtk_switch_port_L2P_get(port), group, mode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_modeForce_get + * Description: + * Get Led group to configuration force mode + * Input: + * port - port ID + * group - Support LED group id. + * pMode - Support LED force mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Error Port ID + * Note: + * The API can get forced Led group mode. + * The force modes that can be set are as following: + * - LED_FORCE_NORMAL, + * - LED_FORCE_BLINK, + * - LED_FORCE_OFF, + * - LED_FORCE_ON. + */ +rtk_api_ret_t rtk_led_modeForce_get(rtk_port_t port, rtk_led_group_t group, rtk_led_force_mode_t *pMode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /* No LED for CPU port */ + if(rtk_switch_isCPUPort(port) == RT_ERR_OK) + return RT_ERR_PORT_ID; + + if (group >= LED_GROUP_END) + return RT_ERR_INPUT; + + if (NULL == pMode) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicForceLed(rtk_switch_port_L2P_get(port), group, pMode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_blinkRate_set + * Description: + * Set LED blinking rate + * Input: + * blinkRate - blinking rate. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * ASIC support 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. + */ +rtk_api_ret_t rtk_led_blinkRate_set(rtk_led_blink_rate_t blinkRate) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (blinkRate >= LED_BLINKRATE_END) + return RT_ERR_FAILED; + + if ((retVal = rtl8367c_setAsicLedBlinkRate(blinkRate)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_blinkRate_get + * Description: + * Get LED blinking rate at mode 0 to mode 3 + * Input: + * None + * Output: + * pBlinkRate - blinking rate. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 6 types of LED blinking rates at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms. + */ +rtk_api_ret_t rtk_led_blinkRate_get(rtk_led_blink_rate_t *pBlinkRate) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pBlinkRate) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedBlinkRate(pBlinkRate)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_groupConfig_set + * Description: + * Set per group Led to configuration mode + * Input: + * group - LED group. + * config - LED configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. + * - Definition LED Statuses Description + * - 0000 LED_Off LED pin Tri-State. + * - 0001 Dup/Col Collision, Full duplex Indicator. + * - 0010 Link/Act Link, Activity Indicator. + * - 0011 Spd1000 1000Mb/s Speed Indicator. + * - 0100 Spd100 100Mb/s Speed Indicator. + * - 0101 Spd10 10Mb/s Speed Indicator. + * - 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. + * - 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. + * - 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. + * - 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. + * - 1010 LoopDetect LoopDetect Indicator. + * - 1011 EEE EEE Indicator. + * - 1100 Link/Rx Link, Activity Indicator. + * - 1101 Link/Tx Link, Activity Indicator. + * - 1110 Master Link on Master Indicator. + * - 1111 Act Activity Indicator. Low for link established. + */ +rtk_api_ret_t rtk_led_groupConfig_set(rtk_led_group_t group, rtk_led_congig_t config) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (LED_GROUP_END <= group) + return RT_ERR_FAILED; + + if (LED_CONFIG_END <= config) + return RT_ERR_FAILED; + + if ((retVal = rtl8367c_setAsicLedIndicateInfoConfig(group, config)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_groupConfig_get + * Description: + * Get Led group configuration mode + * Input: + * group - LED group. + * Output: + * pConfig - LED configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LED indicated information configuration for each LED group. + */ +rtk_api_ret_t rtk_led_groupConfig_get(rtk_led_group_t group, rtk_led_congig_t *pConfig) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (LED_GROUP_END <= group) + return RT_ERR_FAILED; + + if(NULL == pConfig) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedIndicateInfoConfig(group, pConfig)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_groupAbility_set + * Description: + * Configure per group Led ability + * Input: + * group - LED group. + * pAbility - LED ability + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * None. + */ + +rtk_api_ret_t rtk_led_groupAbility_set(rtk_led_group_t group, rtk_led_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (LED_GROUP_END <= group) + return RT_ERR_FAILED; + + if(pAbility == NULL) + return RT_ERR_NULL_POINTER; + + if( (pAbility->link_10m >= RTK_ENABLE_END) || (pAbility->link_100m >= RTK_ENABLE_END)|| + (pAbility->link_500m >= RTK_ENABLE_END) || (pAbility->link_1000m >= RTK_ENABLE_END)|| + (pAbility->act_rx >= RTK_ENABLE_END) || (pAbility->act_tx >= RTK_ENABLE_END) ) + { + return RT_ERR_INPUT; + } + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, ®Data)) != RT_ERR_OK) + return retVal; + + if(pAbility->link_10m == ENABLED) + regData |= 0x0001; + else + regData &= ~0x0001; + + if(pAbility->link_100m == ENABLED) + regData |= 0x0002; + else + regData &= ~0x0002; + + if(pAbility->link_500m == ENABLED) + regData |= 0x0004; + else + regData &= ~0x0004; + + if(pAbility->link_1000m == ENABLED) + regData |= 0x0008; + else + regData &= ~0x0008; + + if(pAbility->act_rx == ENABLED) + regData |= 0x0010; + else + regData &= ~0x0010; + + if(pAbility->act_tx == ENABLED) + regData |= 0x0020; + else + regData &= ~0x0020; + + regData |= (0x0001 << 6); + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_groupAbility_get + * Description: + * Get per group Led ability + * Input: + * group - LED group. + * pAbility - LED ability + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * None. + */ + +rtk_api_ret_t rtk_led_groupAbility_get(rtk_led_group_t group, rtk_led_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (LED_GROUP_END <= group) + return RT_ERR_FAILED; + + if(pAbility == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_LED0_DATA_CTRL + (rtk_uint32)group, ®Data)) != RT_ERR_OK) + return retVal; + + pAbility->link_10m = (regData & 0x0001) ? ENABLED : DISABLED; + pAbility->link_100m = (regData & 0x0002) ? ENABLED : DISABLED; + pAbility->link_500m = (regData & 0x0004) ? ENABLED : DISABLED; + pAbility->link_1000m = (regData & 0x0008) ? ENABLED : DISABLED; + pAbility->act_rx = (regData & 0x0010) ? ENABLED : DISABLED; + pAbility->act_tx = (regData & 0x0020) ? ENABLED : DISABLED; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_led_serialMode_set + * Description: + * Set Led serial mode active configuration + * Input: + * active - LED group. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set LED serial mode active configuration. + */ +rtk_api_ret_t rtk_led_serialMode_set(rtk_led_active_t active) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ( active >= LED_ACTIVE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicLedSerialModeConfig(active,1))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_serialMode_get + * Description: + * Get Led group congiuration mode + * Input: + * group - LED group. + * Output: + * pConfig - LED configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get LED serial mode active configuration. + */ +rtk_api_ret_t rtk_led_serialMode_get(rtk_led_active_t *pActive) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pActive) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedSerialModeConfig(pActive,®Data))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_OutputEnable_set + * Description: + * This API set LED I/O state. + * Input: + * enabled - LED I/O state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set LED I/O state. + */ +rtk_api_ret_t rtk_led_OutputEnable_set(rtk_enable_t state) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (state >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicLedOutputEnable(state))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_OutputEnable_get + * Description: + * This API get LED I/O state. + * Input: + * None. + * Output: + * pEnabled - LED I/O state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current LED I/O state. + */ +rtk_api_ret_t rtk_led_OutputEnable_get(rtk_enable_t *pState) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pState == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedOutputEnable(pState))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_led_serialModePortmask_set + * Description: + * This API configure Serial LED output Group and portmask + * Input: + * output - output group + * pPortmask - output portmask + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * None. + */ +rtk_api_ret_t rtk_led_serialModePortmask_set(rtk_led_serialOutput_t output, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(output >= SERIAL_LED_END) + return RT_ERR_INPUT; + + if(pPortmask == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicLedSerialOutput((rtk_uint32)output, pmask))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_led_serialModePortmask_get + * Description: + * This API get Serial LED output Group and portmask + * Input: + * None. + * Output: + * pOutput - output group + * pPortmask - output portmask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * None. + */ +rtk_api_ret_t rtk_led_serialModePortmask_get(rtk_led_serialOutput_t *pOutput, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pOutput == NULL) + return RT_ERR_NULL_POINTER; + + if(pPortmask == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicLedSerialOutput((rtk_uint32 *)pOutput, &pmask))!=RT_ERR_OK) + return retVal; + + if((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/mirror.c b/drivers/net/phy/rtk/rtl8367c/mirror.c new file mode 100644 index 000000000000..3bbad8adb65d --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/mirror.c @@ -0,0 +1,548 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Mirror module. + * + */ + +#include +#include +#include +#include +#include +#include + +/* Function Name: + * rtk_mirror_portBased_set + * Description: + * Set port mirror function. + * Input: + * mirroring_port - Monitor port. + * pMirrored_rx_portmask - Rx mirror port mask. + * pMirrored_tx_portmask - Tx mirror port mask. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API is to set mirror function of source port and mirror port. + * The mirror port can only be set to one port and the TX and RX mirror ports + * should be identical. + */ +rtk_api_ret_t rtk_mirror_portBased_set(rtk_port_t mirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask) +{ + rtk_api_ret_t retVal; + rtk_enable_t mirRx, mirTx; + rtk_uint32 i, pmask; + rtk_port_t source_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(mirroring_port); + + if(NULL == pMirrored_rx_portmask) + return RT_ERR_NULL_POINTER; + + if(NULL == pMirrored_tx_portmask) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pMirrored_rx_portmask); + + RTK_CHK_PORTMASK_VALID(pMirrored_tx_portmask); + + /*Mirror Source Port Mask Check*/ + if (pMirrored_tx_portmask->bits[0]!=pMirrored_rx_portmask->bits[0]&&pMirrored_tx_portmask->bits[0]!=0&&pMirrored_rx_portmask->bits[0]!=0) + return RT_ERR_PORT_MASK; + + /*mirror port != source port*/ + if(RTK_PORTMASK_IS_PORT_SET((*pMirrored_tx_portmask), mirroring_port) || RTK_PORTMASK_IS_PORT_SET((*pMirrored_rx_portmask), mirroring_port)) + return RT_ERR_PORT_MASK; + + source_port = rtk_switch_maxLogicalPort_get(); + + RTK_SCAN_ALL_LOG_PORT(i) + { + if (pMirrored_tx_portmask->bits[0]&(1<bits[0]&(1<bits[0] != 0) + { + if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_rx_portmask, &pmask)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtk_switch_portmask_L2P_get(pMirrored_tx_portmask, &pmask)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPortMirrorMask(pmask)) != RT_ERR_OK) + return retVal; + } + + + if (pMirrored_rx_portmask->bits[0]) + mirRx = ENABLED; + else + mirRx = DISABLED; + + if ((retVal = rtl8367c_setAsicPortMirrorRxFunction(mirRx)) != RT_ERR_OK) + return retVal; + + if (pMirrored_tx_portmask->bits[0]) + mirTx = ENABLED; + else + mirTx = DISABLED; + + if ((retVal = rtl8367c_setAsicPortMirrorTxFunction(mirTx)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_mirror_portBased_get + * Description: + * Get port mirror function. + * Input: + * None + * Output: + * pMirroring_port - Monitor port. + * pMirrored_rx_portmask - Rx mirror port mask. + * pMirrored_tx_portmask - Tx mirror port mask. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror function of source port and mirror port. + */ +rtk_api_ret_t rtk_mirror_portBased_get(rtk_port_t *pMirroring_port, rtk_portmask_t *pMirrored_rx_portmask, rtk_portmask_t *pMirrored_tx_portmask) +{ + rtk_api_ret_t retVal; + rtk_port_t source_port; + rtk_enable_t mirRx, mirTx; + rtk_uint32 sport, mport, pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMirrored_rx_portmask) + return RT_ERR_NULL_POINTER; + + if(NULL == pMirrored_tx_portmask) + return RT_ERR_NULL_POINTER; + + if(NULL == pMirroring_port) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortMirror(&sport, &mport)) != RT_ERR_OK) + return retVal; + source_port = rtk_switch_port_P2L_get(sport); + *pMirroring_port = rtk_switch_port_P2L_get(mport); + + if ((retVal = rtl8367c_getAsicPortMirrorRxFunction((rtk_uint32*)&mirRx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortMirrorTxFunction((rtk_uint32*)&mirTx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortMirrorMask(&pmask)) != RT_ERR_OK) + return retVal; + + if (DISABLED == mirRx) + pMirrored_rx_portmask->bits[0]=0; + else + { + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_rx_portmask)) != RT_ERR_OK) + return retVal; + pMirrored_rx_portmask->bits[0] |= 1<bits[0]=0; + else + { + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pMirrored_tx_portmask)) != RT_ERR_OK) + return retVal; + pMirrored_tx_portmask->bits[0] |= 1<= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortMirrorIsolation(enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_portIso_get + * Description: + * Get mirror port isolation. + * Input: + * None + * Output: + * pEnable |Mirror isolation status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror isolation status. + */ +rtk_api_ret_t rtk_mirror_portIso_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortMirrorIsolation(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_vlanLeaky_set + * Description: + * Set mirror VLAN leaky. + * Input: + * txenable -TX leaky enable. + * rxenable - RX leaky enable. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set mirror VLAN leaky function forwarding packets to miror port. + */ +rtk_api_ret_t rtk_mirror_vlanLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END)) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortMirrorVlanTxLeaky(txenable)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortMirrorVlanRxLeaky(rxenable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_vlanLeaky_get + * Description: + * Get mirror VLAN leaky. + * Input: + * None + * Output: + * pTxenable - TX leaky enable. + * pRxenable - RX leaky enable. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror VLAN leaky status. + */ +rtk_api_ret_t rtk_mirror_vlanLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if( (NULL == pTxenable) || (NULL == pRxenable) ) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortMirrorVlanTxLeaky(pTxenable)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortMirrorVlanRxLeaky(pRxenable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_isolationLeaky_set + * Description: + * Set mirror Isolation leaky. + * Input: + * txenable -TX leaky enable. + * rxenable - RX leaky enable. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set mirror VLAN leaky function forwarding packets to mirror port. + */ +rtk_api_ret_t rtk_mirror_isolationLeaky_set(rtk_enable_t txenable, rtk_enable_t rxenable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((txenable >= RTK_ENABLE_END) ||(rxenable >= RTK_ENABLE_END)) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(txenable)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortMirrorIsolationRxLeaky(rxenable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_isolationLeaky_get + * Description: + * Get mirror isolation leaky. + * Input: + * None + * Output: + * pTxenable - TX leaky enable. + * pRxenable - RX leaky enable. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror isolation leaky status. + */ +rtk_api_ret_t rtk_mirror_isolationLeaky_get(rtk_enable_t *pTxenable, rtk_enable_t *pRxenable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if( (NULL == pTxenable) || (NULL == pRxenable) ) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortMirrorIsolationTxLeaky(pTxenable)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortMirrorIsolationRxLeaky(pRxenable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_keep_set + * Description: + * Set mirror packet format keep. + * Input: + * mode - -mirror keep mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The API is to set -mirror keep mode. + * The mirror keep mode is as following: + * - MIRROR_FOLLOW_VLAN + * - MIRROR_KEEP_ORIGINAL + * - MIRROR_KEEP_END + */ +rtk_api_ret_t rtk_mirror_keep_set(rtk_mirror_keep_t mode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (mode >= MIRROR_KEEP_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortMirrorRealKeep(mode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_keep_get + * Description: + * Get mirror packet format keep. + * Input: + * None + * Output: + * pMode -mirror keep mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API is to get mirror keep mode. + * The mirror keep mode is as following: + * - MIRROR_FOLLOW_VLAN + * - MIRROR_KEEP_ORIGINAL + * - MIRROR_KEEP_END + */ +rtk_api_ret_t rtk_mirror_keep_get(rtk_mirror_keep_t *pMode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMode) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortMirrorRealKeep(pMode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_override_set + * Description: + * Set port mirror override function. + * Input: + * rxMirror - 1: output mirrored packet, 0: output normal forward packet + * txMirror - 1: output mirrored packet, 0: output normal forward packet + * aclMirror - 1: output mirrored packet, 0: output normal forward packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API is to set mirror override function. + * This function control the output format when a port output + * normal forward & mirrored packet at the same time. + */ +rtk_api_ret_t rtk_mirror_override_set(rtk_enable_t rxMirror, rtk_enable_t txMirror, rtk_enable_t aclMirror) +{ + rtk_api_ret_t retVal; + + if( (rxMirror >= RTK_ENABLE_END) || (txMirror >= RTK_ENABLE_END) || (aclMirror >= RTK_ENABLE_END)) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortMirrorOverride((rtk_uint32)rxMirror, (rtk_uint32)txMirror, (rtk_uint32)aclMirror)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_mirror_override_get + * Description: + * Get port mirror override function. + * Input: + * None + * Output: + * pRxMirror - 1: output mirrored packet, 0: output normal forward packet + * pTxMirror - 1: output mirrored packet, 0: output normal forward packet + * pAclMirror - 1: output mirrored packet, 0: output normal forward packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null Pointer + * Note: + * The API is to Get mirror override function. + * This function control the output format when a port output + * normal forward & mirrored packet at the same time. + */ +rtk_api_ret_t rtk_mirror_override_get(rtk_enable_t *pRxMirror, rtk_enable_t *pTxMirror, rtk_enable_t *pAclMirror) +{ + rtk_api_ret_t retVal; + + if( (pRxMirror == NULL) || (pTxMirror == NULL) || (pAclMirror == NULL)) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_getAsicPortMirrorOverride((rtk_uint32 *)pRxMirror, (rtk_uint32 *)pTxMirror, (rtk_uint32 *)pAclMirror)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/oam.c b/drivers/net/phy/rtk/rtl8367c/oam.c new file mode 100644 index 000000000000..dc1559ae3ef8 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/oam.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in OAM(802.3ah) module. + * + */ + +#include +#include +#include +#include + +#include +#include + + +/* Module Name : OAM */ + +/* Function Name: + * rtk_oam_init + * Description: + * Initialize oam module. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * Must initialize oam module before calling any oam APIs. + */ +rtk_api_ret_t rtk_oam_init(void) +{ + return RT_ERR_OK; +} /* end of rtk_oam_init */ + + +/* Function Name: + * rtk_oam_state_set + * Description: + * This API set OAM state. + * Input: + * enabled -OAMstate + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set OAM state. + */ +rtk_api_ret_t rtk_oam_state_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enabled >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicOamEnable(enabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_oam_state_get + * Description: + * This API get OAM state. + * Input: + * None. + * Output: + * pEnabled - H/W IGMP state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error parameter + * Note: + * This API set current OAM state. + */ +rtk_api_ret_t rtk_oam_state_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicOamEnable(pEnabled))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + + +/* Function Name: + * rtk_oam_parserAction_set + * Description: + * Set OAM parser action + * Input: + * port - port id + * action - parser action + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +rtk_api_ret_t rtk_oam_parserAction_set(rtk_port_t port, rtk_oam_parser_act_t action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (action >= OAM_PARSER_ACTION_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicOamParser(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_oam_parserAction_set + * Description: + * Get OAM parser action + * Input: + * port - port id + * Output: + * pAction - parser action + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +rtk_api_ret_t rtk_oam_parserAction_get(rtk_port_t port, rtk_oam_parser_act_t *pAction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicOamParser(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_oam_multiplexerAction_set + * Description: + * Set OAM multiplexer action + * Input: + * port - port id + * action - parser action + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +rtk_api_ret_t rtk_oam_multiplexerAction_set(rtk_port_t port, rtk_oam_multiplexer_act_t action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (action >= OAM_MULTIPLEXER_ACTION_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicOamMultiplexer(rtk_switch_port_L2P_get(port), action))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_oam_parserAction_set + * Description: + * Get OAM multiplexer action + * Input: + * port - port id + * Output: + * pAction - parser action + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * Note: + * None + */ +rtk_api_ret_t rtk_oam_multiplexerAction_get(rtk_port_t port, rtk_oam_multiplexer_act_t *pAction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicOamMultiplexer(rtk_switch_port_L2P_get(port), pAction))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/port.c b/drivers/net/phy/rtk/rtl8367c/port.c new file mode 100644 index 000000000000..9c7bcd0e38a1 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/port.c @@ -0,0 +1,2467 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Port module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define FIBER_INIT_SIZE 1507 +CONST_T rtk_uint8 Fiber[FIBER_INIT_SIZE] = { +0x02,0x04,0x41,0xE4,0xF5,0xA8,0xD2,0xAF, +0x22,0x00,0x00,0x02,0x05,0x2D,0xE4,0x90, +0x06,0x2A,0xF0,0xFD,0x7C,0x01,0x7F,0x3F, +0x7E,0x1D,0x12,0x05,0xAF,0x7D,0x40,0x12, +0x02,0x5F,0xE4,0xFF,0xFE,0xFD,0x80,0x08, +0x12,0x05,0x9E,0x50,0x0C,0x12,0x05,0x8B, +0xFC,0x90,0x06,0x24,0x12,0x03,0x76,0x80, +0xEF,0xE4,0xF5,0xA8,0xD2,0xAF,0x7D,0x1F, +0xFC,0x7F,0x49,0x7E,0x13,0x12,0x05,0xAF, +0x12,0x05,0xD6,0x7D,0xD7,0x12,0x02,0x1E, +0x7D,0x80,0x12,0x01,0xCA,0x7D,0x94,0x7C, +0xF9,0x12,0x02,0x3B,0x7D,0x81,0x12,0x01, +0xCA,0x7D,0xA2,0x7C,0x31,0x12,0x02,0x3B, +0x7D,0x82,0x12,0x01,0xDF,0x7D,0x60,0x7C, +0x69,0x12,0x02,0x43,0x7D,0x83,0x12,0x01, +0xDF,0x7D,0x28,0x7C,0x97,0x12,0x02,0x43, +0x7D,0x84,0x12,0x01,0xF4,0x7D,0x85,0x7C, +0x9D,0x12,0x02,0x57,0x7D,0x23,0x12,0x01, +0xF4,0x7D,0x10,0x7C,0xD8,0x12,0x02,0x57, +0x7D,0x24,0x7C,0x04,0x12,0x02,0x28,0x7D, +0x00,0x12,0x02,0x1E,0x7D,0x2F,0x12,0x02, +0x09,0x7D,0x20,0x7C,0x0F,0x7F,0x02,0x7E, +0x66,0x12,0x05,0xAF,0x7D,0x01,0x12,0x02, +0x09,0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x7F, +0x02,0x7E,0x66,0x12,0x02,0x4B,0x44,0x02, +0xFF,0x90,0x06,0x28,0xEE,0xF0,0xA3,0xEF, +0xF0,0x44,0x04,0xFF,0x90,0x06,0x28,0xEE, +0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F,0x02, +0x7E,0x66,0x12,0x05,0xAF,0x7D,0x04,0x7C, +0x00,0x12,0x02,0x28,0x7D,0xB9,0x7C,0x15, +0x7F,0xEB,0x7E,0x13,0x12,0x05,0xAF,0x7D, +0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12, +0x05,0xAF,0x7D,0x40,0x7C,0x11,0x7F,0x00, +0x7E,0x62,0x12,0x05,0xAF,0x12,0x03,0x82, +0x7D,0x41,0x12,0x02,0x5F,0xE4,0xFF,0xFE, +0xFD,0x80,0x08,0x12,0x05,0x9E,0x50,0x0C, +0x12,0x05,0x8B,0xFC,0x90,0x06,0x24,0x12, +0x03,0x76,0x80,0xEF,0xC2,0x00,0xC2,0x01, +0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62, +0x12,0x02,0x4B,0x30,0xE2,0x05,0xE4,0xA3, +0xF0,0x80,0xF1,0x90,0x06,0x2A,0xE0,0x70, +0x12,0x12,0x01,0x89,0x90,0x06,0x2A,0x74, +0x01,0xF0,0xE4,0x90,0x06,0x2D,0xF0,0xA3, +0xF0,0x80,0xD9,0xC3,0x90,0x06,0x2E,0xE0, +0x94,0x64,0x90,0x06,0x2D,0xE0,0x94,0x00, +0x40,0xCA,0xE4,0xF0,0xA3,0xF0,0x12,0x01, +0x89,0x90,0x06,0x2A,0x74,0x01,0xF0,0x80, +0xBB,0x7D,0x04,0xFC,0x7F,0x02,0x7E,0x66, +0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F, +0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05, +0xAF,0xE4,0xFD,0xFC,0x7F,0x02,0x7E,0x66, +0x12,0x05,0xAF,0x7D,0x00,0x7C,0x04,0x7F, +0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x05, +0xAF,0x22,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C, +0x04,0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF, +0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, +0x12,0x05,0xAF,0x22,0x7C,0x04,0x7F,0x01, +0x7E,0x66,0x12,0x05,0xAF,0x7D,0xC0,0x7C, +0x00,0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF, +0x22,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C,0x04, +0x7F,0x02,0x7E,0x66,0x12,0x05,0xAF,0x22, +0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D, +0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12, +0x05,0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12, +0x05,0xAF,0x22,0x12,0x05,0x67,0x90,0x06, +0x28,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7F, +0x02,0x7E,0x66,0x12,0x05,0xAF,0x22,0x7C, +0x00,0x7F,0x36,0x7E,0x13,0x12,0x05,0xAF, +0x22,0xC5,0xF0,0xF8,0xA3,0xE0,0x28,0xF0, +0xC5,0xF0,0xF8,0xE5,0x82,0x15,0x82,0x70, +0x02,0x15,0x83,0xE0,0x38,0xF0,0x22,0x75, +0xF0,0x08,0x75,0x82,0x00,0xEF,0x2F,0xFF, +0xEE,0x33,0xFE,0xCD,0x33,0xCD,0xCC,0x33, +0xCC,0xC5,0x82,0x33,0xC5,0x82,0x9B,0xED, +0x9A,0xEC,0x99,0xE5,0x82,0x98,0x40,0x0C, +0xF5,0x82,0xEE,0x9B,0xFE,0xED,0x9A,0xFD, +0xEC,0x99,0xFC,0x0F,0xD5,0xF0,0xD6,0xE4, +0xCE,0xFB,0xE4,0xCD,0xFA,0xE4,0xCC,0xF9, +0xA8,0x82,0x22,0xB8,0x00,0xC1,0xB9,0x00, +0x59,0xBA,0x00,0x2D,0xEC,0x8B,0xF0,0x84, +0xCF,0xCE,0xCD,0xFC,0xE5,0xF0,0xCB,0xF9, +0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xED,0x33,0xFD,0xEC,0x33,0xFC,0xEB,0x33, +0xFB,0x10,0xD7,0x03,0x99,0x40,0x04,0xEB, +0x99,0xFB,0x0F,0xD8,0xE5,0xE4,0xF9,0xFA, +0x22,0x78,0x18,0xEF,0x2F,0xFF,0xEE,0x33, +0xFE,0xED,0x33,0xFD,0xEC,0x33,0xFC,0xC9, +0x33,0xC9,0x10,0xD7,0x05,0x9B,0xE9,0x9A, +0x40,0x07,0xEC,0x9B,0xFC,0xE9,0x9A,0xF9, +0x0F,0xD8,0xE0,0xE4,0xC9,0xFA,0xE4,0xCC, +0xFB,0x22,0x75,0xF0,0x10,0xEF,0x2F,0xFF, +0xEE,0x33,0xFE,0xED,0x33,0xFD,0xCC,0x33, +0xCC,0xC8,0x33,0xC8,0x10,0xD7,0x07,0x9B, +0xEC,0x9A,0xE8,0x99,0x40,0x0A,0xED,0x9B, +0xFD,0xEC,0x9A,0xFC,0xE8,0x99,0xF8,0x0F, +0xD5,0xF0,0xDA,0xE4,0xCD,0xFB,0xE4,0xCC, +0xFA,0xE4,0xC8,0xF9,0x22,0xEB,0x9F,0xF5, +0xF0,0xEA,0x9E,0x42,0xF0,0xE9,0x9D,0x42, +0xF0,0xE8,0x9C,0x45,0xF0,0x22,0xE0,0xFC, +0xA3,0xE0,0xFD,0xA3,0xE0,0xFE,0xA3,0xE0, +0xFF,0x22,0xE0,0xF8,0xA3,0xE0,0xF9,0xA3, +0xE0,0xFA,0xA3,0xE0,0xFB,0x22,0xEC,0xF0, +0xA3,0xED,0xF0,0xA3,0xEE,0xF0,0xA3,0xEF, +0xF0,0x22,0x12,0x03,0xF8,0x12,0x04,0x1A, +0x44,0x40,0x12,0x04,0x0F,0x7D,0x03,0x7C, +0x00,0x12,0x04,0x23,0x12,0x05,0xAF,0x12, +0x03,0xF8,0x12,0x04,0x1A,0x54,0xBF,0x12, +0x04,0x0F,0x7D,0x03,0x7C,0x00,0x12,0x03, +0xD0,0x7F,0x02,0x7E,0x66,0x12,0x05,0x67, +0xEF,0x54,0xFD,0x54,0xFE,0x12,0x04,0x33, +0x12,0x03,0xD0,0x7F,0x02,0x7E,0x66,0x12, +0x05,0x67,0xEF,0x44,0x02,0x44,0x01,0x12, +0x04,0x33,0x12,0x04,0x23,0x02,0x05,0xAF, +0x7F,0x01,0x7E,0x66,0x12,0x05,0xAF,0x7D, +0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x05,0xAF,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x05,0xAF,0x22, +0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66, +0x12,0x05,0xAF,0x7D,0x80,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x05,0xAF,0x22,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x05, +0xAF,0x22,0x7F,0x02,0x7E,0x66,0x12,0x05, +0x67,0xEF,0x22,0x7F,0x01,0x7E,0x66,0x12, +0x05,0xAF,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x22,0xFD,0xAC,0x06,0x7F,0x02, +0x7E,0x66,0x12,0x05,0xAF,0xE4,0xFD,0xFC, +0x22,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, +0x81,0x3C,0x02,0x04,0x88,0x02,0x00,0x0E, +0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, +0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, +0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, +0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, +0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, +0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, +0x90,0x05,0xCB,0xE4,0x7E,0x01,0x93,0x60, +0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, +0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, +0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, +0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, +0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, +0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, +0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, +0xE9,0xDE,0xE7,0x80,0xBE,0x75,0x0F,0x80, +0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, +0x83,0xE4,0xF5,0x10,0x75,0x0B,0xA0,0x75, +0x0A,0xAC,0x75,0x09,0xB9,0x75,0x08,0x03, +0x75,0x89,0x11,0x7B,0x60,0x7A,0x09,0xF9, +0xF8,0xAF,0x0B,0xAE,0x0A,0xAD,0x09,0xAC, +0x08,0x12,0x02,0xBB,0xAD,0x07,0xAC,0x06, +0xC3,0xE4,0x9D,0xFD,0xE4,0x9C,0xFC,0x78, +0x17,0xF6,0xAF,0x05,0xEF,0x08,0xF6,0x18, +0xE6,0xF5,0x8C,0x08,0xE6,0xF5,0x8A,0x74, +0x0D,0x2D,0xFD,0xE4,0x3C,0x18,0xF6,0xAF, +0x05,0xEF,0x08,0xF6,0x75,0x88,0x10,0x53, +0x8E,0xC7,0xD2,0xA9,0x22,0xC0,0xE0,0xC0, +0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75, +0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5, +0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06, +0x2B,0xE4,0x75,0xF0,0x01,0x12,0x02,0x69, +0x90,0x06,0x2D,0xE4,0x75,0xF0,0x01,0x12, +0x02,0x69,0xD0,0x00,0xD0,0xD0,0xD0,0x82, +0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2, +0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D, +0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE, +0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7, +0xD2,0xAF,0x22,0x90,0x06,0x24,0x12,0x03, +0x5E,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE, +0xE4,0x3D,0xFD,0xE4,0x3C,0x22,0xE4,0x7F, +0x20,0x7E,0x4E,0xFD,0xFC,0x90,0x06,0x24, +0x12,0x03,0x6A,0xC3,0x02,0x03,0x4D,0xC2, +0xAF,0xAB,0x07,0xAA,0x06,0x8A,0xA2,0x8B, +0xA3,0x8C,0xA4,0x8D,0xA5,0x75,0xA0,0x03, +0x00,0x00,0x00,0xAA,0xA1,0xBA,0x00,0xF8, +0xD2,0xAF,0x22,0x42,0x06,0x2D,0x00,0x00, +0x42,0x06,0x2B,0x00,0x00,0x00,0x12,0x05, +0xDF,0x12,0x04,0xCD,0x02,0x00,0x03,0xE4, +0xF5,0x8E,0x22}; + +static rtk_api_ret_t _rtk_port_FiberModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check Combo port or not */ + RTK_CHK_PORT_IS_COMBO(port); + + /* Flow Control */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG04, ®Data)) != RT_ERR_OK) + return retVal; + + if (pAbility->AsyFC == 1) + regData |= (0x0001 << 8); + else + regData &= ~(0x0001 << 8); + + if (pAbility->FC == 1) + regData |= (0x0001 << 7); + else + regData &= ~(0x0001 << 7); + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG04, regData)) != RT_ERR_OK) + return retVal; + + /* Speed ability */ + if( (pAbility->Full_1000 == 1) && (pAbility->Full_100 == 1) && (pAbility->AutoNegotiation == 1) ) + { + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 7)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK) + return retVal; + } + else if(pAbility->Full_1000 == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 4)) != RT_ERR_OK) + return retVal; + + if(pAbility->AutoNegotiation == 1) + { + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x1140)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x0140)) != RT_ERR_OK) + return retVal; + } + } + else if(pAbility->Full_100 == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, 5)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_FIB0_CFG00, 0x2100)) != RT_ERR_OK) + return retVal; + } + + /* Digital software reset */ + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, ®Data)) != RT_ERR_OK) + return retVal; + + regData |= (0x0001 << 6); + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + regData &= ~(0x0001 << 6); + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, regData)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + /* CDR reset */ + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1401))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x1403))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0000))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +static rtk_api_ret_t _rtk_port_FiberModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 data, regData; + + /* Check Combo port or not */ + RTK_CHK_PORT_IS_COMBO(port); + + memset(pAbility, 0x00, sizeof(rtk_port_phy_ability_t)); + + /* Flow Control */ + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_REG4_FIB100_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0044)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, ®Data)) != RT_ERR_OK) + return retVal; + + if(regData & (0x0001 << 8)) + pAbility->AsyFC = 1; + + if(regData & (0x0001 << 7)) + pAbility->FC = 1; + + /* Speed ability */ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_FRC_MODE_OFFSET, &data)) != RT_ERR_OK) + return retVal; + + if(data == 0) + { + pAbility->AutoNegotiation = 1; + pAbility->Full_1000 = 1; + pAbility->Full_100 = 1; + } + else + { + if ((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FIBER_CFG_1, RTL8367C_SDS_MODE_MASK, &data)) != RT_ERR_OK) + return retVal; + + if(data == 4) + { + pAbility->Full_1000 = 1; + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_FIB0_CFG00, &data)) != RT_ERR_OK) + return retVal; + + if(data & 0x1000) + pAbility->AutoNegotiation = 1; + else + pAbility->AutoNegotiation = 0; + } + else if(data == 5) + pAbility->Full_100 = 1; + else + return RT_ERR_FAILED; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyAutoNegoAbility_set + * Description: + * Set Ethernet PHY auto-negotiation desired ability. + * Input: + * port - port id. + * pAbility - Ability structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * If Full_1000 bit is set to 1, the AutoNegotiation will be automatic set to 1. While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will + * be set as following 100F > 100H > 10F > 10H priority sequence. + */ +rtk_api_ret_t rtk_port_phyAutoNegoAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData; + rtk_uint32 phyEnMsk0; + rtk_uint32 phyEnMsk4; + rtk_uint32 phyEnMsk9; + rtk_port_media_t media_type; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pAbility) + return RT_ERR_NULL_POINTER; + + if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END || + pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END || + pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END || + pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (rtk_switch_isComboPort(port) == RT_ERR_OK) + { + if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) + return retVal; + + if(media_type == PORT_MEDIA_FIBER) + { + return _rtk_port_FiberModeAbility_set(port, pAbility); + } + } + + /*for PHY auto mode setup*/ + pAbility->AutoNegotiation = 1; + + phyEnMsk0 = 0; + phyEnMsk4 = 0; + phyEnMsk9 = 0; + + if (1 == pAbility->Half_10) + { + /*10BASE-TX half duplex capable in reg 4.5*/ + phyEnMsk4 = phyEnMsk4 | (1 << 5); + + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); + } + + if (1 == pAbility->Full_10) + { + /*10BASE-TX full duplex capable in reg 4.6*/ + phyEnMsk4 = phyEnMsk4 | (1 << 6); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); + + /*Full duplex mode in reg 0.8*/ + phyEnMsk0 = phyEnMsk0 | (1 << 8); + + } + + if (1 == pAbility->Half_100) + { + /*100BASE-TX half duplex capable in reg 4.7*/ + phyEnMsk4 = phyEnMsk4 | (1 << 7); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 | (1 << 13); + } + + + if (1 == pAbility->Full_100) + { + /*100BASE-TX full duplex capable in reg 4.8*/ + phyEnMsk4 = phyEnMsk4 | (1 << 8); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 | (1 << 13); + /*Full duplex mode in reg 0.8*/ + phyEnMsk0 = phyEnMsk0 | (1 << 8); + } + + + if (1 == pAbility->Full_1000) + { + /*1000 BASE-T FULL duplex capable setting in reg 9.9*/ + phyEnMsk9 = phyEnMsk9 | (1 << 9); + + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 | (1 << 6); + phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); + + + /*Auto-Negotiation setting in reg 0.12*/ + phyEnMsk0 = phyEnMsk0 | (1 << 12); + + } + + if (1 == pAbility->AutoNegotiation) + { + /*Auto-Negotiation setting in reg 0.12*/ + phyEnMsk0 = phyEnMsk0 | (1 << 12); + } + + if (1 == pAbility->AsyFC) + { + /*Asymetric flow control in reg 4.11*/ + phyEnMsk4 = phyEnMsk4 | (1 << 11); + } + if (1 == pAbility->FC) + { + /*Flow control in reg 4.10*/ + phyEnMsk4 = phyEnMsk4 | (1 << 10); + } + + /*1000 BASE-T control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK) + return retVal; + + phyData = (phyData & (~0x0200)) | phyEnMsk9 ; + + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK) + return retVal; + + /*Auto-Negotiation control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK) + return retVal; + + phyData = (phyData & (~0x0DE0)) | phyEnMsk4; + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK) + return retVal; + + /*Control register setting and restart auto*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData)) != RT_ERR_OK) + return retVal; + + phyData = (phyData & (~0x3140)) | phyEnMsk0; + /*If have auto-negotiation capable, then restart auto negotiation*/ + if (1 == pAbility->AutoNegotiation) + { + phyData = phyData | (1 << 9); + } + + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyAutoNegoAbility_get + * Description: + * Get PHY ability through PHY registers. + * Input: + * port - Port id. + * Output: + * pAbility - Ability structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * Get the capability of specified PHY. + */ +rtk_api_ret_t rtk_port_phyAutoNegoAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData0; + rtk_uint32 phyData4; + rtk_uint32 phyData9; + rtk_port_media_t media_type; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pAbility) + return RT_ERR_NULL_POINTER; + + if (rtk_switch_isComboPort(port) == RT_ERR_OK) + { + if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) + return retVal; + + if(media_type == PORT_MEDIA_FIBER) + { + return _rtk_port_FiberModeAbility_get(port, pAbility); + } + } + + /*Control register setting and restart auto*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK) + return retVal; + + /*Auto-Negotiation control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK) + return retVal; + + /*1000 BASE-T control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK) + return retVal; + + if (phyData9 & (1 << 9)) + pAbility->Full_1000 = 1; + else + pAbility->Full_1000 = 0; + + if (phyData4 & (1 << 11)) + pAbility->AsyFC = 1; + else + pAbility->AsyFC = 0; + + if (phyData4 & (1 << 10)) + pAbility->FC = 1; + else + pAbility->FC = 0; + + + if (phyData4 & (1 << 8)) + pAbility->Full_100 = 1; + else + pAbility->Full_100 = 0; + + if (phyData4 & (1 << 7)) + pAbility->Half_100 = 1; + else + pAbility->Half_100 = 0; + + if (phyData4 & (1 << 6)) + pAbility->Full_10 = 1; + else + pAbility->Full_10 = 0; + + if (phyData4 & (1 << 5)) + pAbility->Half_10 = 1; + else + pAbility->Half_10 = 0; + + + if (phyData0 & (1 << 12)) + pAbility->AutoNegotiation = 1; + else + pAbility->AutoNegotiation = 0; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyForceModeAbility_set + * Description: + * Set the port speed/duplex mode/pause/asy_pause in the PHY force mode. + * Input: + * port - port id. + * pAbility - Ability structure + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * While both AutoNegotiation and Full_1000 are set to 0, the PHY speed and duplex selection will + * be set as following 100F > 100H > 10F > 10H priority sequence. + * This API can be used to configure combo port in fiber mode. + * The possible parameters in fiber mode are Full_1000 and Full 100. + * All the other fields in rtk_port_phy_ability_t will be ignored in fiber port. + */ +rtk_api_ret_t rtk_port_phyForceModeAbility_set(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData; + rtk_uint32 phyEnMsk0; + rtk_uint32 phyEnMsk4; + rtk_uint32 phyEnMsk9; + rtk_port_media_t media_type; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pAbility) + return RT_ERR_NULL_POINTER; + + if (pAbility->Half_10 >= RTK_ENABLE_END || pAbility->Full_10 >= RTK_ENABLE_END || + pAbility->Half_100 >= RTK_ENABLE_END || pAbility->Full_100 >= RTK_ENABLE_END || + pAbility->Full_1000 >= RTK_ENABLE_END || pAbility->AutoNegotiation >= RTK_ENABLE_END || + pAbility->AsyFC >= RTK_ENABLE_END || pAbility->FC >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (rtk_switch_isComboPort(port) == RT_ERR_OK) + { + if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) + return retVal; + + if(media_type == PORT_MEDIA_FIBER) + { + return _rtk_port_FiberModeAbility_set(port, pAbility); + } + } + + if (1 == pAbility->Full_1000) + return RT_ERR_INPUT; + + /*for PHY force mode setup*/ + pAbility->AutoNegotiation = 0; + + phyEnMsk0 = 0; + phyEnMsk4 = 0; + phyEnMsk9 = 0; + + if (1 == pAbility->Half_10) + { + /*10BASE-TX half duplex capable in reg 4.5*/ + phyEnMsk4 = phyEnMsk4 | (1 << 5); + + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); + } + + if (1 == pAbility->Full_10) + { + /*10BASE-TX full duplex capable in reg 4.6*/ + phyEnMsk4 = phyEnMsk4 | (1 << 6); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 & (~(1 << 13)); + + /*Full duplex mode in reg 0.8*/ + phyEnMsk0 = phyEnMsk0 | (1 << 8); + + } + + if (1 == pAbility->Half_100) + { + /*100BASE-TX half duplex capable in reg 4.7*/ + phyEnMsk4 = phyEnMsk4 | (1 << 7); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 | (1 << 13); + } + + + if (1 == pAbility->Full_100) + { + /*100BASE-TX full duplex capable in reg 4.8*/ + phyEnMsk4 = phyEnMsk4 | (1 << 8); + /*Speed selection [1:0] */ + /* 11=Reserved*/ + /* 10= 1000Mpbs*/ + /* 01= 100Mpbs*/ + /* 00= 10Mpbs*/ + phyEnMsk0 = phyEnMsk0 & (~(1 << 6)); + phyEnMsk0 = phyEnMsk0 | (1 << 13); + /*Full duplex mode in reg 0.8*/ + phyEnMsk0 = phyEnMsk0 | (1 << 8); + } + + if (1 == pAbility->AsyFC) + { + /*Asymmetric flow control in reg 4.11*/ + phyEnMsk4 = phyEnMsk4 | (1 << 11); + } + if (1 == pAbility->FC) + { + /*Flow control in reg 4.10*/ + phyEnMsk4 = phyEnMsk4 | ((1 << 10)); + } + + /*1000 BASE-T control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData)) != RT_ERR_OK) + return retVal; + + phyData = (phyData & (~0x0200)) | phyEnMsk9 ; + + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, phyData)) != RT_ERR_OK) + return retVal; + + /*Auto-Negotiation control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData)) != RT_ERR_OK) + return retVal; + + phyData = (phyData & (~0x0DE0)) | phyEnMsk4; + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, phyData)) != RT_ERR_OK) + return retVal; + + /*Control register setting and power off/on*/ + phyData = phyEnMsk0 & (~(1 << 12)); + phyData |= (1 << 11); /* power down PHY, bit 11 should be set to 1 */ + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) + return retVal; + + phyData = phyData & (~(1 << 11)); /* power on PHY, bit 11 should be set to 0*/ + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, phyData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyForceModeAbility_get + * Description: + * Get PHY ability through PHY registers. + * Input: + * port - Port id. + * Output: + * pAbility - Ability structure + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * Get the capability of specified PHY. + */ +rtk_api_ret_t rtk_port_phyForceModeAbility_get(rtk_port_t port, rtk_port_phy_ability_t *pAbility) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData0; + rtk_uint32 phyData4; + rtk_uint32 phyData9; + rtk_port_media_t media_type; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pAbility) + return RT_ERR_NULL_POINTER; + + if (rtk_switch_isComboPort(port) == RT_ERR_OK) + { + if ((retVal = rtk_port_phyComboPortMedia_get(port, &media_type)) != RT_ERR_OK) + return retVal; + + if(media_type == PORT_MEDIA_FIBER) + { + return _rtk_port_FiberModeAbility_get(port, pAbility); + } + } + + /*Control register setting and restart auto*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &phyData0)) != RT_ERR_OK) + return retVal; + + /*Auto-Negotiation control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_AN_ADVERTISEMENT_REG, &phyData4)) != RT_ERR_OK) + return retVal; + + /*1000 BASE-T control register setting*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_1000_BASET_CONTROL_REG, &phyData9)) != RT_ERR_OK) + return retVal; + + if (phyData9 & (1 << 9)) + pAbility->Full_1000 = 1; + else + pAbility->Full_1000 = 0; + + if (phyData4 & (1 << 11)) + pAbility->AsyFC = 1; + else + pAbility->AsyFC = 0; + + if (phyData4 & ((1 << 10))) + pAbility->FC = 1; + else + pAbility->FC = 0; + + + if (phyData4 & (1 << 8)) + pAbility->Full_100 = 1; + else + pAbility->Full_100 = 0; + + if (phyData4 & (1 << 7)) + pAbility->Half_100 = 1; + else + pAbility->Half_100 = 0; + + if (phyData4 & (1 << 6)) + pAbility->Full_10 = 1; + else + pAbility->Full_10 = 0; + + if (phyData4 & (1 << 5)) + pAbility->Half_10 = 1; + else + pAbility->Half_10 = 0; + + + if (phyData0 & (1 << 12)) + pAbility->AutoNegotiation = 1; + else + pAbility->AutoNegotiation = 0; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyStatus_get + * Description: + * Get Ethernet PHY linking status + * Input: + * port - Port id. + * Output: + * linkStatus - PHY link status + * speed - PHY link speed + * duplex - PHY duplex mode + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * API will return auto negotiation status of phy. + */ +rtk_api_ret_t rtk_port_phyStatus_get(rtk_port_t port, rtk_port_linkStatus_t *pLinkStatus, rtk_port_speed_t *pSpeed, rtk_port_duplex_t *pDuplex) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if( (NULL == pLinkStatus) || (NULL == pSpeed) || (NULL == pDuplex) ) + return RT_ERR_NULL_POINTER; + + /*Get PHY resolved register*/ + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_RESOLVED_REG, &phyData)) != RT_ERR_OK) + return retVal; + + /*check link status*/ + if (phyData & (1<<2)) + { + *pLinkStatus = 1; + + /*check link speed*/ + *pSpeed = (phyData&0x0030) >> 4; + + /*check link duplex*/ + *pDuplex = (phyData&0x0008) >> 3; + } + else + { + *pLinkStatus = 0; + *pSpeed = 0; + *pDuplex = 0; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macForceLink_set + * Description: + * Set port force linking configuration. + * Input: + * port - port id. + * pPortability - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can set Port/MAC force mode properties. + */ +rtk_api_ret_t rtk_port_macForceLink_set(rtk_port_t port, rtk_port_mac_ability_t *pPortability) +{ + rtk_api_ret_t retVal; + rtl8367c_port_ability_t ability; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pPortability) + return RT_ERR_NULL_POINTER; + + if (pPortability->forcemode >1|| pPortability->speed > 2 || pPortability->duplex > 1 || + pPortability->link > 1 || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) + return retVal; + + ability.forcemode = pPortability->forcemode; + ability.speed = pPortability->speed; + ability.duplex = pPortability->duplex; + ability.link = pPortability->link; + ability.nway = pPortability->nway; + ability.txpause = pPortability->txpause; + ability.rxpause = pPortability->rxpause; + + if ((retVal = rtl8367c_setAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macForceLink_get + * Description: + * Get port force linking configuration. + * Input: + * port - Port id. + * Output: + * pPortability - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get Port/MAC force mode properties. + */ +rtk_api_ret_t rtk_port_macForceLink_get(rtk_port_t port, rtk_port_mac_ability_t *pPortability) +{ + rtk_api_ret_t retVal; + rtl8367c_port_ability_t ability; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pPortability) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortForceLink(rtk_switch_port_L2P_get(port), &ability)) != RT_ERR_OK) + return retVal; + + pPortability->forcemode = ability.forcemode; + pPortability->speed = ability.speed; + pPortability->duplex = ability.duplex; + pPortability->link = ability.link; + pPortability->nway = ability.nway; + pPortability->txpause = ability.txpause; + pPortability->rxpause = ability.rxpause; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macForceLinkExt_set + * Description: + * Set external interface force linking configuration. + * Input: + * port - external port ID + * mode - external interface mode + * pPortability - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface force mode properties. + * The external interface can be set to: + * - MODE_EXT_DISABLE, + * - MODE_EXT_RGMII, + * - MODE_EXT_MII_MAC, + * - MODE_EXT_MII_PHY, + * - MODE_EXT_TMII_MAC, + * - MODE_EXT_TMII_PHY, + * - MODE_EXT_GMII, + * - MODE_EXT_RMII_MAC, + * - MODE_EXT_RMII_PHY, + * - MODE_EXT_SGMII, + * - MODE_EXT_HSGMII, + * - MODE_EXT_1000X_100FX, + * - MODE_EXT_1000X, + * - MODE_EXT_100FX, + */ +rtk_api_ret_t rtk_port_macForceLinkExt_set(rtk_port_t port, rtk_mode_ext_t mode, rtk_port_mac_ability_t *pPortability) +{ + rtk_api_ret_t retVal; + rtl8367c_port_ability_t ability; + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_EXT(port); + + if(NULL == pPortability) + return RT_ERR_NULL_POINTER; + + if (mode >=MODE_EXT_END) + return RT_ERR_INPUT; + + if(mode == MODE_EXT_HSGMII) + { + if (pPortability->forcemode > 1 || pPortability->speed != PORT_SPEED_2500M || pPortability->duplex != PORT_FULL_DUPLEX || + pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) + return RT_ERR_INPUT; + + if(rtk_switch_isHsgPort(port) != RT_ERR_OK) + return RT_ERR_PORT_ID; + } + else + { + if (pPortability->forcemode > 1 || pPortability->speed > PORT_SPEED_1000M || pPortability->duplex >= PORT_DUPLEX_END || + pPortability->link >= PORT_LINKSTATUS_END || pPortability->nway > 1 || pPortability->txpause > 1 || pPortability->rxpause > 1) + return RT_ERR_INPUT; + } + + ext_id = port - 15; + + if(mode == MODE_EXT_DISABLE) + { + memset(&ability, 0x00, sizeof(rtl8367c_port_ability_t)); + if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicPortExtMode(ext_id, mode)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) + return retVal; + + ability.forcemode = pPortability->forcemode; + ability.speed = (mode == MODE_EXT_HSGMII) ? PORT_SPEED_1000M : pPortability->speed; + ability.duplex = pPortability->duplex; + ability.link = pPortability->link; + ability.nway = pPortability->nway; + ability.txpause = pPortability->txpause; + ability.rxpause = pPortability->rxpause; + + if ((retVal = rtl8367c_setAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macForceLinkExt_get + * Description: + * Set external interface force linking configuration. + * Input: + * port - external port ID + * Output: + * pMode - external interface mode + * pPortability - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get external interface force mode properties. + */ +rtk_api_ret_t rtk_port_macForceLinkExt_get(rtk_port_t port, rtk_mode_ext_t *pMode, rtk_port_mac_ability_t *pPortability) +{ + rtk_api_ret_t retVal; + rtl8367c_port_ability_t ability; + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_EXT(port); + + if(NULL == pMode) + return RT_ERR_NULL_POINTER; + + if(NULL == pPortability) + return RT_ERR_NULL_POINTER; + + ext_id = port - 15; + + if ((retVal = rtl8367c_getAsicPortExtMode(ext_id, (rtk_uint32 *)pMode)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortForceLinkExt(ext_id, &ability)) != RT_ERR_OK) + return retVal; + + pPortability->forcemode = ability.forcemode; + pPortability->speed = (*pMode == MODE_EXT_HSGMII) ? PORT_SPEED_2500M : ability.speed; + pPortability->duplex = ability.duplex; + pPortability->link = ability.link; + pPortability->nway = ability.nway; + pPortability->txpause = ability.txpause; + pPortability->rxpause = ability.rxpause; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_port_macStatus_get + * Description: + * Get port link status. + * Input: + * port - Port id. + * Output: + * pPortstatus - port ability configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get Port/PHY properties. + */ +rtk_api_ret_t rtk_port_macStatus_get(rtk_port_t port, rtk_port_mac_ability_t *pPortstatus) +{ + rtk_api_ret_t retVal; + rtl8367c_port_status_t status; + rtk_uint32 hsgsel; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pPortstatus) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortStatus(rtk_switch_port_L2P_get(port), &status)) != RT_ERR_OK) + return retVal; + + + pPortstatus->duplex = status.duplex; + pPortstatus->link = status.link; + pPortstatus->nway = status.nway; + pPortstatus->txpause = status.txpause; + pPortstatus->rxpause = status.rxpause; + + if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgsel)) != RT_ERR_OK) + return retVal; + + if( (rtk_switch_isHsgPort(port) == RT_ERR_OK) && (hsgsel == 1) ) + pPortstatus->speed = PORT_SPEED_2500M; + else + pPortstatus->speed = status.speed; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macLocalLoopbackEnable_set + * Description: + * Set Port Local Loopback. (Redirect TX to RX.) + * Input: + * port - Port id. + * enable - Loopback state, 0:disable, 1:enable + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can enable/disable Local loopback in MAC. + * For UTP port, This API will also enable the digital + * loopback bit in PHY register for sync of speed between + * PHY and MAC. For EXT port, users need to force the + * link state by themselves. + */ +rtk_api_ret_t rtk_port_macLocalLoopbackEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortLoopback(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + if(rtk_switch_isUtpPort(port) == RT_ERR_OK) + { + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, &data)) != RT_ERR_OK) + return retVal; + + if(enable == ENABLED) + data |= (0x0001 << 14); + else + data &= ~(0x0001 << 14); + + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), PHY_CONTROL_REG, data)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_macLocalLoopbackEnable_get + * Description: + * Get Port Local Loopback. (Redirect TX to RX.) + * Input: + * port - Port id. + * Output: + * pEnable - Loopback state, 0:disable, 1:enable + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +rtk_api_ret_t rtk_port_macLocalLoopbackEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortLoopback(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyReg_set + * Description: + * Set PHY register data of the specific port. + * Input: + * port - port id. + * reg - Register id + * regData - Register data + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * This API can set PHY register data of the specific port. + */ +rtk_api_ret_t rtk_port_phyReg_set(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t regData) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), reg, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyReg_get + * Description: + * Get PHY register data of the specific port. + * Input: + * port - Port id. + * reg - Register id + * Output: + * pData - Register data + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PHY_REG_ID - Invalid PHY address + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * This API can get PHY register data of the specific port. + */ +rtk_api_ret_t rtk_port_phyReg_get(rtk_port_t port, rtk_port_phy_reg_t reg, rtk_port_phy_data_t *pData) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), reg, pData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_backpressureEnable_set + * Description: + * Set the half duplex back-pressure enable status of the specific port. + * Input: + * port - port id. + * enable - Back pressure status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set the half duplex back-pressure enable status of the specific port. + * The half duplex back-pressure enable status of the port is as following: + * - DISABLE(Defer) + * - ENABLE (Back-pressure) + */ +rtk_api_ret_t rtk_port_backpressureEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortJamMode(!enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_backpressureEnable_get + * Description: + * Get the half duplex back-pressure enable status of the specific port. + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get the half duplex back-pressure enable status of the specific port. + * The half duplex back-pressure enable status of the port is as following: + * - DISABLE(Defer) + * - ENABLE (Back-pressure) + */ +rtk_api_ret_t rtk_port_backpressureEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortJamMode(®Data)) != RT_ERR_OK) + return retVal; + + *pEnable = !regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_adminEnable_set + * Description: + * Set port admin configuration of the specific port. + * Input: + * port - port id. + * enable - Back pressure status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set port admin configuration of the specific port. + * The port admin configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_port_adminEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) + return retVal; + + if (ENABLED == enable) + { + data &= 0xF7FF; + data |= 0x0200; + } + else if (DISABLED == enable) + { + data |= 0x0800; + } + + if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_adminEnable_get + * Description: + * Get port admin configuration of the specific port. + * Input: + * port - Port id. + * Output: + * pEnable - Back pressure status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API can get port admin configuration of the specific port. + * The port admin configuration of the port is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_port_adminEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) + return retVal; + + if ( (data & 0x0800) == 0x0800) + { + *pEnable = DISABLED; + } + else + { + *pEnable = ENABLED; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_isolation_set + * Description: + * Set permitted port isolation portmask + * Input: + * port - port id. + * pPortmask - Permit port mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * This API set the port mask that a port can transmit packet to of each port + * A port can only transmit packet to ports included in permitted portmask + */ +rtk_api_ret_t rtk_port_isolation_set(rtk_port_t port, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + /* check port mask */ + RTK_CHK_PORTMASK_VALID(pPortmask); + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_isolation_get + * Description: + * Get permitted port isolation portmask + * Input: + * port - Port id. + * Output: + * pPortmask - Permit port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * This API get the port mask that a port can transmit packet to of each port + * A port can only transmit packet to ports included in permitted portmask + */ +rtk_api_ret_t rtk_port_isolation_get(rtk_port_t port, rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_switch_port_L2P_get(port), &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_rgmiiDelayExt_set + * Description: + * Set RGMII interface delay value for TX and RX. + * Input: + * txDelay - TX delay value, 1 for delay 2ns and 0 for no-delay + * rxDelay - RX delay value, 0~7 for delay setup. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface 2 RGMII delay. + * In TX delay, there are 2 selection: no-delay and 2ns delay. + * In RX delay, there are 8 steps for delay tuning. 0 for no-delay, and 7 for maximum delay. + */ +rtk_api_ret_t rtk_port_rgmiiDelayExt_set(rtk_port_t port, rtk_data_t txDelay, rtk_data_t rxDelay) +{ + rtk_api_ret_t retVal; + rtk_uint32 regAddr, regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_EXT(port); + + if ((txDelay > 1) || (rxDelay > 7)) + return RT_ERR_INPUT; + + if(port == EXT_PORT0) + regAddr = RTL8367C_REG_EXT1_RGMXF; + else if(port == EXT_PORT1) + regAddr = RTL8367C_REG_EXT2_RGMXF; + else + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + regData = (regData & 0xFFF0) | ((txDelay << 3) & 0x0008) | (rxDelay & 0x0007); + + if ((retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_rgmiiDelayExt_get + * Description: + * Get RGMII interface delay value for TX and RX. + * Input: + * None + * Output: + * pTxDelay - TX delay value + * pRxDelay - RX delay value + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set external interface 2 RGMII delay. + * In TX delay, there are 2 selection: no-delay and 2ns delay. + * In RX delay, there are 8 steps for delay tuning. 0 for n0-delay, and 7 for maximum delay. + */ +rtk_api_ret_t rtk_port_rgmiiDelayExt_get(rtk_port_t port, rtk_data_t *pTxDelay, rtk_data_t *pRxDelay) +{ + rtk_api_ret_t retVal; + rtk_uint32 regAddr, regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_EXT(port); + + if( (NULL == pTxDelay) || (NULL == pRxDelay) ) + return RT_ERR_NULL_POINTER; + + if(port == EXT_PORT0) + regAddr = RTL8367C_REG_EXT1_RGMXF; + else if(port == EXT_PORT1) + regAddr = RTL8367C_REG_EXT2_RGMXF; + else + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + *pTxDelay = (regData & 0x0008) >> 3; + *pRxDelay = regData & 0x0007; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyEnableAll_set + * Description: + * Set all PHY enable status. + * Input: + * enable - PHY Enable State. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set all PHY status. + * The configuration of all PHY is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_port_phyEnableAll_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 data; + rtk_uint32 port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortEnableAll(enable)) != RT_ERR_OK) + return retVal; + + RTK_SCAN_ALL_LOG_PORT(port) + { + if(rtk_switch_isUtpPort(port) == RT_ERR_OK) + { + if ((retVal = rtk_port_phyReg_get(port, PHY_CONTROL_REG, &data)) != RT_ERR_OK) + return retVal; + + if (ENABLED == enable) + { + data &= 0xF7FF; + data |= 0x0200; + } + else + { + data |= 0x0800; + } + + if ((retVal = rtk_port_phyReg_set(port, PHY_CONTROL_REG, data)) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_port_phyEnableAll_get + * Description: + * Get all PHY enable status. + * Input: + * None + * Output: + * pEnable - PHY Enable State. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API can set all PHY status. + * The configuration of all PHY is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_port_phyEnableAll_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortEnableAll(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_efid_set + * Description: + * Set port-based enhanced filtering database + * Input: + * port - Port id. + * efid - Specified enhanced filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid fid. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can set port-based enhanced filtering database. + */ +rtk_api_ret_t rtk_port_efid_set(rtk_port_t port, rtk_data_t efid) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /* efid must be 0~7 */ + if (efid > RTK_EFID_MAX) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), efid))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_efid_get + * Description: + * Get port-based enhanced filtering database + * Input: + * port - Port id. + * Output: + * pEfid - Specified enhanced filtering database. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get port-based enhanced filtering database status. + */ +rtk_api_ret_t rtk_port_efid_get(rtk_port_t port, rtk_data_t *pEfid) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEfid) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortIsolationEfid(rtk_switch_port_L2P_get(port), pEfid))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyComboPortMedia_set + * Description: + * Set Combo port media type + * Input: + * port - Port id. + * media - Media (COPPER or FIBER) + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can Set Combo port media type. + */ +rtk_api_ret_t rtk_port_phyComboPortMedia_set(rtk_port_t port, rtk_port_media_t media) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + rtk_uint32 idx; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + /* Check Combo Port ID */ + RTK_CHK_PORT_IS_COMBO(port); + + if (media >= PORT_MEDIA_END) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + if(regData != 0x6367) + return RT_ERR_CHIP_NOT_SUPPORTED; + + if(media == PORT_MEDIA_FIBER) + { + /* software init */ + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + for(idx = 0; idx < FIBER_INIT_SIZE; idx++) + { + if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber[idx])) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, 1))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_DW8051_READY_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_phyComboPortMedia_get + * Description: + * Get Combo port media type + * Input: + * port - Port id. + * Output: + * pMedia - Media (COPPER or FIBER) + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can Set Combo port media type. + */ +rtk_api_ret_t rtk_port_phyComboPortMedia_get(rtk_port_t port, rtk_port_media_t *pMedia) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + rtk_uint32 data; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + /* Check Combo Port ID */ + RTK_CHK_PORT_IS_COMBO(port); + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + if(regData != 0x6367) + { + *pMedia = PORT_MEDIA_COPPER; + } + else + { + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_UTP_FIB_DET, RTL8367C_UTP_FIRST_OFFSET, &data))!=RT_ERR_OK) + return retVal; + + if(data == 1) + *pMedia = PORT_MEDIA_COPPER; + else + *pMedia = PORT_MEDIA_FIBER; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_rtctEnable_set + * Description: + * Enable RTCT test + * Input: + * pPortmask - Port mask of RTCT enabled port + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * The API can enable RTCT Test + */ +rtk_api_ret_t rtk_port_rtctEnable_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Mask Valid */ + RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask); + + if ((retVal = rtl8367c_setAsicPortRTCTEnable(pPortmask->bits[0]))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_rtctDisable_set + * Description: + * Disable RTCT test + * Input: + * pPortmask - Port mask of RTCT disabled port + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask. + * Note: + * The API can disable RTCT Test + */ +rtk_api_ret_t rtk_port_rtctDisable_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Mask Valid */ + RTK_CHK_PORTMASK_VALID_ONLY_UTP(pPortmask); + + if ((retVal = rtl8367c_setAsicPortRTCTDisable(pPortmask->bits[0]))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_port_rtctResult_get + * Description: + * Get the result of RTCT test + * Input: + * port - Port ID + * Output: + * pRtctResult - The result of RTCT result + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_PHY_RTCT_NOT_FINISH - Testing does not finish. + * Note: + * The API can get RTCT test result. + * RTCT test may takes 4.8 seconds to finish its test at most. + * Thus, if this API return RT_ERR_PHY_RTCT_NOT_FINISH or + * other error code, the result can not be referenced and + * user should call this API again until this API returns + * a RT_ERR_OK. + * The result is stored at pRtctResult->ge_result + * pRtctResult->linkType is unused. + * The unit of channel length is 2.5cm. Ex. 300 means 300 * 2.5 = 750cm = 7.5M + */ +rtk_api_ret_t rtk_port_rtctResult_get(rtk_port_t port, rtk_rtctResult_t *pRtctResult) +{ + rtk_api_ret_t retVal; + rtl8367c_port_rtct_result_t result; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_IS_UTP(port); + + memset(pRtctResult, 0x00, sizeof(rtk_rtctResult_t)); + if ((retVal = rtl8367c_getAsicPortRTCTResult(port, &result))!=RT_ERR_OK) + return retVal; + + pRtctResult->result.ge_result.channelALen = result.channelALen; + pRtctResult->result.ge_result.channelBLen = result.channelBLen; + pRtctResult->result.ge_result.channelCLen = result.channelCLen; + pRtctResult->result.ge_result.channelDLen = result.channelDLen; + + pRtctResult->result.ge_result.channelALinedriver = result.channelALinedriver; + pRtctResult->result.ge_result.channelBLinedriver = result.channelBLinedriver; + pRtctResult->result.ge_result.channelCLinedriver = result.channelCLinedriver; + pRtctResult->result.ge_result.channelDLinedriver = result.channelDLinedriver; + + pRtctResult->result.ge_result.channelAMismatch = result.channelAMismatch; + pRtctResult->result.ge_result.channelBMismatch = result.channelBMismatch; + pRtctResult->result.ge_result.channelCMismatch = result.channelCMismatch; + pRtctResult->result.ge_result.channelDMismatch = result.channelDMismatch; + + pRtctResult->result.ge_result.channelAOpen = result.channelAOpen; + pRtctResult->result.ge_result.channelBOpen = result.channelBOpen; + pRtctResult->result.ge_result.channelCOpen = result.channelCOpen; + pRtctResult->result.ge_result.channelDOpen = result.channelDOpen; + + pRtctResult->result.ge_result.channelAShort = result.channelAShort; + pRtctResult->result.ge_result.channelBShort = result.channelBShort; + pRtctResult->result.ge_result.channelCShort = result.channelCShort; + pRtctResult->result.ge_result.channelDShort = result.channelDShort; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_port_sds_reset + * Description: + * Reset Serdes + * Input: + * port - Port ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can reset Serdes + */ +rtk_api_ret_t rtk_port_sds_reset(rtk_port_t port) +{ + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) + return RT_ERR_PORT_ID; + + ext_id = port - 15; + return rtl8367c_sdsReset(ext_id); +} + +/* Function Name: + * rtk_port_sgmiiLinkStatus_get + * Description: + * Get SGMII status + * Input: + * port - Port ID + * Output: + * pSignalDetect - Signal detect + * pSync - Sync + * pLink - Link + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can reset Serdes + */ +rtk_api_ret_t rtk_port_sgmiiLinkStatus_get(rtk_port_t port, rtk_data_t *pSignalDetect, rtk_data_t *pSync, rtk_port_linkStatus_t *pLink) +{ + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) + return RT_ERR_PORT_ID; + + if(NULL == pSignalDetect) + return RT_ERR_NULL_POINTER; + + if(NULL == pSync) + return RT_ERR_NULL_POINTER; + + if(NULL == pLink) + return RT_ERR_NULL_POINTER; + + ext_id = port - 15; + return rtl8367c_getSdsLinkStatus(ext_id, (rtk_uint32 *)pSignalDetect, (rtk_uint32 *)pSync, (rtk_uint32 *)pLink); +} + +/* Function Name: + * rtk_port_sgmiiNway_set + * Description: + * Configure SGMII/HSGMII port Nway state + * Input: + * port - Port ID + * state - Nway state + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API configure SGMII/HSGMII port Nway state + */ +rtk_api_ret_t rtk_port_sgmiiNway_set(rtk_port_t port, rtk_enable_t state) +{ + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) + return RT_ERR_PORT_ID; + + if(state >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + ext_id = port - 15; + return rtl8367c_setSgmiiNway(ext_id, (rtk_uint32)state); +} + +/* Function Name: + * rtk_port_sgmiiNway_get + * Description: + * Get SGMII/HSGMII port Nway state + * Input: + * port - Port ID + * Output: + * pState - Nway state + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get SGMII/HSGMII port Nway state + */ +rtk_api_ret_t rtk_port_sgmiiNway_get(rtk_port_t port, rtk_enable_t *pState) +{ + rtk_uint32 ext_id; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + if(rtk_switch_isSgmiiPort(port) != RT_ERR_OK) + return RT_ERR_PORT_ID; + + if(NULL == pState) + return RT_ERR_NULL_POINTER; + + ext_id = port - 15; + return rtl8367c_getSgmiiNway(ext_id, (rtk_uint32 *)pState); +} diff --git a/drivers/net/phy/rtk/rtl8367c/ptp.c b/drivers/net/phy/rtk/rtl8367c/ptp.c new file mode 100644 index 000000000000..af8ce30912dc --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/ptp.c @@ -0,0 +1,759 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 39583 $ + * $Date: 2013-05-20 16:59:23 +0800 (星期一, 20 五月 2013) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in time module. + * + */ + +#include +#include +#include +#include + +#include +#include + +/* Function Name: + * rtk_ptp_init + * Description: + * PTP function initialization. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API is used to initialize PTP status. + */ +rtk_api_ret_t rtk_ptp_init(void) +{ + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_mac_set + * Description: + * Configure PTP mac address. + * Input: + * mac - mac address to parser PTP packets. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_mac_set(rtk_mac_t mac) +{ + rtk_api_ret_t retVal; + ether_addr_t sw_mac; + + memcpy(sw_mac.octet, mac.octet, ETHER_ADDR_LEN); + + if((retVal=rtl8367c_setAsicEavMacAddress(sw_mac))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_mac_get + * Description: + * Get PTP mac address. + * Input: + * None + * Output: + * pMac - mac address to parser PTP packets. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_mac_get(rtk_mac_t *pMac) +{ + rtk_api_ret_t retVal; + ether_addr_t sw_mac; + + if((retVal=rtl8367c_getAsicEavMacAddress(&sw_mac))!=RT_ERR_OK) + return retVal; + + memcpy(pMac->octet, sw_mac.octet, ETHER_ADDR_LEN); + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_tpid_set + * Description: + * Configure PTP accepted outer & inner tag TPID. + * Input: + * outerId - Ether type of S-tag frame parsing in PTP ports. + * innerId - Ether type of C-tag frame parsing in PTP ports. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_tpid_set(rtk_ptp_tpid_t outerId, rtk_ptp_tpid_t innerId) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((outerId>RTK_MAX_NUM_OF_TPID) ||(innerId>RTK_MAX_NUM_OF_TPID)) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicEavTpid(outerId, innerId)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_tpid_get + * Description: + * Get PTP accepted outer & inner tag TPID. + * Input: + * None + * Output: + * pOuterId - Ether type of S-tag frame parsing in PTP ports. + * pInnerId - Ether type of C-tag frame parsing in PTP ports. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_tpid_get(rtk_ptp_tpid_t *pOuterId, rtk_ptp_tpid_t *pInnerId) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicEavTpid(pOuterId, pInnerId)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_refTime_set + * Description: + * Set the reference time of the specified device. + * Input: + * timeStamp - reference timestamp value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Applicable: + * 8390, 8380 + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_refTime_set(rtk_ptp_timeStamp_t timeStamp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicEavSysTime(timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_refTime_get + * Description: + * Get the reference time of the specified device. + * Input: + * Output: + * pTimeStamp - pointer buffer of the reference time + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_refTime_get(rtk_ptp_timeStamp_t *pTimeStamp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicEavSysTime(&pTimeStamp->sec, &pTimeStamp->nsec))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_refTimeAdjust_set + * Description: + * Adjust the reference time. + * Input: + * unit - unit id + * sign - significant + * timeStamp - reference timestamp value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * sign=0 for positive adjustment, sign=1 for negative adjustment. + */ +rtk_api_ret_t rtk_ptp_refTimeAdjust_set(rtk_ptp_sys_adjust_t sign, rtk_ptp_timeStamp_t timeStamp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (timeStamp.nsec > RTK_MAX_NUM_OF_NANO_SECOND) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicEavSysTimeAdjust(sign, timeStamp.sec, timeStamp.nsec))!=RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_refTimeEnable_set + * Description: + * Set the enable state of reference time of the specified device. + * Input: + * enable - status + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_refTimeEnable_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicEavSysTimeCtrl(enable))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_refTimeEnable_get + * Description: + * Get the enable state of reference time of the specified device. + * Input: + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_refTimeEnable_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicEavSysTimeCtrl(pEnable))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_portEnable_set + * Description: + * Set PTP status of the specified port. + * Input: + * port - port id + * enable - status + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_portEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port is PTP port */ + RTK_CHK_PORT_IS_PTP(port); + + if (enable>=RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicEavPortEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_portEnable_get + * Description: + * Get PTP status of the specified port. + * Input: + * port - port id + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_portEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port is PTP port */ + RTK_CHK_PORT_IS_PTP(port); + + if ((retVal = rtl8367c_getAsicEavPortEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_ptp_portTimestamp_get + * Description: + * Get PTP timestamp according to the PTP identifier on the dedicated port from the specified device. + * Input: + * unit - unit id + * port - port id + * type - PTP message type + * Output: + * pInfo - pointer buffer of sequence ID and timestamp + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Applicable: + * 8390, 8380 + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_portTimestamp_get( rtk_port_t port, rtk_ptp_msgType_t type, rtk_ptp_info_t *pInfo) +{ + rtk_api_ret_t retVal; + rtl8367c_ptp_time_stamp_t time; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port is PTP port */ + RTK_CHK_PORT_IS_PTP(port); + + if ((retVal = rtl8367c_getAsicEavPortTimeStamp(rtk_switch_port_L2P_get(port), type, &time)) != RT_ERR_OK) + return retVal; + + pInfo->sequenceId = time.sequence_id; + pInfo->timeStamp.sec = time.second; + pInfo->timeStamp.nsec = time.nano_second; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_intControl_set + * Description: + * Set PTP interrupt trigger status configuration. + * Input: + * type - Interrupt type. + * enable - Interrupt status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set PTP interrupt status configuration. + * The interrupt trigger status is shown in the following: + * PTP_INT_TYPE_TX_SYNC = 0, + * PTP_INT_TYPE_TX_DELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_REQ, + * PTP_INT_TYPE_TX_PDELAY_RESP, + * PTP_INT_TYPE_RX_SYNC, + * PTP_INT_TYPE_RX_DELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_REQ, + * PTP_INT_TYPE_RX_PDELAY_RESP, + * PTP_INT_TYPE_ALL, + */ +rtk_api_ret_t rtk_ptp_intControl_set(rtk_ptp_intType_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 mask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type>=PTP_INT_TYPE_END) + return RT_ERR_INPUT; + + if (PTP_INT_TYPE_ALL!=type) + { + if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK) + return retVal; + + if (ENABLED == enable) + mask = mask | (1<=PTP_INT_TYPE_ALL) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicEavInterruptMask(&mask)) != RT_ERR_OK) + return retVal; + + if (0 == (mask&(1<=RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicEavTrap(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_ptp_portPtpEnable_get + * Description: + * Get PTP packet trap of the specified port. + * Input: + * port - port id + * Output: + * pEnable - status + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT - invalid port id + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +rtk_api_ret_t rtk_ptp_portTrap_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicEavTrap(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/qos.c b/drivers/net/phy/rtk/rtl8367c/qos.c new file mode 100644 index 000000000000..9bcb49cfbd64 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/qos.c @@ -0,0 +1,1452 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in QoS module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Function Name: + * rtk_qos_init + * Description: + * Configure QoS default settings with queue number assignment to each port. + * Input: + * queueNum - Queue number of each port. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QUEUE_NUM - Invalid queue number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API will initialize related QoS setting with queue number assignment. + * The queue number is from 1 to 8. + */ +rtk_api_ret_t rtk_qos_init(rtk_queue_num_t queueNum) +{ + CONST_T rtk_uint16 g_prioritytToQid[8][8]= { + {0, 0,0,0,0,0,0,0}, + {0, 0,0,0,7,7,7,7}, + {0, 0,0,0,1,1,7,7}, + {0, 0,1,1,2,2,7,7}, + {0, 0,1,1,2,3,7,7}, + {0, 0,1,2,3,4,7,7}, + {0, 0,1,2,3,4,5,7}, + {0,1,2,3,4,5,6,7} + }; + + CONST_T rtk_uint32 g_priorityDecision[8] = {0x01, 0x80,0x04,0x02,0x20,0x40,0x10,0x08}; + CONST_T rtk_uint32 g_prioritytRemap[8] = {0,1,2,3,4,5,6,7}; + + rtk_api_ret_t retVal; + rtk_uint32 qmapidx; + rtk_uint32 priority; + rtk_uint32 priDec; + rtk_uint32 port; + rtk_uint32 dscp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (queueNum <= 0 || queueNum > RTK_MAX_NUM_OF_QUEUE) + return RT_ERR_QUEUE_NUM; + + /*Set Output Queue Number*/ + if (RTK_MAX_NUM_OF_QUEUE == queueNum) + qmapidx = 0; + else + qmapidx = queueNum; + + RTK_SCAN_ALL_PHY_PORTMASK(port) + { + if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(port, qmapidx)) != RT_ERR_OK) + return retVal; + } + + /*Set Priority to Qid*/ + for (priority = 0; priority <= RTK_PRIMAX; priority++) + { + if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queueNum - 1, priority, g_prioritytToQid[queueNum - 1][priority])) != RT_ERR_OK) + return retVal; + } + + /*Set Flow Control Type to Ingress Flow Control*/ + if ((retVal = rtl8367c_setAsicFlowControlSelect(FC_INGRESS)) != RT_ERR_OK) + return retVal; + + + /*Priority Decision Order*/ + for (priDec = 0;priDec < PRIDEC_END;priDec++) + { + if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX0, priDec, g_priorityDecision[priDec])) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPriorityDecision(PRIDECTBL_IDX1, priDec, g_priorityDecision[priDec])) != RT_ERR_OK) + return retVal; + } + + /*Set Port-based Priority to 0*/ + RTK_SCAN_ALL_PHY_PORTMASK(port) + { + if ((retVal = rtl8367c_setAsicPriorityPortBased(port, 0)) != RT_ERR_OK) + return retVal; + } + + /*Disable 1p Remarking*/ + RTK_SCAN_ALL_PHY_PORTMASK(port) + { + if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(port, DISABLED)) != RT_ERR_OK) + return retVal; + } + + /*Disable DSCP Remarking*/ + if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(DISABLED)) != RT_ERR_OK) + return retVal; + + /*Set 1p & DSCP Priority Remapping & Remarking*/ + for (priority = 0; priority <= RTL8367C_PRIMAX; priority++) + { + if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(priority, g_prioritytRemap[priority])) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(priority, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(priority, 0)) != RT_ERR_OK) + return retVal; + } + + /*Set DSCP Priority*/ + for (dscp = 0; dscp <= 63; dscp++) + { + if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, 0)) != RT_ERR_OK) + return retVal; + } + + /* Fine-tune B/T value */ + if((retVal = rtl8367c_setAsicReg(0x1722, 0x1158)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_priSel_set + * Description: + * Configure the priority order among different priority mechanism. + * Input: + * index - Priority decision table index (0~1) + * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter. + * Note: + * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. + * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to + * assign queue priority to receiving frame. + * The priority sources are: + * - PRIDEC_PORT + * - PRIDEC_ACL + * - PRIDEC_DSCP + * - PRIDEC_1Q + * - PRIDEC_1AD + * - PRIDEC_CVLAN + * - PRIDEC_DA + * - PRIDEC_SA + */ +rtk_api_ret_t rtk_qos_priSel_set(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec) +{ + rtk_api_ret_t retVal; + rtk_uint32 port_pow; + rtk_uint32 dot1q_pow; + rtk_uint32 dscp_pow; + rtk_uint32 acl_pow; + rtk_uint32 svlan_pow; + rtk_uint32 cvlan_pow; + rtk_uint32 smac_pow; + rtk_uint32 dmac_pow; + rtk_uint32 i; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index < 0 || index >= PRIDECTBL_END) + return RT_ERR_ENTRY_INDEX; + + if (pPriDec->port_pri >= 8 || pPriDec->dot1q_pri >= 8 || pPriDec->acl_pri >= 8 || pPriDec->dscp_pri >= 8 || + pPriDec->cvlan_pri >= 8 || pPriDec->svlan_pri >= 8 || pPriDec->dmac_pri >= 8 || pPriDec->smac_pri >= 8) + return RT_ERR_QOS_SEL_PRI_SOURCE; + + port_pow = 1; + for (i = pPriDec->port_pri; i > 0; i--) + port_pow = (port_pow)*2; + + dot1q_pow = 1; + for (i = pPriDec->dot1q_pri; i > 0; i--) + dot1q_pow = (dot1q_pow)*2; + + acl_pow = 1; + for (i = pPriDec->acl_pri; i > 0; i--) + acl_pow = (acl_pow)*2; + + dscp_pow = 1; + for (i = pPriDec->dscp_pri; i > 0; i--) + dscp_pow = (dscp_pow)*2; + + svlan_pow = 1; + for (i = pPriDec->svlan_pri; i > 0; i--) + svlan_pow = (svlan_pow)*2; + + cvlan_pow = 1; + for (i = pPriDec->cvlan_pri; i > 0; i--) + cvlan_pow = (cvlan_pow)*2; + + dmac_pow = 1; + for (i = pPriDec->dmac_pri; i > 0; i--) + dmac_pow = (dmac_pow)*2; + + smac_pow = 1; + for (i = pPriDec->smac_pri; i > 0; i--) + smac_pow = (smac_pow)*2; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_PORT, port_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_ACL, acl_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DSCP, dscp_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1Q, dot1q_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_1AD, svlan_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_CVLAN, cvlan_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_DA, dmac_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPriorityDecision(index, PRIDEC_SA, smac_pow)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_priSel_get + * Description: + * Get the priority order configuration among different priority mechanism. + * Input: + * index - Priority decision table index (0~1) + * Output: + * pPriDec - Priority assign for port, dscp, 802.1p, cvlan, svlan, acl based priority decision . + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * ASIC will follow user priority setting of mechanisms to select mapped queue priority for receiving frame. + * If two priority mechanisms are the same, the ASIC will chose the highest priority from mechanisms to + * assign queue priority to receiving frame. + * The priority sources are: + * - PRIDEC_PORT, + * - PRIDEC_ACL, + * - PRIDEC_DSCP, + * - PRIDEC_1Q, + * - PRIDEC_1AD, + * - PRIDEC_CVLAN, + * - PRIDEC_DA, + * - PRIDEC_SA, + */ +rtk_api_ret_t rtk_qos_priSel_get(rtk_qos_priDecTbl_t index, rtk_priority_select_t *pPriDec) +{ + + rtk_api_ret_t retVal; + rtk_int32 i; + rtk_uint32 port_pow; + rtk_uint32 dot1q_pow; + rtk_uint32 dscp_pow; + rtk_uint32 acl_pow; + rtk_uint32 svlan_pow; + rtk_uint32 cvlan_pow; + rtk_uint32 smac_pow; + rtk_uint32 dmac_pow; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index < 0 || index >= PRIDECTBL_END) + return RT_ERR_ENTRY_INDEX; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_PORT, &port_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_ACL, &acl_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DSCP, &dscp_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1Q, &dot1q_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_1AD, &svlan_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_CVLAN, &cvlan_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_DA, &dmac_pow)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPriorityDecision(index, PRIDEC_SA, &smac_pow)) != RT_ERR_OK) + return retVal; + + for (i = 31; i >= 0; i--) + { + if (port_pow & (1 << i)) + { + pPriDec->port_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (dot1q_pow & (1 << i)) + { + pPriDec->dot1q_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (acl_pow & (1 << i)) + { + pPriDec->acl_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (dscp_pow & (1 << i)) + { + pPriDec->dscp_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (svlan_pow & (1 << i)) + { + pPriDec->svlan_pri = i; + break; + } + } + + for (i = 31;i >= 0; i--) + { + if (cvlan_pow & (1 << i)) + { + pPriDec->cvlan_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (dmac_pow&(1<dmac_pri = i; + break; + } + } + + for (i = 31; i >= 0; i--) + { + if (smac_pow & (1 << i)) + { + pPriDec->smac_pri = i; + break; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pPriRemap_set + * Description: + * Configure 1Q priorities mapping to internal absolute priority. + * Input: + * dot1p_pri - 802.1p priority value. + * int_pri - internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_1pPriRemap_set(rtk_pri_t dot1p_pri, rtk_pri_t int_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (dot1p_pri > RTL8367C_PRIMAX || int_pri > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if ((retVal = rtl8367c_setAsicPriorityDot1qRemapping(dot1p_pri, int_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pPriRemap_get + * Description: + * Get 1Q priorities mapping to internal absolute priority. + * Input: + * dot1p_pri - 802.1p priority value . + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * Priority of 802.1Q assignment for internal asic priority, and it is used for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_1pPriRemap_get(rtk_pri_t dot1p_pri, rtk_pri_t *pInt_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (dot1p_pri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_getAsicPriorityDot1qRemapping(dot1p_pri, pInt_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpPriRemap_set + * Description: + * Map dscp value to internal priority. + * Input: + * dscp - Dscp value of receiving frame + * int_pri - internal priority value . + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically + * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of + * DSCP are carefully chosen then backward compatibility can be achieved. + */ +rtk_api_ret_t rtk_qos_dscpPriRemap_set(rtk_dscp_t dscp, rtk_pri_t int_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (int_pri > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if (dscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + if ((retVal = rtl8367c_setAsicPriorityDscpBased(dscp, int_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpPriRemap_get + * Description: + * Get dscp value to internal priority. + * Input: + * dscp - Dscp value of receiving frame + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * Note: + * The Differentiated Service Code Point is a selector for router's per-hop behaviors. As a selector, there is no implication that a numerically + * greater DSCP implies a better network service. As can be seen, the DSCP totally overlaps the old precedence field of TOS. So if values of + * DSCP are carefully chosen then backward compatibility can be achieved. + */ +rtk_api_ret_t rtk_qos_dscpPriRemap_get(rtk_dscp_t dscp, rtk_pri_t *pInt_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (dscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + if ((retVal = rtl8367c_getAsicPriorityDscpBased(dscp, pInt_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_portPri_set + * Description: + * Configure priority usage to each port. + * Input: + * port - Port id. + * int_pri - internal priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_SEL_PORT_PRI - Invalid port priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can set priority of port assignments for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_portPri_set(rtk_port_t port, rtk_pri_t int_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (int_pri > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_setAsicPriorityPortBased(rtk_switch_port_L2P_get(port), int_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_portPri_get + * Description: + * Get priority usage to each port. + * Input: + * port - Port id. + * Output: + * pInt_pri - internal priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get priority of port assignments for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_portPri_get(rtk_port_t port, rtk_pri_t *pInt_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicPriorityPortBased(rtk_switch_port_L2P_get(port), pInt_pri)) != RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_queueNum_set + * Description: + * Set output queue number for each port. + * Input: + * port - Port id. + * index - Mapping queue number (1~8) + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * Note: + * The API can set the output queue number of the specified port. The queue number is from 1 to 8. + */ +rtk_api_ret_t rtk_qos_queueNum_set(rtk_port_t port, rtk_queue_num_t queue_num) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) + return RT_ERR_FAILED; + + if (RTK_MAX_NUM_OF_QUEUE == queue_num) + queue_num = 0; + + if ((retVal = rtl8367c_setAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), queue_num)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_queueNum_get + * Description: + * Get output queue number. + * Input: + * port - Port id. + * Output: + * pQueue_num - Mapping queue number + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API will return the output queue number of the specified port. The queue number is from 1 to 8. + */ +rtk_api_ret_t rtk_qos_queueNum_get(rtk_port_t port, rtk_queue_num_t *pQueue_num) +{ + rtk_api_ret_t retVal; + rtk_uint32 qidx; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicOutputQueueMappingIndex(rtk_switch_port_L2P_get(port), &qidx)) != RT_ERR_OK) + return retVal; + + if (0 == qidx) + *pQueue_num = 8; + else + *pQueue_num = qidx; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_priMap_set + * Description: + * Set output queue number for each port. + * Input: + * queue_num - Queue number usage. + * pPri2qid - Priority mapping to queue ID. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * RT_ERR_QUEUE_ID - Invalid queue id. + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * ASIC supports priority mapping to queue with different queue number from 1 to 8. + * For different queue numbers usage, ASIC supports different internal available queue IDs. + */ +rtk_api_ret_t rtk_qos_priMap_set(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid) +{ + rtk_api_ret_t retVal; + rtk_uint32 pri; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) + return RT_ERR_QUEUE_NUM; + + for (pri = 0; pri <= RTK_PRIMAX; pri++) + { + if (pPri2qid->pri2queue[pri] > RTK_QIDMAX) + return RT_ERR_QUEUE_ID; + + if ((retVal = rtl8367c_setAsicPriorityToQIDMappingTable(queue_num - 1, pri, pPri2qid->pri2queue[pri])) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_priMap_get + * Description: + * Get priority to queue ID mapping table parameters. + * Input: + * queue_num - Queue number usage. + * Output: + * pPri2qid - Priority mapping to queue ID. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QUEUE_NUM - Invalid queue number. + * Note: + * The API can return the mapping queue id of the specified priority and queue number. + * The queue number is from 1 to 8. + */ +rtk_api_ret_t rtk_qos_priMap_get(rtk_queue_num_t queue_num, rtk_qos_pri2queue_t *pPri2qid) +{ + rtk_api_ret_t retVal; + rtk_uint32 pri; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((0 == queue_num) || (queue_num > RTK_MAX_NUM_OF_QUEUE)) + return RT_ERR_QUEUE_NUM; + + for (pri = 0; pri <= RTK_PRIMAX; pri++) + { + if ((retVal = rtl8367c_getAsicPriorityToQIDMappingTable(queue_num-1, pri, &pPri2qid->pri2queue[pri])) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_schedulingQueue_set + * Description: + * Set weight and type of queues in dedicated port. + * Input: + * port - Port id. + * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight. + * Note: + * The API can set weight and type, strict priority or weight fair queue (WFQ) for + * dedicated port for using queues. If queue id is not included in queue usage, + * then its type and weight setting in dummy for setting. There are priorities + * as queue id in strict queues. It means strict queue id 5 carrying higher priority + * than strict queue id 4. The WFQ queue weight is from 1 to 127, and weight 0 is + * for strict priority queue type. + */ +rtk_api_ret_t rtk_qos_schedulingQueue_set(rtk_port_t port, rtk_qos_queue_weights_t *pQweights) +{ + rtk_api_ret_t retVal; + rtk_uint32 qid; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + for (qid = 0; qid < RTL8367C_QUEUENO; qid ++) + { + + if (pQweights->weights[qid] > QOS_WEIGHT_MAX) + return RT_ERR_QOS_QUEUE_WEIGHT; + + if (0 == pQweights->weights[qid]) + { + if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_STRICT)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicQueueType(rtk_switch_port_L2P_get(port), qid, QTYPE_WFQ)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicWFQWeight(rtk_switch_port_L2P_get(port),qid, pQweights->weights[qid])) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_schedulingQueue_get + * Description: + * Get weight and type of queues in dedicated port. + * Input: + * port - Port id. + * Output: + * pQweights - The array of weights for WRR/WFQ queue (0 for STRICT_PRIORITY queue). + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get weight and type, strict priority or weight fair queue (WFQ) for dedicated port for using queues. + * The WFQ queue weight is from 1 to 127, and weight 0 is for strict priority queue type. + */ +rtk_api_ret_t rtk_qos_schedulingQueue_get(rtk_port_t port, rtk_qos_queue_weights_t *pQweights) +{ + rtk_api_ret_t retVal; + rtk_uint32 qid,qtype,qweight; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + for (qid = 0; qid < RTL8367C_QUEUENO; qid++) + { + if ((retVal = rtl8367c_getAsicQueueType(rtk_switch_port_L2P_get(port), qid, &qtype)) != RT_ERR_OK) + return retVal; + + if (QTYPE_STRICT == qtype) + { + pQweights->weights[qid] = 0; + } + else if (QTYPE_WFQ == qtype) + { + if ((retVal = rtl8367c_getAsicWFQWeight(rtk_switch_port_L2P_get(port), qid, &qweight)) != RT_ERR_OK) + return retVal; + pQweights->weights[qid] = qweight; + } + } + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemarkEnable_set + * Description: + * Set 1p Remarking state + * Input: + * port - Port id. + * enable - State of per-port 1p Remarking + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid enable parameter. + * Note: + * The API can enable or disable 802.1p remarking ability for whole system. + * The status of 802.1p remark: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_qos_1pRemarkEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemarkEnable_get + * Description: + * Get 802.1p remarking ability. + * Input: + * port - Port id. + * Output: + * pEnable - Status of 802.1p remark. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get 802.1p remarking ability. + * The status of 802.1p remark: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_qos_1pRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicRemarkingDot1pAbility(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemark_set + * Description: + * Set 802.1p remarking parameter. + * Input: + * int_pri - Internal priority value. + * dot1p_pri - 802.1p priority value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_PRIORITY - Invalid 1p priority. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can set 802.1p parameters source priority and new priority. + */ +rtk_api_ret_t rtk_qos_1pRemark_set(rtk_pri_t int_pri, rtk_pri_t dot1p_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (int_pri > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if (dot1p_pri > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if ((retVal = rtl8367c_setAsicRemarkingDot1pParameter(int_pri, dot1p_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemark_get + * Description: + * Get 802.1p remarking parameter. + * Input: + * int_pri - Internal priority value. + * Output: + * pDot1p_pri - 802.1p priority value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can get 802.1p remarking parameters. It would return new priority of ingress priority. + */ +rtk_api_ret_t rtk_qos_1pRemark_get(rtk_pri_t int_pri, rtk_pri_t *pDot1p_pri) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (int_pri > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_getAsicRemarkingDot1pParameter(int_pri, pDot1p_pri)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemarkSrcSel_set + * Description: + * Set remarking source of 802.1p remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure 802.1p remark functionality to map original 802.1p value or internal + * priority to TX DSCP value. + */ +rtk_api_ret_t rtk_qos_1pRemarkSrcSel_set(rtk_qos_1pRmkSrc_t type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= DOT1P_RMK_SRC_END ) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_setAsicRemarkingDot1pSrc(type)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_1pRemarkSrcSel_get + * Description: + * Get remarking source of 802.1p remarking. + * Input: + * none + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +rtk_api_ret_t rtk_qos_1pRemarkSrcSel_get(rtk_qos_1pRmkSrc_t *pType) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicRemarkingDot1pSrc(pType)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_qos_dscpRemarkEnable_set + * Description: + * Set DSCP remarking ability. + * Input: + * port - Port id. + * enable - status of DSCP remark. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * RT_ERR_ENABLE - Invalid enable parameter. + * Note: + * The API can enable or disable DSCP remarking ability for whole system. + * The status of DSCP remark: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_qos_dscpRemarkEnable_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /*for whole system function, the port value should be 0xFF*/ + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicRemarkingDscpAbility(enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpRemarkEnable_get + * Description: + * Get DSCP remarking ability. + * Input: + * port - Port id. + * Output: + * pEnable - status of DSCP remarking. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get DSCP remarking ability. + * The status of DSCP remark: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_qos_dscpRemarkEnable_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /*for whole system function, the port value should be 0xFF*/ + if (port != RTK_WHOLE_SYSTEM) + return RT_ERR_PORT_ID; + + if ((retVal = rtl8367c_getAsicRemarkingDscpAbility(pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpRemark_set + * Description: + * Set DSCP remarking parameter. + * Input: + * int_pri - Internal priority value. + * dscp - DSCP value. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value. + * Note: + * The API can set DSCP value and mapping priority. + */ +rtk_api_ret_t rtk_qos_dscpRemark_set(rtk_pri_t int_pri, rtk_dscp_t dscp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (int_pri > RTK_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if (dscp > RTK_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + if ((retVal = rtl8367c_setAsicRemarkingDscpParameter(int_pri, dscp)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_qos_dscpRemark_get + * Description: + * Get DSCP remarking parameter. + * Input: + * int_pri - Internal priority value. + * Output: + * Dscp - DSCP value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority. + * Note: + * The API can get DSCP parameters. It would return DSCP value for mapping priority. + */ +rtk_api_ret_t rtk_qos_dscpRemark_get(rtk_pri_t int_pri, rtk_dscp_t *pDscp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (int_pri > RTK_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_getAsicRemarkingDscpParameter(int_pri, pDscp)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpRemarkSrcSel_set + * Description: + * Set remarking source of DSCP remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure DSCP remark functionality to map original DSCP value or internal + * priority to TX DSCP value. + */ +rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_set(rtk_qos_dscpRmkSrc_t type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= DSCP_RMK_SRC_END ) + return RT_ERR_QOS_INT_PRIORITY; + + if ((retVal = rtl8367c_setAsicRemarkingDscpSrc(type)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dcpRemarkSrcSel_get + * Description: + * Get remarking source of DSCP remarking. + * Input: + * none + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +rtk_api_ret_t rtk_qos_dscpRemarkSrcSel_get(rtk_qos_dscpRmkSrc_t *pType) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicRemarkingDscpSrc(pType)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpRemark2Dscp_set + * Description: + * Set DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * rmkDscp - remarked DSCP value + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * Note: + * dscp parameter can be DSCP value or internal priority according to configuration of API + * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP + * value or internal priority to TX DSCP value. + */ +rtk_api_ret_t rtk_qos_dscpRemark2Dscp_set(rtk_dscp_t dscp, rtk_dscp_t rmkDscp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((dscp > RTK_DSCPMAX) || (rmkDscp > RTK_DSCPMAX)) + return RT_ERR_QOS_DSCP_VALUE; + + if ((retVal = rtl8367c_setAsicRemarkingDscp2Dscp(dscp, rmkDscp)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_dscpRemark2Dscp_get + * Description: + * Get DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * Output: + * pDscp - remarked DSCP value + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * None. + */ +rtk_api_ret_t rtk_qos_dscpRemark2Dscp_get(rtk_dscp_t dscp, rtk_dscp_t *pDscp) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (dscp > RTK_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + if ((retVal = rtl8367c_getAsicRemarkingDscp2Dscp(dscp, pDscp)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_portPriSelIndex_set + * Description: + * Configure priority decision index to each port. + * Input: + * port - Port id. + * index - priority decision index. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENTRY_INDEX - Invalid entry index. + * Note: + * The API can set priority of port assignments for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_portPriSelIndex_set(rtk_port_t port, rtk_qos_priDecTbl_t index) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (index >= PRIDECTBL_END ) + return RT_ERR_ENTRY_INDEX; + + if ((retVal = rtl8367c_setAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), index)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_qos_portPriSelIndex_get + * Description: + * Get priority decision index from each port. + * Input: + * port - Port id. + * Output: + * pIndex - priority decision index. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get priority of port assignments for queue usage and packet scheduling. + */ +rtk_api_ret_t rtk_qos_portPriSelIndex_get(rtk_port_t port, rtk_qos_priDecTbl_t *pIndex) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicPortPriorityDecisionIndex(rtk_switch_port_L2P_get(port), pIndex)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/rate.c b/drivers/net/phy/rtk/rtl8367c/rate.c new file mode 100644 index 000000000000..a077e0c5cc16 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rate.c @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in rate module. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Function Name: + * rtk_rate_shareMeter_set + * Description: + * Set meter configuration + * Input: + * index - shared meter index + * type - shared meter type + * rate - rate of share meter + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * RT_ERR_RATE - Invalid rate + * RT_ERR_INPUT - Invalid input parameters + * Note: + * The API can set shared meter rate and ifg include for each meter. + * The rate unit is 1 kbps and the range is from 8k to 1048568k if type is METER_TYPE_KBPS and + * the granularity of rate is 8 kbps. + * The rate unit is packets per second and the range is 1 ~ 0x1FFF if type is METER_TYPE_PPS. + * The ifg_include parameter is used + * for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_shareMeter_set(rtk_meter_id_t index, rtk_meter_type_t type, rtk_rate_t rate, rtk_enable_t ifg_include) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + if (type >= METER_TYPE_END) + return RT_ERR_INPUT; + + if (ifg_include >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + switch (type) + { + case METER_TYPE_KBPS: + if (rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG || rate < RTL8367C_QOS_RATE_INPUT_MIN) + return RT_ERR_RATE ; + + if ((retVal = rtl8367c_setAsicShareMeter(index, rate >> 3, ifg_include)) != RT_ERR_OK) + return retVal; + + break; + case METER_TYPE_PPS: + if (rate > RTL8367C_QOS_PPS_INPUT_MAX || rate < RTL8367C_QOS_PPS_INPUT_MIN) + return RT_ERR_RATE ; + + if ((retVal = rtl8367c_setAsicShareMeter(index, rate, ifg_include)) != RT_ERR_OK) + return retVal; + + break; + default: + return RT_ERR_INPUT; + } + + /* Set Type */ + if ((retVal = rtl8367c_setAsicShareMeterType(index, (rtk_uint32)type)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_shareMeter_get + * Description: + * Get meter configuration + * Input: + * index - shared meter index + * Output: + * pType - Meter Type + * pRate - pointer of rate of share meter + * pIfg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * + */ +rtk_api_ret_t rtk_rate_shareMeter_get(rtk_meter_id_t index, rtk_meter_type_t *pType, rtk_rate_t *pRate, rtk_enable_t *pIfg_include) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + if(NULL == pType) + return RT_ERR_NULL_POINTER; + + if(NULL == pRate) + return RT_ERR_NULL_POINTER; + + if(NULL == pIfg_include) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicShareMeter(index, ®Data, pIfg_include)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicShareMeterType(index, (rtk_uint32 *)pType)) != RT_ERR_OK) + return retVal; + + if(*pType == METER_TYPE_KBPS) + *pRate = regData<<3; + else + *pRate = regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_shareMeterBucket_set + * Description: + * Set meter Bucket Size + * Input: + * index - shared meter index + * bucket_size - Bucket Size + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_INPUT - Error Input + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * The API can set shared meter bucket size. + */ +rtk_api_ret_t rtk_rate_shareMeterBucket_set(rtk_meter_id_t index, rtk_uint32 bucket_size) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + if(bucket_size > RTL8367C_METERBUCKETSIZEMAX) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicShareMeterBucketSize(index, bucket_size)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_shareMeterBucket_get + * Description: + * Get meter Bucket Size + * Input: + * index - shared meter index + * Output: + * pBucket_size - Bucket Size + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * The API can get shared meter bucket size. + */ +rtk_api_ret_t rtk_rate_shareMeterBucket_get(rtk_meter_id_t index, rtk_uint32 *pBucket_size) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + if(NULL == pBucket_size) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicShareMeterBucketSize(index, pBucket_size)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_igrBandwidthCtrlRate_set + * Description: + * Set port ingress bandwidth control + * Input: + * port - Port id + * rate - Rate of share meter + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * fc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_ENABLE - Invalid IFG parameter. + * RT_ERR_INBW_RATE - Invalid ingress rate parameter. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_set(rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include, rtk_enable_t fc_enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(ifg_include >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(fc_enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if(rtk_switch_isHsgPort(port) == RT_ERR_OK) + { + if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) + return RT_ERR_QOS_EBW_RATE ; + } + else + { + if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) + return RT_ERR_QOS_EBW_RATE ; + } + + if ((retVal = rtl8367c_setAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), rate>>3, ifg_include,fc_enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_igrBandwidthCtrlRate_get + * Description: + * Get port ingress bandwidth control + * Input: + * port - Port id + * Output: + * pRate - Rate of share meter + * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude + * pFc_enable - enable flow control or not, ENABLE:use flow control DISABLE:drop + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_igrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include, rtk_enable_t *pFc_enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pIfg_include) + return RT_ERR_NULL_POINTER; + + if(NULL == pFc_enable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortIngressBandwidth(rtk_switch_port_L2P_get(port), ®Data, pIfg_include, pFc_enable)) != RT_ERR_OK) + return retVal; + + *pRate = regData<<3; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_egrBandwidthCtrlRate_set + * Description: + * Set port egress bandwidth control + * Input: + * port - Port id + * rate - Rate of egress bandwidth + * ifg_include - include IFG or not, ENABLE:include DISABLE:exclude + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_QOS_EBW_RATE - Invalid egress bandwidth/rate + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_set( rtk_port_t port, rtk_rate_t rate, rtk_enable_t ifg_include) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(rtk_switch_isHsgPort(port) == RT_ERR_OK) + { + if ((rate > RTL8367C_QOS_RATE_INPUT_MAX_HSG) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) + return RT_ERR_QOS_EBW_RATE ; + } + else + { + if ((rate > RTL8367C_QOS_RATE_INPUT_MAX) || (rate < RTL8367C_QOS_RATE_INPUT_MIN)) + return RT_ERR_QOS_EBW_RATE ; + } + + if (ifg_include >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicPortEgressRate(rtk_switch_port_L2P_get(port), rate>>3)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortEgressRateIfg(ifg_include)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_egrBandwidthCtrlRate_get + * Description: + * Get port egress bandwidth control + * Input: + * port - Port id + * Output: + * pRate - Rate of egress bandwidth + * pIfg_include - Rate's calculation including IFG, ENABLE:include DISABLE:exclude + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The rate unit is 1 kbps and the range is from 8k to 1048568k. The granularity of rate is 8 kbps. + * The ifg_include parameter is used for rate calculation with/without inter-frame-gap and preamble. + */ +rtk_api_ret_t rtk_rate_egrBandwidthCtrlRate_get(rtk_port_t port, rtk_rate_t *pRate, rtk_enable_t *pIfg_include) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pRate) + return RT_ERR_NULL_POINTER; + + if(NULL == pIfg_include) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortEgressRate(rtk_switch_port_L2P_get(port), ®Data)) != RT_ERR_OK) + return retVal; + + *pRate = regData << 3; + + if ((retVal = rtl8367c_getAsicPortEgressRateIfg((rtk_uint32*)pIfg_include)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_rate_egrQueueBwCtrlEnable_get + * Description: + * Get enable status of egress bandwidth control on specified queue. + * Input: + * unit - unit id + * port - port id + * queue - queue id + * Output: + * pEnable - Pointer to enable status of egress queue bandwidth control + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_get(rtk_port_t port, rtk_qid_t queue, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /*for whole port function, the queue value should be 0xFF*/ + if (queue != RTK_WHOLE_SYSTEM) + return RT_ERR_QUEUE_ID; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicAprEnable(rtk_switch_port_L2P_get(port),pEnable))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_egrQueueBwCtrlEnable_set + * Description: + * Set enable status of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * enable - enable status of egress queue bandwidth control + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_INPUT - invalid input parameter + * Note: + * None + */ +rtk_api_ret_t rtk_rate_egrQueueBwCtrlEnable_set(rtk_port_t port, rtk_qid_t queue, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /*for whole port function, the queue value should be 0xFF*/ + if (queue != RTK_WHOLE_SYSTEM) + return RT_ERR_QUEUE_ID; + + if (enable>=RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicAprEnable(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_egrQueueBwCtrlRate_get + * Description: + * Get rate of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * pIndex - shared meter index + * Output: + * pRate - pointer to rate of egress queue bandwidth control + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter id + * Note: + * The actual rate control is set in shared meters. + * The unit of granularity is 8Kbps. + */ +rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_get(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t *pIndex) +{ + rtk_api_ret_t retVal; + rtk_uint32 offset_idx; + rtk_uint32 phy_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (queue >= RTK_MAX_NUM_OF_QUEUE) + return RT_ERR_QUEUE_ID; + + if(NULL == pIndex) + return RT_ERR_NULL_POINTER; + + phy_port = rtk_switch_port_L2P_get(port); + if ((retVal=rtl8367c_getAsicAprMeter(phy_port, queue,&offset_idx))!=RT_ERR_OK) + return retVal; + + *pIndex = offset_idx + ((phy_port%4)*8); + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_rate_egrQueueBwCtrlRate_set + * Description: + * Set rate of egress bandwidth control on specified queue. + * Input: + * port - port id + * queue - queue id + * index - shared meter index + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_QUEUE_ID - invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter id + * Note: + * The actual rate control is set in shared meters. + * The unit of granularity is 8Kbps. + */ +rtk_api_ret_t rtk_rate_egrQueueBwCtrlRate_set(rtk_port_t port, rtk_qid_t queue, rtk_meter_id_t index) +{ + rtk_api_ret_t retVal; + rtk_uint32 offset_idx; + rtk_uint32 phy_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (queue >= RTK_MAX_NUM_OF_QUEUE) + return RT_ERR_QUEUE_ID; + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + phy_port = rtk_switch_port_L2P_get(port); + if (index < ((phy_port%4)*8) || index > (7 + (phy_port%4)*8)) + return RT_ERR_FILTER_METER_ID; + + offset_idx = index - ((phy_port%4)*8); + + if ((retVal=rtl8367c_setAsicAprMeter(phy_port,queue,offset_idx))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rldp.c b/drivers/net/phy/rtk/rtl8367c/rldp.c new file mode 100644 index 000000000000..0ecc32a6b571 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rldp.c @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : Declaration of RLDP and RLPP API + * + * Feature : The file have include the following module and sub-modules + * 1) RLDP and RLPP configuration and status + * + */ + + +/* + * Include Files + */ +#include +#include +//#include +#include + +#include +#include + +/* + * Symbol Definition + */ + + +/* + * Data Declaration + */ + + +/* + * Macro Declaration + */ + + +/* + * Function Declaration + */ + +/* Module Name : RLDP */ + +/* Function Name: + * rtk_rldp_config_set + * Description: + * Set RLDP module configuration + * Input: + * pConfig - configuration structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +rtk_api_ret_t rtk_rldp_config_set(rtk_rldp_config_t *pConfig) +{ + rtk_api_ret_t retVal; + ether_addr_t magic; + rtk_uint32 pmsk; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (pConfig->rldp_enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (pConfig->trigger_mode >= RTK_RLDP_TRIGGER_END) + return RT_ERR_INPUT; + + if (pConfig->compare_type >= RTK_RLDP_CMPTYPE_END) + return RT_ERR_INPUT; + + if (pConfig->num_check >= RTK_RLDP_NUM_MAX) + return RT_ERR_INPUT; + + if (pConfig->interval_check >= RTK_RLDP_INTERVAL_MAX) + return RT_ERR_INPUT; + + if (pConfig->num_loop >= RTK_RLDP_NUM_MAX) + return RT_ERR_INPUT; + + if (pConfig->interval_loop >= RTK_RLDP_INTERVAL_MAX) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpTxPortmask(0x00))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpTxPortmask(pmsk))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldp(pConfig->rldp_enable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpTriggerMode(pConfig->trigger_mode))!=RT_ERR_OK) + return retVal; + + memcpy(&magic, &pConfig->magic, sizeof(ether_addr_t)); + if ((retVal = rtl8367c_setAsicRldpMagicNum(magic))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpCompareRandomNumber(pConfig->compare_type))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpCheckingStatePara(pConfig->num_check, pConfig->interval_check))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRldpLoopStatePara(pConfig->num_loop, pConfig->interval_loop))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_rldp_config_get + * Description: + * Get RLDP module configuration + * Input: + * None + * Output: + * pConfig - configuration structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +rtk_api_ret_t rtk_rldp_config_get(rtk_rldp_config_t *pConfig) +{ + rtk_api_ret_t retVal; + ether_addr_t magic; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicRldp(&pConfig->rldp_enable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRldpTriggerMode(&pConfig->trigger_mode))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRldpMagicNum(&magic))!=RT_ERR_OK) + return retVal; + memcpy(&pConfig->magic, &magic, sizeof(ether_addr_t)); + + if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRldpCompareRandomNumber(&pConfig->compare_type))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRldpCheckingStatePara(&pConfig->num_check, &pConfig->interval_check))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRldpLoopStatePara(&pConfig->num_loop, &pConfig->interval_loop))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_rldp_portConfig_set + * Description: + * Set per port RLDP module configuration + * Input: + * port - port number to be configured + * pPortConfig - per port configuration structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +rtk_api_ret_t rtk_rldp_portConfig_set(rtk_port_t port, rtk_rldp_portConfig_t *pPortConfig) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + rtk_uint32 phy_port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (pPortConfig->tx_enable>= RTK_ENABLE_END) + return RT_ERR_INPUT; + + phy_port = rtk_switch_port_L2P_get(port); + + if ((retVal = rtl8367c_getAsicRldpTxPortmask(&pmsk))!=RT_ERR_OK) + return retVal; + + if (pPortConfig->tx_enable) + { + pmsk |=(1<tx_enable = ENABLED; + } + else + { + pPortConfig->tx_enable = DISABLED; + } + + return RT_ERR_OK; +} /* end of rtk_rldp_portConfig_get */ + + +/* Function Name: + * rtk_rldp_status_get + * Description: + * Get RLDP module status + * Input: + * None + * Output: + * pStatus - status structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER + * Note: + * None + */ +rtk_api_ret_t rtk_rldp_status_get(rtk_rldp_status_t *pStatus) +{ + rtk_api_ret_t retVal; + ether_addr_t seed; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_getAsicRldpRandomNumber(&seed))!=RT_ERR_OK) + return retVal; + memcpy(&pStatus->id, &seed, sizeof(ether_addr_t)); + + return RT_ERR_OK; +} /* end of rtk_rldp_status_get */ + + +/* Function Name: + * rtk_rldp_portStatus_get + * Description: + * Get RLDP module status + * Input: + * port - port number to be get + * Output: + * pPortStatus - per port status structure of RLDP + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * None + */ +rtk_api_ret_t rtk_rldp_portStatus_get(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + rtk_portmask_t logicalPmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicRldpLoopedPortmask(&pmsk))!=RT_ERR_OK) + return retVal; + if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) + return retVal; + + if (logicalPmask.bits[0] & (1<loop_status = RTK_RLDP_LOOPSTS_LOOPING; + } + else + { + pPortStatus->loop_status = RTK_RLDP_LOOPSTS_NONE; + } + + if ((retVal = rtl8367c_getAsicRldpEnterLoopedPortmask(&pmsk))!=RT_ERR_OK) + return retVal; + if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) + return retVal; + + if (logicalPmask.bits[0] & (1<loop_enter = RTK_RLDP_LOOPSTS_LOOPING; + } + else + { + pPortStatus->loop_enter = RTK_RLDP_LOOPSTS_NONE; + } + + if ((retVal = rtl8367c_getAsicRldpLeaveLoopedPortmask(&pmsk))!=RT_ERR_OK) + return retVal; + if ((retVal = rtk_switch_portmask_P2L_get(pmsk, &logicalPmask)) != RT_ERR_OK) + return retVal; + + if (logicalPmask.bits[0] & (1<loop_leave = RTK_RLDP_LOOPSTS_LOOPING; + } + else + { + pPortStatus->loop_leave = RTK_RLDP_LOOPSTS_NONE; + } + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_rldp_portStatus_clear + * Description: + * Clear RLDP module status + * Input: + * port - port number to be clear + * pPortStatus - per port status structure of RLDP + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT + * RT_ERR_NULL_POINTER + * Note: + * Clear operation effect loop_enter and loop_leave only, other field in + * the structure are don't care. Loop status can't be clean. + */ +rtk_api_ret_t rtk_rldp_portStatus_set(rtk_port_t port, rtk_rldp_portStatus_t *pPortStatus) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + pmsk = (pPortStatus->loop_enter)<loop_leave)< +#include +#include "./include/rtk_switch.h" +#include "./include/vlan.h" +#include "./include/port.h" +#include "./include/rate.h" +#include "./include/rtk_hal.h" +#include "./include/l2.h" +#include "./include/stat.h" +#include "./include/igmp.h" +#include "./include/trap.h" +#include "./include/leaky.h" +#include "./include/mirror.h" +#include "./include/rtl8367c_asicdrv_port.h" +#include "./include/rtl8367c_asicdrv_mib.h" +#include "./include/smi.h" +#include "./include/qos.h" +#include "./include/trunk.h" + +void rtk_hal_switch_init(void) +{ + if(rtk_switch_init() != 0) + printk("rtk_switch_init failed\n"); + mdelay(500); + /*vlan init */ + if (rtk_vlan_init() != 0) + printk("rtk_vlan_init failed\n"); +} + +void rtk_hal_dump_full_mib(void) +{ + rtk_port_t port; + rtk_stat_counter_t Cntr; + rtk_stat_port_type_t cntr_idx; + + for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { + printk("\nPort%d\n", port); + for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu ", Cntr); + if (((cntr_idx%10) == 9)) + printk("\n"); + } + } + + for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { + printk("\nPort%d\n", port); + for (cntr_idx = STAT_IfInOctets; cntr_idx < STAT_PORT_CNTR_END; cntr_idx ++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu ", Cntr); + if (((cntr_idx%10) == 9)) + printk("\n"); + } + } + rtk_stat_global_reset(); +} +void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx) +{ + rtk_port_t port; + rtk_stat_counter_t Cntr; + + for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu", Cntr); + } + for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu", Cntr); + } + printk("\n"); +} + +void rtk_hal_dump_mib(void) +{ + + printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1", + "Port2", "Port3", "Port4", "Port16", "Port17"); + /* Get TX Unicast Pkts */ + printk("TX Unicast Pkts :"); + rtk_dump_mib_type(STAT_IfOutUcastPkts); + /* Get TX Multicast Pkts */ + printk("TX Multicast Pkts:"); + rtk_dump_mib_type(STAT_IfOutMulticastPkts); + /* Get TX BroadCast Pkts */ + printk("TX BroadCast Pkts:"); + rtk_dump_mib_type(STAT_IfOutBroadcastPkts); + /* Get TX Collisions */ + /* Get TX Puase Frames */ + printk("TX Pause Frames :"); + rtk_dump_mib_type(STAT_Dot3OutPauseFrames); + /* Get TX Drop Events */ + /* Get RX Unicast Pkts */ + printk("RX Unicast Pkts :"); + rtk_dump_mib_type(STAT_IfInUcastPkts); + /* Get RX Multicast Pkts */ + printk("RX Multicast Pkts:"); + rtk_dump_mib_type(STAT_IfInMulticastPkts); + /* Get RX Broadcast Pkts */ + printk("RX Broadcast Pkts:"); + rtk_dump_mib_type(STAT_IfInBroadcastPkts); + /* Get RX FCS Erros */ + printk("RX FCS Errors :"); + rtk_dump_mib_type(STAT_Dot3StatsFCSErrors); + /* Get RX Undersize Pkts */ + printk("RX Undersize Pkts:"); + rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts); + /* Get RX Discard Pkts */ + printk("RX Discard Pkts :"); + rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards); + /* Get RX Fragments */ + printk("RX Fragments :"); + rtk_dump_mib_type(STAT_EtherStatsFragments); + /* Get RX Oversize Pkts */ + printk("RX Oversize Pkts :"); + rtk_dump_mib_type(STAT_EtherOversizeStats); + /* Get RX Jabbers */ + printk("RX Jabbers :"); + rtk_dump_mib_type(STAT_EtherStatsJabbers); + /* Get RX Pause Frames */ + printk("RX Pause Frames :"); + rtk_dump_mib_type(STAT_Dot3InPauseFrames); + /* clear MIB */ + rtk_stat_global_reset(); +} +EXPORT_SYMBOL(rtk_hal_dump_mib); + +int rtk_hal_dump_vlan(void) +{ + rtk_vlan_cfg_t vlan; + int i; + + printk("vid portmap\n"); + for (i = 0; i < RTK_SW_VID_RANGE; i++) { + rtk_vlan_get(i, &vlan); + printk("%3d ", i); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT0) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT1) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT2) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT3) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT4) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + EXT_PORT0) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + EXT_PORT1) ? '1' : '-'); + printk("\n"); + } + return 0; +} + +void rtk_hal_clear_vlan(void) +{ + rtk_api_ret_t ret; + + ret = rtk_vlan_reset(); + if (ret != RT_ERR_OK) + printk("rtk_vlan_reset failed\n"); +} + +int rtk_hal_set_vlan(struct ra_switch_ioctl_data *data) +{ + rtk_vlan_cfg_t vlan; + rtk_api_ret_t ret; + int i; + + /* clear vlan entry first */ + memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t)); + RTK_PORTMASK_CLEAR(vlan.mbr); + RTK_PORTMASK_CLEAR(vlan.untag); + rtk_vlan_set(data->vid, &vlan); + + memset(&vlan, 0x00, sizeof(rtk_vlan_cfg_t)); + for (i = 0; i < 5; i++) { + if (data->port_map & (1 << i)) { + RTK_PORTMASK_PORT_SET(vlan.mbr, i); + RTK_PORTMASK_PORT_SET(vlan.untag, i); + rtk_vlan_portPvid_set(i, data->vid, 0); + } + } + for (i = 0; i < 2; i++) { + if (data->port_map & (1 << (i + 5))) { + RTK_PORTMASK_PORT_SET(vlan.mbr, (i + EXT_PORT0)); + RTK_PORTMASK_PORT_SET(vlan.untag, (i + EXT_PORT0)); + rtk_vlan_portPvid_set((i + EXT_PORT0), data->vid, 0); + } + } + vlan.ivl_en = 1; + ret = rtk_vlan_set(data->vid, &vlan); + + return 0; +} + +void rtk_hal_vlan_portpvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority) +{ + rtk_vlan_portPvid_set(port, pvid, priority); +} + +int rtk_hal_set_ingress_rate(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + if (data->on_off == 1) + ret = + rtk_rate_igrBandwidthCtrlRate_set(data->port, data->bw, 0, + 1); + else + ret = + rtk_rate_igrBandwidthCtrlRate_set(data->port, 1048568, 0, + 1); + + return ret; +} + +int rtk_hal_set_egress_rate(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + if (data->on_off == 1) + ret = + rtk_rate_egrBandwidthCtrlRate_set(data->port, data->bw, 1); + else + ret = rtk_rate_egrBandwidthCtrlRate_set(data->port, 1048568, 1); + + return ret; +} + +void rtk_hal_dump_table(void) +{ + rtk_uint32 i; + rtk_uint32 address = 0; + rtk_l2_ucastAddr_t l2_data; + rtk_l2_ipMcastAddr_t ipMcastAddr; + + printk("hash port(0:17) fid vid mac-address\n"); + while (1) { + if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) { + break; + } else { + printk("%03x ", l2_data.address); + for (i = 0; i < 5; i++) + if ( l2_data.port == i) + printk("1"); + else + printk("-"); + for (i = 16; i < 18; i++) + if ( l2_data.port == i) + printk("1"); + else + printk("-"); + + printk(" %2d", l2_data.fid); + printk(" %4d", l2_data.cvid); + printk(" %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0], + l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3], + l2_data.mac.octet[4], l2_data.mac.octet[5]); + address ++; + } + } + + address = 0; + while (1) { + if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) { + break; + } else { + printk("%03x ", ipMcastAddr.address); + for (i = 0; i < 5; i++) + printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); + for (i = 16; i < 18; i++) + printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); + printk(" "); + printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff)); + address ++; + } + } +} + +void rtk_hal_clear_table(void) +{ + rtk_api_ret_t ret; + + ret = rtk_l2_table_clear(); + if (ret != RT_ERR_OK) + printk("rtk_l2_table_clear failed\n"); +} + +void rtk_hal_add_table(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_l2_ucastAddr_t l2_entry; + rtk_mac_t mac; + + mac.octet[0] =data->mac[0]; + mac.octet[1] =data->mac[1]; + mac.octet[2] =data->mac[2]; + mac.octet[3] =data->mac[3]; + mac.octet[4] =data->mac[4]; + mac.octet[5] =data->mac[5]; + + memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t)); + l2_entry.port = data->port; + l2_entry.ivl = 1; + l2_entry.cvid = data->vid; + l2_entry.fid = 0; + l2_entry.efid = 0; + l2_entry.is_static = 1; + ret = rtk_l2_addr_add(&mac, &l2_entry); + if (ret != RT_ERR_OK) + printk("rtk_hal_add_table failed\n"); +} + +void rtk_hal_del_table(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_l2_ucastAddr_t l2_entry; + rtk_mac_t mac; + + mac.octet[0] =data->mac[0]; + mac.octet[1] =data->mac[1]; + mac.octet[2] =data->mac[2]; + mac.octet[3] =data->mac[3]; + mac.octet[4] =data->mac[4]; + mac.octet[5] =data->mac[5]; + + memset(&l2_entry, 0x00, sizeof(rtk_l2_ucastAddr_t)); + l2_entry.port = data->port; + l2_entry.ivl = 1; + l2_entry.cvid = data->vid; + l2_entry.fid = 0; + l2_entry.efid = 0; + ret = rtk_l2_addr_del(&mac, &l2_entry); + if (ret != RT_ERR_OK) + printk("rtk_hal_add_table failed\n"); +} +void rtk_hal_get_phy_status(struct ra_switch_ioctl_data *data) +{ + rtk_port_linkStatus_t linkStatus; + rtk_port_speed_t speed; + rtk_port_duplex_t duplex; + + rtk_port_phyStatus_get(data->port, &linkStatus, &speed, &duplex); + printk("Port%d Status:\n", data->port); + if (linkStatus == 1) { + printk("Link Up"); + if (speed == 0) + printk(" 10M"); + else if (speed == 1) + printk(" 100M"); + else if (speed == 2) + printk(" 1000M"); + if (duplex == 0) + printk(" Half Duplex\n"); + else + printk(" Full Duplex\n"); + } else + printk("Link Down\n"); + +} + +void rtk_hal_set_port_mirror(struct ra_switch_ioctl_data *data) +{ + rtk_portmask_t rx_portmask; + rtk_portmask_t tx_portmask; + rtk_api_ret_t ret; + int i; + + rtk_mirror_portIso_set(ENABLED); + RTK_PORTMASK_CLEAR(rx_portmask); + RTK_PORTMASK_CLEAR(tx_portmask); + for (i = 0; i < 5; i++) + if (data->rx_port_map & (1 << i)) + RTK_PORTMASK_PORT_SET(rx_portmask, i); + for (i = 0; i < 2; i++) + if (data->rx_port_map & (1 << (i + 5))) + RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0)); + + RTK_PORTMASK_CLEAR(tx_portmask); + for (i = 0; i < 5; i++) + if (data->tx_port_map & (1 << i)) + RTK_PORTMASK_PORT_SET(tx_portmask, i); + for (i = 0; i < 2; i++) + if (data->tx_port_map & (1 << (i + 5))) + RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0)); + + ret = rtk_mirror_portBased_set(data->port, &rx_portmask, &tx_portmask); + if (!ret) + printk("rtk_mirror_portBased_set success\n"); +} + +void rtk_hal_read_reg(struct ra_switch_ioctl_data *data) +{ + ret_t retVal; + + retVal = smi_read(data->reg_addr, &data->reg_val); + if(retVal != RT_ERR_OK) + printk("switch reg read failed\n"); + else + printk("reg0x%x = 0x%x\n", data->reg_addr, data->reg_val); +} + +void rtk_hal_write_reg(struct ra_switch_ioctl_data *data) +{ + ret_t retVal; + + retVal = smi_write(data->reg_addr, data->reg_val); + if(retVal != RT_ERR_OK) + printk("switch reg write failed\n"); + else + printk("write switch reg0x%x 0x%x success\n", data->reg_addr, data->reg_val); +} + +void rtk_hal_get_phy_reg(struct ra_switch_ioctl_data *data) +{ + ret_t retVal; + rtk_port_phy_data_t Data; + + retVal = rtk_port_phyReg_get(data->port, data->reg_addr, &Data); + if (retVal == RT_ERR_OK) + printk("Get: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, Data); + else + printk("read phy reg failed\n"); +} + +void rtk_hal_set_phy_reg(struct ra_switch_ioctl_data *data) +{ + ret_t retVal; + + retVal = rtk_port_phyReg_set(data->port, data->reg_addr, data->reg_val); + if (retVal == RT_ERR_OK) + printk("Set: phy[%d].reg[%d] = 0x%04x\n", data->port, data->reg_addr, data->reg_val); + else + printk("write phy reg failed\n"); +} +void rtk_hal_qos_en(struct ra_switch_ioctl_data *data) +{ + + if (data->on_off == 1) { + if (rtk_qos_init(8) != 0) + printk("rtk_qos_init(8) failed\n"); + } + else { + if (rtk_qos_init(1) != 0) + printk("rtk_qos_init(1) failed\n"); + } +} + +void rtk_hal_qos_set_table2type(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_priority_select_t PriDec; + + /* write all pri to 0 */ + PriDec.port_pri = 0; + PriDec.dot1q_pri = 0; + PriDec.acl_pri = 0; + PriDec.cvlan_pri = 0; + PriDec.svlan_pri = 0; + PriDec.dscp_pri = 0; + PriDec.dmac_pri = 0; + PriDec.smac_pri = 0; + + if (data->qos_type == 0) + PriDec.port_pri = 1; + else if (data->qos_type == 1) + PriDec.dot1q_pri = 1; + else if (data->qos_type == 2) + PriDec.acl_pri = 1; + else if (data->qos_type == 3) + PriDec.dscp_pri = 1; + else if (data->qos_type == 4) + PriDec.cvlan_pri = 1; + else if (data->qos_type == 5) + PriDec.svlan_pri = 1; + else if (data->qos_type == 6) + PriDec.dmac_pri = 1; + else if (data->qos_type == 7) + PriDec.smac_pri = 1; + + if (data->qos_table_idx == 0) + ret = rtk_qos_priSel_set(PRIDECTBL_IDX0, &PriDec); + else + ret = rtk_qos_priSel_set(PRIDECTBL_IDX1, &PriDec); + + if (ret != 0) + printk("rtk_qos_priSel_set failed\n"); + +} + +void rtk_hal_qos_get_table2type(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_priority_select_t PriDec; + + if (data->qos_table_idx == 0) + ret = rtk_qos_priSel_get(PRIDECTBL_IDX0, &PriDec); + else + ret = rtk_qos_priSel_get(PRIDECTBL_IDX1, &PriDec); + + if (ret != 0) + printk("rtk_qos_priSel_set failed\n"); + else { + printk("port_pri = %d\n", PriDec.port_pri); + printk("dot1q_pri = %d\n", PriDec.dot1q_pri); + printk("acl_pri = %d\n", PriDec.acl_pri); + printk("dscp_pri = %d\n", PriDec.dscp_pri); + printk("cvlan_pri = %d\n", PriDec.cvlan_pri); + printk("svlan_pri = %d\n", PriDec.svlan_pri); + printk("dmac_pri = %d\n", PriDec.dmac_pri); + printk("smac_pri = %d\n", PriDec.smac_pri); + } +} + +void rtk_hal_qos_set_port2table(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + ret = rtk_qos_portPriSelIndex_set(data->port, data->qos_table_idx); + if (ret != 0) + printk("rtk_qos_portPriSelIndex_set failed\n"); +} + +void rtk_hal_qos_get_port2table(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_qos_priDecTbl_t Index; + + ret = rtk_qos_portPriSelIndex_get(data->port, &Index); + if (ret != 0) + printk("rtk_qos_portPriSelIndex_set failed\n"); + else + printk("port%d belongs to table%d\n", data->port, Index); +} + +void rtk_hal_qos_set_port2pri(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + ret = rtk_qos_portPri_set(data->port, data->qos_pri); + if (ret != 0) + printk("rtk_qos_portPri_set failed\n"); +} + +void rtk_hal_qos_get_port2pri(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_pri_t Int_pri; + + ret = rtk_qos_portPri_get(data->port, &Int_pri); + if (ret != 0) + printk("rtk_qos_portPri_set failed\n"); + else + printk("port%d priority = %d\n", data->port, Int_pri); +} + +void rtk_hal_qos_set_dscp2pri(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + ret = rtk_qos_dscpPriRemap_set(data->qos_dscp, data->qos_pri); + if (ret != 0) + printk("rtk_qos_dscpPriRemap_set failed\n"); +} + +void rtk_hal_qos_get_dscp2pri(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_pri_t Int_pri; + + ret = rtk_qos_dscpPriRemap_get(data->qos_dscp, &Int_pri); + if (ret != 0) + printk("rtk_qos_dscpPriRemap_set failed\n"); + else + printk("dscp%d priority is %d\n", data->qos_dscp, Int_pri); +} + +void rtk_hal_qos_set_pri2queue(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_qos_pri2queue_t pri2qid; + + ret = rtk_qos_priMap_get(8, &pri2qid); + pri2qid.pri2queue[data->qos_queue_num] = data->qos_pri; + ret = rtk_qos_priMap_set(8, &pri2qid); + if (ret != 0) + printk("rtk_qos_priMap_set failed\n"); +} + +void rtk_hal_qos_get_pri2queue(struct ra_switch_ioctl_data *data) +{ + int i; + rtk_api_ret_t ret; + rtk_qos_pri2queue_t pri2qid; + + ret = rtk_qos_priMap_get(8, &pri2qid); + if (ret != 0) + printk("rtk_qos_priMap_get failed\n"); + else { + for (i = 0; i < 8; i++) + printk("pri2qid.pri2queue[%d] = %d\n", i, pri2qid.pri2queue[i]); + } +} + +void rtk_hal_qos_set_queue_weight(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_qos_queue_weights_t qweights; + + ret = rtk_qos_schedulingQueue_get(data->port, &qweights); + qweights.weights[data->qos_queue_num] = data->qos_weight; + ret = rtk_qos_schedulingQueue_set(data->port, &qweights); + if (ret != 0) + printk("rtk_qos_schedulingQueue_set failed\n"); +} + +void rtk_hal_qos_get_queue_weight(struct ra_switch_ioctl_data *data) +{ + int i; + rtk_api_ret_t ret; + rtk_qos_queue_weights_t qweights; + + ret = rtk_qos_schedulingQueue_get(data->port, &qweights); + if (ret != 0) + printk("rtk_qos_schedulingQueue_get failed\n"); + else { + printk("=== Port%d queue weight ===\n", data->port); + for (i = 0; i < 8; i++) + printk("qweights.weights[%d] = %d\n",i ,qweights.weights[i]); + } +} + +void rtk_hal_enable_igmpsnoop(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_portmask_t pmask; + + + ret = rtk_igmp_init(); + if (data->on_off == 1) { + RTK_PORTMASK_CLEAR(pmask); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); + ret |= rtk_igmp_static_router_port_set(&pmask); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + + ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED); + ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED); + /* drop unknown multicast packets*/ + /* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/ + } else { + RTK_PORTMASK_CLEAR(pmask); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1); + ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + + ret |= rtk_igmp_static_router_port_set(&pmask); + } + if(ret != RT_ERR_OK) + printk("enable switch igmpsnoop failed\n"); +} + +void rtk_hal_disable_igmpsnoop(void) +{ + if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK) + printk("Disable IGMP SNOOPING failed\n"); +} + +rtk_api_ret_t rtk_port_phyTestMode_set(rtk_port_t port, rtk_port_phy_test_mode_t mode) +{ + rtk_uint32 data, regData, i; + rtk_api_ret_t retVal; + + RTK_CHK_PORT_IS_UTP(port); + + if(mode >= PHY_TEST_MODE_END) + return RT_ERR_INPUT; + + if( (mode == PHY_TEST_MODE_2) || (mode == PHY_TEST_MODE_3) ) + return RT_ERR_INPUT; + + if (PHY_TEST_MODE_NORMAL != mode) + { + /* Other port should be Normal mode */ + RTK_SCAN_ALL_LOG_PORT(i) + { + if(rtk_switch_isUtpPort(i) == RT_ERR_OK) + { + if(i != port) + { + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(i), 9, &data)) != RT_ERR_OK) + return retVal; + + if((data & 0xE000) != 0) + return RT_ERR_NOT_ALLOWED; + } + } + } + } + + if ((retVal = rtl8367c_getAsicPHYReg(rtk_switch_port_L2P_get(port), 9, &data)) != RT_ERR_OK) + return retVal; + + data &= ~0xE000; + data |= (mode << 13); + if ((retVal = rtl8367c_setAsicPHYReg(rtk_switch_port_L2P_get(port), 9, data)) != RT_ERR_OK) + return retVal; + + if (PHY_TEST_MODE_4 == mode) + { + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if( (regData == 0x0276) || (regData == 0x0597) ) + { + if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xbcc2, 0xF4F4)) != RT_ERR_OK) + return retVal; + } + + if( (regData == 0x6367) ) + { + if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa436, 0x80c1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPHYOCPReg(rtk_switch_port_L2P_get(port), 0xa438, 0xfe00)) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + +void rtk_hal_set_phy_test_mode(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + + ret = rtk_port_phyTestMode_set(data->port, data->mode); + if (ret != RT_ERR_OK) + printk("rtk_port_phyTestMode_set failed\n"); + else + printk("set port%d in test mode %d.\n", data->port, data->mode); +} + +void rtk_hal_set_port_trunk(struct ra_switch_ioctl_data *data) +{ + + rtk_api_ret_t ret; + rtk_portmask_t member; + int i; + + RTK_PORTMASK_CLEAR(member); + for (i = 0; i < 4; i++) { + if (data->port_map & (1 << i)) + RTK_PORTMASK_PORT_SET(member, i); + } + + ret = rtk_trunk_port_set(TRUNK_GROUP0, &member); + if (ret != RT_ERR_OK) + printk("rtk_trunk_port_set failed\n"); + + ret = rtk_trunk_distributionAlgorithm_set(RTK_WHOLE_SYSTEM, 0x7F); + if (ret != RT_ERR_OK) + printk("rtk_trunk_distributionAlgorithm_set failed\n"); +} + +void rtk_hal_vlan_tag(struct ra_switch_ioctl_data *data) +{ + rtk_api_ret_t ret; + rtk_vlan_cfg_t vlan; + + ret = rtk_vlan_get(data->vid, &vlan); + if (ret != RT_ERR_OK) + printk("rtk_vlan_get failed\n"); + else { + if (data->on_off == 0) + RTK_PORTMASK_PORT_SET(vlan.untag, data->port); + else + RTK_PORTMASK_PORT_CLEAR(vlan.untag, data->port); + + ret = rtk_vlan_set(data->vid, &vlan); + if (ret != RT_ERR_OK) + printk("rtk_vlan_set failed\n"); + } +} + +void rtk_hal_vlan_mode(struct ra_switch_ioctl_data *data) +{ + rtk_vlan_cfg_t vlan1, vlan2; + rtk_api_ret_t ret; + + ret = rtk_vlan_get(1, &vlan1); + if (ret != RT_ERR_OK) + printk("rtk_vlan_get failed\n"); + + ret = rtk_vlan_get(2, &vlan2); + if (ret != RT_ERR_OK) + printk("rtk_vlan_get failed\n"); + + if (data->mode == 0) { //ivl + vlan1.ivl_en = 1; + vlan1.fid_msti = 0; + rtk_vlan_set(1, &vlan1); + vlan2.ivl_en = 1; + vlan2.fid_msti = 0; + rtk_vlan_set(2, &vlan2); + } else if(data->mode == 1) {//svl + vlan1.ivl_en = 0; + vlan1.fid_msti = 0; + rtk_vlan_set(1, &vlan1); + vlan2.ivl_en = 0; + vlan2.fid_msti = 1; + rtk_vlan_set(2, &vlan2); + } else + printk("mode not supported\n"); +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtk_switch.c b/drivers/net/phy/rtk/rtl8367c/rtk_switch.c new file mode 100644 index 000000000000..afa3385f3098 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtk_switch.c @@ -0,0 +1,1794 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76336 $ + * $Date: 2017-03-09 10:41:21 +0800 (週四, 09 三月 2017) $ + * + * Purpose : RTK switch high-level API + * Feature : Here is a list of all functions and variables in this module. + * + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(FORCE_PROBE_RTL8367C) +static init_state_t init_state = INIT_COMPLETED; +#elif defined(FORCE_PROBE_RTL8370B) +static init_state_t init_state = INIT_COMPLETED; +#elif defined(FORCE_PROBE_RTL8364B) +static init_state_t init_state = INIT_COMPLETED; +#elif defined(FORCE_PROBE_RTL8363SC_VB) +static init_state_t init_state = INIT_COMPLETED; +#else +static init_state_t init_state = INIT_NOT_COMPLETED; +#endif + +#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8367C)) +static rtk_switch_halCtrl_t rtl8367c_hal_Ctrl = +{ + /* Switch Chip */ + CHIP_RTL8367C, + + /* Logical to Physical */ + {0, 1, 2, 3, 4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + + /* Physical to Logical */ + {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, + + /* Port Type */ + {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, + + /* PTP port */ + {1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + + /* Valid port mask */ + ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid UTP port mask */ + ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) ), + + /* Valid EXT port mask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid CPU port mask */ + 0x00, + + /* Minimum physical port number */ + 0, + + /* Maxmum physical port number */ + 7, + + /* Physical port mask */ + 0xDF, + + /* Combo Logical port ID */ + 4, + + /* HSG Logical port ID */ + EXT_PORT0, + + /* SGMII Logical portmask */ + (0x1 << EXT_PORT0), + + /* Max Meter ID */ + 31, + + /* MAX LUT Address Number */ + 2112, + + /* Trunk Group Mask */ + 0x03 +}; +#endif + +#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8370B)) +static rtk_switch_halCtrl_t rtl8370b_hal_Ctrl = +{ + /* Switch Chip */ + CHIP_RTL8370B, + + /* Logical to Physical */ + {0, 1, 2, 3, 4, 5, 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 8, 9, 10, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + + /* Physical to Logical */ + {UTP_PORT0, UTP_PORT1, UTP_PORT2, UTP_PORT3, UTP_PORT4, UTP_PORT5, UTP_PORT6, UTP_PORT7, + EXT_PORT0, EXT_PORT1, EXT_PORT2, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, + + /* Port Type */ + {UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, UTP_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + EXT_PORT, EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, + + /* PTP port */ + {1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + + /* Valid port mask */ + ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ), + + /* Valid UTP port mask */ + ( (0x1 << UTP_PORT0) | (0x1 << UTP_PORT1) | (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << UTP_PORT4) | (0x1 << UTP_PORT5) | (0x1 << UTP_PORT6) | (0x1 << UTP_PORT7) ), + + /* Valid EXT port mask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) | (0x1 << EXT_PORT2) ), + + /* Valid CPU port mask */ + (0x1 << EXT_PORT2), + + /* Minimum physical port number */ + 0, + + /* Maximum physical port number */ + 10, + + /* Physical port mask */ + 0x7FF, + + /* Combo Logical port ID */ + 7, + + /* HSG Logical port ID */ + EXT_PORT1, + + /* SGMII Logical portmask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Max Meter ID */ + 63, + + /* MAX LUT Address Number 4096 + 64*/ + 4160, + + /* Trunk Group Mask */ + 0x07 +}; +#endif + +#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8364B)) +static rtk_switch_halCtrl_t rtl8364b_hal_Ctrl = +{ + /* Switch Chip */ + CHIP_RTL8364B, + + /* Logical to Physical */ + {0xFF, 1, 0xFF, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + + /* Physical to Logical */ + {UNDEFINE_PORT, UTP_PORT1, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, + + /* Port Type */ + {UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, + + /* PTP port */ + {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + + /* Valid port mask */ + ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid UTP port mask */ + ( (0x1 << UTP_PORT1) | (0x1 << UTP_PORT3) ), + + /* Valid EXT port mask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid CPU port mask */ + 0x00, + + /* Minimum physical port number */ + 0, + + /* Maximum physical port number */ + 7, + + /* Physical port mask */ + 0xCA, + + /* Combo Logical port ID */ + 4, + + /* HSG Logical port ID */ + EXT_PORT0, + + /* SGMII Logical portmask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Max Meter ID */ + 32, + + /* MAX LUT Address Number */ + 2112, + + /* Trunk Group Mask */ + 0x01 +}; +#endif + +#if ((!defined(FORCE_PROBE_RTL8367C) && !defined(FORCE_PROBE_RTL8370B) && !defined(FORCE_PROBE_RTL8364B) && !defined(FORCE_PROBE_RTL8363SC_VB)) || defined(FORCE_PROBE_RTL8363SC_VB)) +static rtk_switch_halCtrl_t rtl8363sc_vb_hal_Ctrl = +{ + /* Switch Chip */ + CHIP_RTL8363SC_VB, + + /* Logical to Physical */ + {0xFF, 0xFF, 1, 3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 6, 7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + + /* Physical to Logical */ + {UNDEFINE_PORT, UTP_PORT2, UNDEFINE_PORT, UTP_PORT3, UNDEFINE_PORT, UNDEFINE_PORT, EXT_PORT0, EXT_PORT1, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, + UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT, UNDEFINE_PORT}, + + /* Port Type */ + {UNKNOWN_PORT, UNKNOWN_PORT, UTP_PORT, UTP_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + EXT_PORT, EXT_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, + UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT, UNKNOWN_PORT}, + + /* PTP port */ + {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }, + + /* Valid port mask */ + ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) | (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid UTP port mask */ + ( (0x1 << UTP_PORT2) | (0x1 << UTP_PORT3) ), + + /* Valid EXT port mask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Valid CPU port mask */ + 0x00, + + /* Minimum physical port number */ + 0, + + /* Maximum physical port number */ + 7, + + /* Physical port mask */ + 0xCA, + + /* Combo Logical port ID */ + 4, + + /* HSG Logical port ID */ + EXT_PORT0, + + /* SGMII Logical portmask */ + ( (0x1 << EXT_PORT0) | (0x1 << EXT_PORT1) ), + + /* Max Meter ID */ + 32, + + /* MAX LUT Address Number */ + 2112, + + /* Trunk Group Mask */ + 0x01 +}; +#endif + +#if defined(FORCE_PROBE_RTL8367C) +static rtk_switch_halCtrl_t *halCtrl = &rtl8367c_hal_Ctrl; +#elif defined(FORCE_PROBE_RTL8370B) +static rtk_switch_halCtrl_t *halCtrl = &rtl8370b_hal_Ctrl; +#elif defined(FORCE_PROBE_RTL8364B) +static rtk_switch_halCtrl_t *halCtrl = &rtl8364b_hal_Ctrl; +#elif defined(FORCE_PROBE_RTL8363SC_VB) +static rtk_switch_halCtrl_t *halCtrl = &rtl8363sc_vb_hal_Ctrl; +#else +static rtk_switch_halCtrl_t *halCtrl = NULL; +#endif + +static rtk_uint32 PatchChipData[210][2] = +{ + {0xa436, 0x8028}, {0xa438, 0x6800}, {0xb82e, 0x0001}, {0xa436, 0xb820}, {0xa438, 0x0090}, {0xa436, 0xa012}, {0xa438, 0x0000}, {0xa436, 0xa014}, {0xa438, 0x2c04}, {0xa438, 0x2c6c}, + {0xa438, 0x2c75}, {0xa438, 0x2c77}, {0xa438, 0x1414}, {0xa438, 0x1579}, {0xa438, 0x1536}, {0xa438, 0xc432}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e}, + {0xa438, 0x614c}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x318c}, {0xa438, 0x42d6}, {0xa438, 0xd702}, {0xa438, 0x31ef}, {0xa438, 0x42d6}, {0xa438, 0x629c}, {0xa438, 0x2c04}, + {0xa438, 0x653c}, {0xa438, 0x422a}, {0xa438, 0x5d83}, {0xa438, 0xd06a}, {0xa438, 0xd1b0}, {0xa438, 0x1536}, {0xa438, 0xc43a}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, + {0xa438, 0x003e}, {0xa438, 0x314a}, {0xa438, 0x42fe}, {0xa438, 0x337b}, {0xa438, 0x02d6}, {0xa438, 0x3063}, {0xa438, 0x0c1b}, {0xa438, 0x22fe}, {0xa438, 0xc435}, {0xa438, 0xd0be}, + {0xa438, 0xd1f7}, {0xa438, 0xe0f0}, {0xa438, 0x1a40}, {0xa438, 0xa320}, {0xa438, 0xd702}, {0xa438, 0x154a}, {0xa438, 0xc434}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, + {0xa438, 0x003e}, {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd705}, {0xa438, 0x619f}, {0xa438, 0xd702}, {0xa438, 0x414f}, {0xa438, 0x2c2e}, {0xa438, 0x610a}, {0xa438, 0xd705}, + {0xa438, 0x5e1f}, {0xa438, 0xc43f}, {0xa438, 0xc88b}, {0xa438, 0xd702}, {0xa438, 0x7fe0}, {0xa438, 0x22f3}, {0xa438, 0xd0a0}, {0xa438, 0xd1b2}, {0xa438, 0xd0c3}, {0xa438, 0xd1c3}, + {0xa438, 0x8d01}, {0xa438, 0x1536}, {0xa438, 0xc438}, {0xa438, 0xe0f0}, {0xa438, 0x1a80}, {0xa438, 0xd706}, {0xa438, 0x60c0}, {0xa438, 0xd710}, {0xa438, 0x409e}, {0xa438, 0xa804}, + {0xa438, 0xad01}, {0xa438, 0x8804}, {0xa438, 0xd702}, {0xa438, 0x32c0}, {0xa438, 0x42d6}, {0xa438, 0x32b5}, {0xa438, 0x003e}, {0xa438, 0x405b}, {0xa438, 0x1576}, {0xa438, 0x7c9c}, + {0xa438, 0x60ec}, {0xa438, 0x1569}, {0xa438, 0xd702}, {0xa438, 0x5d43}, {0xa438, 0x31ef}, {0xa438, 0x02fe}, {0xa438, 0x22d6}, {0xa438, 0x590a}, {0xa438, 0xd706}, {0xa438, 0x5c80}, + {0xa438, 0xd702}, {0xa438, 0x5c44}, {0xa438, 0x3063}, {0xa438, 0x02d6}, {0xa438, 0x5be2}, {0xa438, 0x22fb}, {0xa438, 0xa240}, {0xa438, 0xa104}, {0xa438, 0x8c03}, {0xa438, 0x8178}, + {0xa438, 0xd701}, {0xa438, 0x31ad}, {0xa438, 0x4917}, {0xa438, 0x8102}, {0xa438, 0x2917}, {0xa438, 0xc302}, {0xa438, 0x268a}, {0xa436, 0xA01A}, {0xa438, 0x0000}, {0xa436, 0xA006}, + {0xa438, 0x0fff}, {0xa436, 0xA004}, {0xa438, 0x0689}, {0xa436, 0xA002}, {0xa438, 0x0911}, {0xa436, 0xA000}, {0xa438, 0x7302}, {0xa436, 0xB820}, {0xa438, 0x0010}, {0xa436, 0x8412}, + {0xa438, 0xaf84}, {0xa438, 0x1eaf}, {0xa438, 0x8427}, {0xa438, 0xaf84}, {0xa438, 0x27af}, {0xa438, 0x8427}, {0xa438, 0x0251}, {0xa438, 0x6802}, {0xa438, 0x8427}, {0xa438, 0xaf04}, + {0xa438, 0x0af8}, {0xa438, 0xf9bf}, {0xa438, 0x5581}, {0xa438, 0x0255}, {0xa438, 0x27ef}, {0xa438, 0x310d}, {0xa438, 0x345b}, {0xa438, 0x0fa3}, {0xa438, 0x032a}, {0xa438, 0xe087}, + {0xa438, 0xffac}, {0xa438, 0x2040}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x5527}, {0xa438, 0xef31}, {0xa438, 0xef20}, {0xa438, 0xe787}, {0xa438, 0xfee6}, {0xa438, 0x87fd}, + {0xa438, 0xd488}, {0xa438, 0x88bf}, {0xa438, 0x5674}, {0xa438, 0x0254}, {0xa438, 0xe3e0}, {0xa438, 0x87ff}, {0xa438, 0xf720}, {0xa438, 0xe487}, {0xa438, 0xffaf}, {0xa438, 0x847e}, + {0xa438, 0xe087}, {0xa438, 0xffad}, {0xa438, 0x2016}, {0xa438, 0xe387}, {0xa438, 0xfee2}, {0xa438, 0x87fd}, {0xa438, 0xef45}, {0xa438, 0xbf56}, {0xa438, 0x7402}, {0xa438, 0x54e3}, + {0xa438, 0xe087}, {0xa438, 0xfff6}, {0xa438, 0x20e4}, {0xa438, 0x87ff}, {0xa438, 0xfdfc}, {0xa438, 0x0400}, {0xa436, 0xb818}, {0xa438, 0x0407}, {0xa436, 0xb81a}, {0xa438, 0xfffd}, + {0xa436, 0xb81c}, {0xa438, 0xfffd}, {0xa436, 0xb81e}, {0xa438, 0xfffd}, {0xa436, 0xb832}, {0xa438, 0x0001}, {0xb820, 0x0000}, {0xb82e, 0x0000}, {0xa436, 0x8028}, {0xa438, 0x0000} +}; + +static rtk_api_ret_t _rtk_switch_init_8367c(void) +{ + rtk_port_t port; + rtk_uint32 retVal; + rtk_uint32 regData; + rtk_uint32 regValue; + + if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK) + return retVal; + + RTK_SCAN_ALL_LOG_PORT(port) + { + if(rtk_switch_isUtpPort(port) == RT_ERR_OK) + { + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_100M_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_GIGA_500M_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_TX_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_EEECFG + (0x20 * port), RTL8367C_PORT0_EEECFG_EEE_RX_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA428, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= ~(0x0200); + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA428, regData)) != RT_ERR_OK) + return retVal; + + if((regValue & 0x00F0) == 0x00A0) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA5D0, ®Data)) != RT_ERR_OK) + return retVal; + + regData |= 0x0006; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA5D0, regData)) != RT_ERR_OK) + return retVal; + } + } + } + + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_UTP_FIB_DET, 0x15BB)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1303, 0x06D6)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1304, 0x0700)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13E2, 0x003F)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13F9, 0x0090)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x121e, 0x03CA)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1233, 0x0352)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1237, 0x00a0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x123a, 0x0030)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1239, 0x0084)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x0301, 0x1000)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1349, 0x001F)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x18e0, 0, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x122b, 14, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1305, 0xC000, 3)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +static rtk_api_ret_t _rtk_switch_init_8370b(void) +{ + ret_t retVal; + rtk_uint32 regData, tmp = 0; + rtk_uint32 i, prf, counter; + rtk_uint32 long_link[8] = {0x0210, 0x03e8, 0x0218, 0x03f0, 0x0220, 0x03f8, 0x0208, 0x03e0 }; + + if((retVal = rtl8367c_setAsicRegBits(0x1205, 0x0300, 3)) != RT_ERR_OK) + return retVal; + + + for(i=0; i<8; i++) + { + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa420, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData & 0x7 ; + if(tmp == 0x3) + { + prf = 1; + if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6fa9)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xa9)) != RT_ERR_OK) + return retVal; + for(counter = 0; counter < 10000; counter++); //delay + + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData | 0x10; + if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK) + return retVal; + for(counter = 0; counter < 10000; counter++); //delay + counter = 0; + do{ + counter = counter + 1; + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData & 0x40; + if(tmp != 0) + break; + } while (counter < 20); //Wait for patch ready = 1... + } + } + if ((retVal = rtl8367c_getAsicReg(0x1d01, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData; + tmp = tmp | 0x3BE0; /*Broadcast port enable*/ + tmp = tmp & 0xFFE0; /*Phy_id = 0 */ + if((retVal = rtl8367c_setAsicReg(0x1d01, tmp)) != RT_ERR_OK) + return retVal; + + for(i=0;i < 210; i++) + { + if((retVal = rtl8367c_setAsicPHYOCPReg(0, PatchChipData[i][0], PatchChipData[i][1])) != RT_ERR_OK) + return retVal; + } + + if((retVal = rtl8367c_setAsicReg(0x1d01, regData)) != RT_ERR_OK) + return retVal; + + for(i=0; i < 8; i++) + { + if((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa4b4, long_link[i])) != RT_ERR_OK) + return retVal; + } + + if (prf == 0x1) + { + for(i=0; i<8; i++) + { + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb820, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData & 0xFFEF; + if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb820, tmp)) != RT_ERR_OK) + return retVal; + + for(counter = 0; counter < 10000; counter++); //delay + + counter = 0; + do{ + counter = counter + 1; + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xb800, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData & 0x40; + if( tmp == 0 ) + break; + } while (counter < 20); //Wait for patch ready = 1... + if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb83e, 0x6f48)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xb840, 0xfa)) != RT_ERR_OK) + return retVal; + } + } + + /*Check phy link status*/ + for(i=0; i<8; i++) + { + if ((retVal = rtl8367c_getAsicPHYOCPReg(i, 0xa400, ®Data)) != RT_ERR_OK) + return retVal; + tmp = regData & 0x800; + if(tmp == 0x0) + { + tmp = regData | 0x200; + if ((retVal = rtl8367c_setAsicPHYOCPReg(i, 0xa400, tmp)) != RT_ERR_OK) + return retVal; + } + } + + for(counter = 0; counter < 10000; counter++); //delay + + return RT_ERR_OK; +} + +static rtk_api_ret_t _rtk_switch_init_8364b(void) +{ + ret_t retVal; + rtk_uint32 regData; + + /*enable EEE, include mac & phy*/ + + if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK) + return retVal; + + /*PAD para*/ + + /*EXT1 PAD Para*/ + if ((retVal = rtl8367c_getAsicReg(0x1303, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFFFFFFE; + regData |= 0x250; + if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) + return retVal; + + /*EXT2 PAD Para*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) + return retVal; + + + /*SDS PATCH*/ + /*SP_CFG_EN_LINK_FIB1G*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Data)) != RT_ERR_OK) + return retVal; + regData |= 0x4; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK) + return retVal; + + /*FIB100 Down-speed*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, ®Data)) != RT_ERR_OK) + return retVal; + regData |= 0x20; + if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +static rtk_api_ret_t _rtk_switch_init_8363sc_vb(void) +{ + + ret_t retVal; + rtk_uint32 regData; + + /*enable EEE, include mac & phy*/ + + if ((retVal = rtl8367c_setAsicRegBits(0x38, 0x300, 3)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x78, 0x300, 3)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0xd8, 0x300, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0xf8, 0x300, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPHYOCPReg(1, 0xa5d0, 6)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicPHYOCPReg(3, 0xa5d0, 6)) != RT_ERR_OK) + return retVal; + + /*PAD para*/ + + /*EXT1 PAD Para*/ + if ((retVal = rtl8367c_getAsicReg(0x1303, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFFFFFFE; + regData |= 0x250; + if((retVal = rtl8367c_setAsicReg(0x1303, regData)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x700, 7)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) + return retVal; + + /*EXT2 PAD Para*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13E2, 0x1ff, 0x26)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) + return retVal; + + + /*SDS PATCH*/ + /*SP_CFG_EN_LINK_FIB1G*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Data)) != RT_ERR_OK) + return retVal; + regData |= 0x4; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, regData)) != RT_ERR_OK) + return retVal; + + /*FIB100 Down-speed*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 1, 0, ®Data)) != RT_ERR_OK) + return retVal; + regData |= 0x20; + if((retVal = rtl8367c_setAsicSdsReg(0,1,0, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_probe + * Description: + * Probe switch + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Switch probed + * RT_ERR_FAILED - Switch Unprobed. + * Note: + * + */ +rtk_api_ret_t rtk_switch_probe(switch_chip_t *pSwitchChip) +{ +#if defined(FORCE_PROBE_RTL8367C) + + *pSwitchChip = CHIP_RTL8367C; + halCtrl = &rtl8367c_hal_Ctrl; + +#elif defined(FORCE_PROBE_RTL8370B) + + *pSwitchChip = CHIP_RTL8370B; + halCtrl = &rtl8370b_hal_Ctrl; + +#elif defined(FORCE_PROBE_RTL8364B) + + *pSwitchChip = CHIP_RTL8364B; + halCtrl = &rtl8364b_hal_Ctrl; + +#elif defined(FORCE_PROBE_RTL8363SC_VB) + + *pSwitchChip = CHIP_RTL8363SC_VB; + halCtrl = &rtl8363sc_vb_hal_Ctrl; + +#else + rtk_uint32 retVal; + rtk_uint32 data, regValue; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (data) + { + case 0x0276: + case 0x0597: + case 0x6367: + *pSwitchChip = CHIP_RTL8367C; + halCtrl = &rtl8367c_hal_Ctrl; + break; + case 0x0652: + case 0x6368: + *pSwitchChip = CHIP_RTL8370B; + halCtrl = &rtl8370b_hal_Ctrl; + break; + case 0x0801: + case 0x6511: + if( (regValue & 0x00F0) == 0x0080) + { + *pSwitchChip = CHIP_RTL8363SC_VB; + halCtrl = &rtl8363sc_vb_hal_Ctrl; + } + else + { + *pSwitchChip = CHIP_RTL8364B; + halCtrl = &rtl8364b_hal_Ctrl; + } + break; + default: + return RT_ERR_FAILED; + } +#endif + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_initialState_set + * Description: + * Set initial status + * Input: + * state - Initial state; + * Output: + * None + * Return: + * RT_ERR_OK - Initialized + * RT_ERR_FAILED - Uninitialized + * Note: + * + */ +rtk_api_ret_t rtk_switch_initialState_set(init_state_t state) +{ + if(state >= INIT_STATE_END) + return RT_ERR_FAILED; + + init_state = state; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_initialState_get + * Description: + * Get initial status + * Input: + * None + * Output: + * None + * Return: + * INIT_COMPLETED - Initialized + * INIT_NOT_COMPLETED - Uninitialized + * Note: + * + */ +init_state_t rtk_switch_initialState_get(void) +{ + return init_state; +} + +/* Function Name: + * rtk_switch_logicalPortCheck + * Description: + * Check logical port ID. + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is correct + * RT_ERR_FAILED - Port ID is not correct + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_logicalPortCheck(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(halCtrl->l2p_port[logicalPort] == 0xFF) + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_isUtpPort + * Description: + * Check is logical port a UTP port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a UTP port + * RT_ERR_FAILED - Port ID is not a UTP port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isUtpPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(halCtrl->log_port_type[logicalPort] == UTP_PORT) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_isExtPort + * Description: + * Check is logical port a Extension port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a EXT port + * RT_ERR_FAILED - Port ID is not a EXT port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isExtPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(halCtrl->log_port_type[logicalPort] == EXT_PORT) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + + +/* Function Name: + * rtk_switch_isHsgPort + * Description: + * Check is logical port a HSG port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a HSG port + * RT_ERR_FAILED - Port ID is not a HSG port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isHsgPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(logicalPort == halCtrl->hsg_logical_port) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_isSgmiiPort + * Description: + * Check is logical port a SGMII port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a SGMII port + * RT_ERR_FAILED - Port ID is not a SGMII port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isSgmiiPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if( ((0x01 << logicalPort) & halCtrl->sg_logical_portmask) != 0) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_isCPUPort + * Description: + * Check is logical port a CPU port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a CPU port + * RT_ERR_FAILED - Port ID is not a CPU port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isCPUPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if( ((0x01 << logicalPort) & halCtrl->valid_cpu_portmask) != 0) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_isComboPort + * Description: + * Check is logical port a Combo port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a combo port + * RT_ERR_FAILED - Port ID is not a combo port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isComboPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(halCtrl->combo_logical_port == logicalPort) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_ComboPort_get + * Description: + * Get Combo port ID + * Input: + * None + * Output: + * None + * Return: + * Port ID of combo port + * Note: + * + */ +rtk_uint32 rtk_switch_ComboPort_get(void) +{ + return halCtrl->combo_logical_port; +} + +/* Function Name: + * rtk_switch_isPtpPort + * Description: + * Check is logical port a PTP port + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * RT_ERR_OK - Port ID is a PTP port + * RT_ERR_FAILED - Port ID is not a PTP port + * RT_ERR_NOT_INIT - Not Initialize + * Note: + * + */ +rtk_api_ret_t rtk_switch_isPtpPort(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return RT_ERR_FAILED; + + if(halCtrl->ptp_port[logicalPort] == 1) + return RT_ERR_OK; + else + return RT_ERR_FAILED; +} + +/* Function Name: + * rtk_switch_port_L2P_get + * Description: + * Get physical port ID + * Input: + * logicalPort - logical port ID + * Output: + * None + * Return: + * Physical port ID + * Note: + * + */ +rtk_uint32 rtk_switch_port_L2P_get(rtk_port_t logicalPort) +{ + if(init_state != INIT_COMPLETED) + return UNDEFINE_PHY_PORT; + + if(logicalPort >= RTK_SWITCH_PORT_NUM) + return UNDEFINE_PHY_PORT; + + return (halCtrl->l2p_port[logicalPort]); +} + +/* Function Name: + * rtk_switch_port_P2L_get + * Description: + * Get logical port ID + * Input: + * physicalPort - physical port ID + * Output: + * None + * Return: + * logical port ID + * Note: + * + */ +rtk_port_t rtk_switch_port_P2L_get(rtk_uint32 physicalPort) +{ + if(init_state != INIT_COMPLETED) + return UNDEFINE_PORT; + + if(physicalPort >= RTK_SWITCH_PORT_NUM) + return UNDEFINE_PORT; + + return (halCtrl->p2l_port[physicalPort]); +} + +/* Function Name: + * rtk_switch_isPortMaskValid + * Description: + * Check portmask is valid or not + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - port mask is valid + * RT_ERR_FAILED - port mask is not valid + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_switch_isPortMaskValid(rtk_portmask_t *pPmask) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(NULL == pPmask) + return RT_ERR_NULL_POINTER; + + if( (pPmask->bits[0] | halCtrl->valid_portmask) != halCtrl->valid_portmask ) + return RT_ERR_FAILED; + else + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_isPortMaskUtp + * Description: + * Check all ports in portmask are only UTP port + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - Only UTP port in port mask + * RT_ERR_FAILED - Not only UTP port in port mask + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_switch_isPortMaskUtp(rtk_portmask_t *pPmask) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(NULL == pPmask) + return RT_ERR_NULL_POINTER; + + if( (pPmask->bits[0] | halCtrl->valid_utp_portmask) != halCtrl->valid_utp_portmask ) + return RT_ERR_FAILED; + else + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_isPortMaskExt + * Description: + * Check all ports in portmask are only EXT port + * Input: + * pPmask - logical port mask + * Output: + * None + * Return: + * RT_ERR_OK - Only EXT port in port mask + * RT_ERR_FAILED - Not only EXT port in port mask + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_switch_isPortMaskExt(rtk_portmask_t *pPmask) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(NULL == pPmask) + return RT_ERR_NULL_POINTER; + + if( (pPmask->bits[0] | halCtrl->valid_ext_portmask) != halCtrl->valid_ext_portmask ) + return RT_ERR_FAILED; + else + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_portmask_L2P_get + * Description: + * Get physical portmask from logical portmask + * Input: + * pLogicalPmask - logical port mask + * Output: + * pPhysicalPortmask - physical port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_PORT_MASK - Error port mask + * Note: + * + */ +rtk_api_ret_t rtk_switch_portmask_L2P_get(rtk_portmask_t *pLogicalPmask, rtk_uint32 *pPhysicalPortmask) +{ + rtk_uint32 log_port, phy_port; + + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(NULL == pLogicalPmask) + return RT_ERR_NULL_POINTER; + + if(NULL == pPhysicalPortmask) + return RT_ERR_NULL_POINTER; + + if(rtk_switch_isPortMaskValid(pLogicalPmask) != RT_ERR_OK) + return RT_ERR_PORT_MASK; + + /* reset physical port mask */ + *pPhysicalPortmask = 0; + + RTK_PORTMASK_SCAN((*pLogicalPmask), log_port) + { + phy_port = rtk_switch_port_L2P_get((rtk_port_t)log_port); + *pPhysicalPortmask |= (0x0001 << phy_port); + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_portmask_P2L_get + * Description: + * Get logical portmask from physical portmask + * Input: + * physicalPortmask - physical port mask + * Output: + * pLogicalPmask - logical port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * RT_ERR_PORT_MASK - Error port mask + * Note: + * + */ +rtk_api_ret_t rtk_switch_portmask_P2L_get(rtk_uint32 physicalPortmask, rtk_portmask_t *pLogicalPmask) +{ + rtk_uint32 log_port, phy_port; + + if(init_state != INIT_COMPLETED) + return RT_ERR_NOT_INIT; + + if(NULL == pLogicalPmask) + return RT_ERR_NULL_POINTER; + + RTK_PORTMASK_CLEAR(*pLogicalPmask); + + for(phy_port = halCtrl->min_phy_port; phy_port <= halCtrl->max_phy_port; phy_port++) + { + if(physicalPortmask & (0x0001 << phy_port)) + { + log_port = rtk_switch_port_P2L_get(phy_port); + if(log_port != UNDEFINE_PORT) + { + RTK_PORTMASK_PORT_SET(*pLogicalPmask, log_port); + } + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_phyPortMask_get + * Description: + * Get physical portmask + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Physical port mask + * Note: + * + */ +rtk_uint32 rtk_switch_phyPortMask_get(void) +{ + if(init_state != INIT_COMPLETED) + return 0x00; /* No port in portmask */ + + return (halCtrl->phy_portmask); +} + +/* Function Name: + * rtk_switch_logPortMask_get + * Description: + * Get Logical portmask + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_NOT_INIT - Not Initialize + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_switch_logPortMask_get(rtk_portmask_t *pPortmask) +{ + if(init_state != INIT_COMPLETED) + return RT_ERR_FAILED; + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + pPortmask->bits[0] = halCtrl->valid_portmask; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_init + * Description: + * Set chip to default configuration environment + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can set chip registers to default configuration for different release chip model. + */ +rtk_api_ret_t rtk_switch_init(void) +{ + rtk_uint32 retVal; + rtl8367c_rma_t rmaCfg; + switch_chip_t switchChip; + + /* probe switch */ + if((retVal = rtk_switch_probe(&switchChip)) != RT_ERR_OK) + return retVal; + + /* Set initial state */ + + if((retVal = rtk_switch_initialState_set(INIT_COMPLETED)) != RT_ERR_OK) + return retVal; + + /* Initial */ + switch(switchChip) + { + case CHIP_RTL8367C: + if((retVal = _rtk_switch_init_8367c()) != RT_ERR_OK) + return retVal; + break; + case CHIP_RTL8370B: + if((retVal = _rtk_switch_init_8370b()) != RT_ERR_OK) + return retVal; + break; + case CHIP_RTL8364B: + if((retVal = _rtk_switch_init_8364b()) != RT_ERR_OK) + return retVal; + break; + case CHIP_RTL8363SC_VB: + if((retVal = _rtk_switch_init_8363sc_vb()) != RT_ERR_OK) + return retVal; + break; + default: + return RT_ERR_CHIP_NOT_FOUND; + } + + /* Set Old max packet length to 16K */ + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LENGTH_LIMINT_IPG, RTL8367C_MAX_LENTH_CTRL_MASK, 3)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX, RTL8367C_MAX_LEN_RX_TX_MASK, 3)) != RT_ERR_OK) + return retVal; + + /* ACL Mode */ + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_ACCESS_MODE, RTL8367C_ACL_ACCESS_MODE_MASK, 1)) != RT_ERR_OK) + return retVal; + + /* Max rate */ + if((retVal = rtk_rate_igrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, DISABLED, ENABLED)) != RT_ERR_OK) + return retVal; + + if((retVal = rtk_rate_egrBandwidthCtrlRate_set(halCtrl->hsg_logical_port, RTL8367C_QOS_RATE_INPUT_MAX_HSG, ENABLED)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x03fa, 0x0007)) != RT_ERR_OK) + return retVal; + + /* Change unknown DA to per port setting */ + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_UNICAST_DA_BEHAVE_MASK, 3)) != RT_ERR_OK) + return retVal; + + /* LUT lookup OP = 1 */ + if ((retVal = rtl8367c_setAsicLutIpLookupMethod(1))!=RT_ERR_OK) + return retVal; + + /* Set RMA */ + rmaCfg.portiso_leaky = 0; + rmaCfg.vlan_leaky = 0; + rmaCfg.keep_format = 0; + rmaCfg.trap_priority = 0; + rmaCfg.discard_storm_filter = 0; + rmaCfg.operation = 0; + if ((retVal = rtl8367c_setAsicRma(2, &rmaCfg))!=RT_ERR_OK) + return retVal; + + /* Enable TX Mirror isolation leaky */ + if ((retVal = rtl8367c_setAsicPortMirrorIsolationTxLeaky(ENABLED)) != RT_ERR_OK) + return retVal; + + /* INT EN */ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IO_MISC_FUNC, RTL8367C_INT_EN_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_portMaxPktLen_set + * Description: + * Set Max packet length + * Input: + * port - Port ID + * speed - Speed + * cfgId - Configuration ID + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +rtk_api_ret_t rtk_switch_portMaxPktLen_set(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 cfgId) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(speed >= MAXPKTLEN_LINK_SPEED_END) + return RT_ERR_INPUT; + + if(cfgId > MAXPKTLEN_CFG_ID_MAX) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_setAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, cfgId)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_portMaxPktLen_get + * Description: + * Get Max packet length + * Input: + * port - Port ID + * speed - Speed + * Output: + * pCfgId - Configuration ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +rtk_api_ret_t rtk_switch_portMaxPktLen_get(rtk_port_t port, rtk_switch_maxPktLen_linkSpeed_t speed, rtk_uint32 *pCfgId) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(speed >= MAXPKTLEN_LINK_SPEED_END) + return RT_ERR_INPUT; + + if(NULL == pCfgId) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicMaxLength(rtk_switch_port_L2P_get(port), (rtk_uint32)speed, pCfgId)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_maxPktLenCfg_set + * Description: + * Set Max packet length configuration + * Input: + * cfgId - Configuration ID + * pktLen - Max packet length + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +rtk_api_ret_t rtk_switch_maxPktLenCfg_set(rtk_uint32 cfgId, rtk_uint32 pktLen) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(cfgId > MAXPKTLEN_CFG_ID_MAX) + return RT_ERR_INPUT; + + if(pktLen > RTK_SWITCH_MAX_PKTLEN) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_setAsicMaxLengthCfg(cfgId, pktLen)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_maxPktLenCfg_get + * Description: + * Get Max packet length configuration + * Input: + * cfgId - Configuration ID + * pPktLen - Max packet length + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + */ +rtk_api_ret_t rtk_switch_maxPktLenCfg_get(rtk_uint32 cfgId, rtk_uint32 *pPktLen) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(cfgId > MAXPKTLEN_CFG_ID_MAX) + return RT_ERR_INPUT; + + if(NULL == pPktLen) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicMaxLengthCfg(cfgId, pPktLen)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_greenEthernet_set + * Description: + * Set all Ports Green Ethernet state. + * Input: + * enable - Green Ethernet state. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * This API can set all Ports Green Ethernet state. + * The configuration is as following: + * - DISABLE + * - ENABLE + */ +rtk_api_ret_t rtk_switch_greenEthernet_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + RTK_SCAN_ALL_LOG_PORT(port) + { + if(rtk_switch_isUtpPort(port) == RT_ERR_OK) + { + if ((retVal = rtl8367c_setAsicPowerSaving(rtk_switch_port_L2P_get(port),enable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicGreenEthernet(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_greenEthernet_get + * Description: + * Get all Ports Green Ethernet state. + * Input: + * None + * Output: + * pEnable - Green Ethernet state. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API can get Green Ethernet state. + */ +rtk_api_ret_t rtk_switch_greenEthernet_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 port; + rtk_uint32 state; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + RTK_SCAN_ALL_LOG_PORT(port) + { + if(rtk_switch_isUtpPort(port) == RT_ERR_OK) + { + if ((retVal = rtl8367c_getAsicPowerSaving(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK) + return retVal; + + if(state == DISABLED) + { + *pEnable = DISABLED; + return RT_ERR_OK; + } + + if ((retVal = rtl8367c_getAsicGreenEthernet(rtk_switch_port_L2P_get(port), &state))!=RT_ERR_OK) + return retVal; + + if(state == DISABLED) + { + *pEnable = DISABLED; + return RT_ERR_OK; + } + } + } + + *pEnable = ENABLED; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_switch_maxLogicalPort_get + * Description: + * Get Max logical port ID + * Input: + * None + * Output: + * None + * Return: + * Max logical port + * Note: + * This API can get max logical port + */ +rtk_port_t rtk_switch_maxLogicalPort_get(void) +{ + rtk_port_t port, maxLogicalPort = 0; + + /* Check initialization state */ + if(rtk_switch_initialState_get() != INIT_COMPLETED) + { + return UNDEFINE_PORT; + } + + for(port = 0; port < RTK_SWITCH_PORT_NUM; port++) + { + if( (halCtrl->log_port_type[port] == UTP_PORT) || (halCtrl->log_port_type[port] == EXT_PORT) ) + maxLogicalPort = port; + } + + return maxLogicalPort; +} + +/* Function Name: + * rtk_switch_maxMeterId_get + * Description: + * Get Max Meter ID + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Max Meter ID + * Note: + * + */ +rtk_uint32 rtk_switch_maxMeterId_get(void) +{ + if(init_state != INIT_COMPLETED) + return 0x00; + + return (halCtrl->max_meter_id); +} + +/* Function Name: + * rtk_switch_maxLutAddrNumber_get + * Description: + * Get Max LUT Address number + * Input: + * None + * Output: + * None + * Return: + * 0x00 - Not Initialize + * Other value - Max LUT Address number + * Note: + * + */ +rtk_uint32 rtk_switch_maxLutAddrNumber_get(void) +{ + if(init_state != INIT_COMPLETED) + return 0x00; + + return (halCtrl->max_lut_addr_num); +} + +/* Function Name: + * rtk_switch_isValidTrunkGrpId + * Description: + * Check if trunk group is valid or not + * Input: + * grpId - Group ID + * Output: + * None + * Return: + * RT_ERR_OK - Trunk Group ID is valid + * RT_ERR_LA_TRUNK_ID - Trunk Group ID is not valid + * Note: + * + */ +rtk_uint32 rtk_switch_isValidTrunkGrpId(rtk_uint32 grpId) +{ + if(init_state != INIT_COMPLETED) + return 0x00; + + if( (halCtrl->trunk_group_mask & (0x01 << grpId) ) != 0) + return RT_ERR_OK; + else + return RT_ERR_LA_TRUNK_ID; + +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c new file mode 100644 index 000000000000..7858edcf530a --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : + * + */ + +#include + +#if defined(RTK_X86_ASICDRV) +#include +#else +#include +#endif + +/*for driver verify testing only*/ +#ifdef CONFIG_RTL8367C_ASICDRV_TEST +#define CLE_VIRTUAL_REG_SIZE 0x10000 +rtk_uint16 CleVirtualReg[CLE_VIRTUAL_REG_SIZE]; +#endif + +#if defined(CONFIG_RTL865X_CLE) || defined (RTK_X86_CLE) +rtk_uint32 cleDebuggingDisplay; +#endif + +#ifdef EMBEDDED_SUPPORT +extern void setReg(rtk_uint16, rtk_uint16); +extern rtk_uint16 getReg(rtk_uint16); +#endif + +/* Function Name: + * rtl8367c_setAsicRegBit + * Description: + * Set a bit value of a specified register + * Input: + * reg - register's address + * bit - bit location + * value - value to set. It can be value 0 or 1. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * Note: + * Set a bit of a specified register to 1 or 0. + */ +ret_t rtl8367c_setAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 value) +{ + +#if defined(RTK_X86_ASICDRV) + rtk_uint32 regData; + ret_t retVal; + + if(bit >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + + retVal = Access_Read(reg, 2, ®Data); + if(TRUE != retVal) + return RT_ERR_SMI; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + + if(value) + regData = regData | (1 << bit); + else + regData = regData & (~(1 << bit)); + + retVal = Access_Write(reg,2, regData); + if(TRUE != retVal) + return RT_ERR_SMI; + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); + + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + + if(bit >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + + else if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + if(value) + { + CleVirtualReg[reg] = CleVirtualReg[reg] | (1 << bit); + } + else + { + CleVirtualReg[reg] = CleVirtualReg[reg] & (~(1 << bit)); + } + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); + +#elif defined(EMBEDDED_SUPPORT) + rtk_uint16 tmp; + + if(reg > RTL8367C_REGDATAMAX || value > 1) + return RT_ERR_INPUT; + + tmp = getReg(reg); + tmp &= (1 << bitIdx); + tmp |= (value << bitIdx); + setReg(reg, tmp); + +#else + rtk_uint32 regData; + ret_t retVal; + + if(bit >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + + retVal = smi_read(reg, ®Data); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif + if(value) + regData = regData | (1 << bit); + else + regData = regData & (~(1 << bit)); + + retVal = smi_write(reg, regData); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif + +#endif + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicRegBit + * Description: + * Get a bit value of a specified register + * Input: + * reg - register's address + * bit - bit location + * value - value to get. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicRegBit(rtk_uint32 reg, rtk_uint32 bit, rtk_uint32 *pValue) +{ + +#if defined(RTK_X86_ASICDRV) + + rtk_uint32 regData; + ret_t retVal; + + if(bit >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + + retVal = Access_Read(reg, 2, ®Data); + if(TRUE != retVal) + return RT_ERR_SMI; + + *pValue = (regData & (0x1 << bit)) >> bit; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + + if(bit >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + + if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + *pValue = (CleVirtualReg[reg] & (0x1 << bit)) >> bit; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); + +#elif defined(EMBEDDED_SUPPORT) + rtk_uint16 tmp; + + if(reg > RTL8367C_REGDATAMAX ) + return RT_ERR_INPUT; + + tmp = getReg(reg); + tmp = tmp >> bitIdx; + tmp &= 1; + *value = tmp; +#else + rtk_uint32 regData; + ret_t retVal; + + retVal = smi_read(reg, ®Data); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif + + *pValue = (regData & (0x1 << bit)) >> bit; + +#endif + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicRegBits + * Description: + * Set bits value of a specified register + * Input: + * reg - register's address + * bits - bits mask for setting + * value - bits value for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * Note: + * Set bits of a specified register to value. Both bits and value are be treated as bit-mask + */ +ret_t rtl8367c_setAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 value) +{ + +#if defined(RTK_X86_ASICDRV) + + rtk_uint32 regData; + ret_t retVal; + rtk_uint32 bitsShift; + rtk_uint32 valueShifted; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + valueShifted = value << bitsShift; + if(valueShifted > RTL8367C_REGDATAMAX) + return RT_ERR_INPUT; + + retVal = Access_Read(reg, 2, ®Data); + if(TRUE != retVal) + return RT_ERR_SMI; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + + regData = regData & (~bits); + regData = regData | (valueShifted & bits); + + retVal = Access_Write(reg,2, regData); + if(TRUE != retVal) + return RT_ERR_SMI; + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + rtk_uint32 regData; + rtk_uint32 bitsShift; + rtk_uint32 valueShifted; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + valueShifted = value << bitsShift; + + if(valueShifted > RTL8367C_REGDATAMAX) + return RT_ERR_INPUT; + + if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + regData = CleVirtualReg[reg] & (~bits); + regData = regData | (valueShifted & bits); + + CleVirtualReg[reg] = regData; + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); + +#elif defined(EMBEDDED_SUPPORT) + rtk_uint32 regData; + rtk_uint32 bitsShift; + rtk_uint32 valueShifted; + + if(reg > RTL8367C_REGDATAMAX ) + return RT_ERR_INPUT; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + valueShifted = value << bitsShift; + if(valueShifted > RTL8367C_REGDATAMAX) + return RT_ERR_INPUT; + + regData = getReg(reg); + regData = regData & (~bits); + regData = regData | (valueShifted & bits); + + setReg(reg, regData); + +#else + rtk_uint32 regData; + ret_t retVal; + rtk_uint32 bitsShift; + rtk_uint32 valueShifted; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + valueShifted = value << bitsShift; + + if(valueShifted > RTL8367C_REGDATAMAX) + return RT_ERR_INPUT; + + retVal = smi_read(reg, ®Data); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif + + regData = regData & (~bits); + regData = regData | (valueShifted & bits); + + retVal = smi_write(reg, regData); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif +#endif + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicRegBits + * Description: + * Get bits value of a specified register + * Input: + * reg - register's address + * bits - bits mask for setting + * value - bits value for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicRegBits(rtk_uint32 reg, rtk_uint32 bits, rtk_uint32 *pValue) +{ + +#if defined(RTK_X86_ASICDRV) + + rtk_uint32 regData; + ret_t retVal; + rtk_uint32 bitsShift; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + retVal = Access_Read(reg, 2, ®Data); + if(TRUE != retVal) + return RT_ERR_SMI; + + *pValue = (regData & bits) >> bitsShift; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + rtk_uint32 bitsShift; + + if(bits >= (1 << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1 << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + *pValue = (CleVirtualReg[reg] & bits) >> bitsShift; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); + +#elif defined(EMBEDDED_SUPPORT) + rtk_uint32 regData; + rtk_uint32 bitsShift; + + if(reg > RTL8367C_REGDATAMAX ) + return RT_ERR_INPUT; + + if(bits >= (1UL << RTL8367C_REGBITLENGTH) ) + return RT_ERR_INPUT; + + bitsShift = 0; + while(!(bits & (1UL << bitsShift))) + { + bitsShift++; + if(bitsShift >= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + regData = getReg(reg); + *value = (regData & bits) >> bitsShift; + +#else + rtk_uint32 regData; + ret_t retVal; + rtk_uint32 bitsShift; + + if(bits>= (1<= RTL8367C_REGBITLENGTH) + return RT_ERR_INPUT; + } + + retVal = smi_read(reg, ®Data); + if(retVal != RT_ERR_OK) return RT_ERR_SMI; + + *pValue = (regData & bits) >> bitsShift; + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n",reg, regData); + #endif + +#endif + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicReg + * Description: + * Set content of asic register + * Input: + * reg - register's address + * value - Value setting to register + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * The value will be set to ASIC mapping address only and it is always return RT_ERR_OK while setting un-mapping address registers + */ +ret_t rtl8367c_setAsicReg(rtk_uint32 reg, rtk_uint32 value) +{ +#if defined(RTK_X86_ASICDRV)/*RTK-CNSD2-NickWu-20061222: for x86 compile*/ + + ret_t retVal; + + retVal = Access_Write(reg,2,value); + if(TRUE != retVal) return RT_ERR_SMI; + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value); + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + + /*MIBs emulating*/ + if(reg == RTL8367C_REG_MIB_ADDRESS) + { + CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG] = 0x1; + CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+1] = 0x2; + CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+2] = 0x3; + CleVirtualReg[RTL8367C_MIB_COUNTER_BASE_REG+3] = 0x4; + } + + if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + CleVirtualReg[reg] = value; + + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n",reg,CleVirtualReg[reg]); + +#elif defined(EMBEDDED_SUPPORT) + if(reg > RTL8367C_REGDATAMAX || value > RTL8367C_REGDATAMAX ) + return RT_ERR_INPUT; + + setReg(reg, value); + +#else + ret_t retVal; + + retVal = smi_write(reg, value); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("W[0x%4.4x]=0x%4.4x\n",reg,value); + #endif + +#endif + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicReg + * Description: + * Get content of asic register + * Input: + * reg - register's address + * value - Value setting to register + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * Value 0x0000 will be returned for ASIC un-mapping address + */ +ret_t rtl8367c_getAsicReg(rtk_uint32 reg, rtk_uint32 *pValue) +{ + +#if defined(RTK_X86_ASICDRV) + + rtk_uint32 regData; + ret_t retVal; + + retVal = Access_Read(reg, 2, ®Data); + if(TRUE != retVal) + return RT_ERR_SMI; + + *pValue = regData; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + +#elif defined(CONFIG_RTL8367C_ASICDRV_TEST) + if(reg >= CLE_VIRTUAL_REG_SIZE) + return RT_ERR_OUT_OF_RANGE; + + *pValue = CleVirtualReg[reg]; + + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, CleVirtualReg[reg]); + +#elif defined(EMBEDDED_SUPPORT) + if(reg > RTL8367C_REGDATAMAX ) + return RT_ERR_INPUT; + + *value = getReg(reg); + +#else + rtk_uint32 regData; + ret_t retVal; + + retVal = smi_read(reg, ®Data); + if(retVal != RT_ERR_OK) + return RT_ERR_SMI; + + *pValue = regData; + #ifdef CONFIG_RTL865X_CLE + if(0x8367B == cleDebuggingDisplay) + PRINT("R[0x%4.4x]=0x%4.4x\n", reg, regData); + #endif + +#endif + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c new file mode 100644 index 000000000000..1e4d2961e7d1 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_acl.c @@ -0,0 +1,1173 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : ACL related function drivers + * + */ +#include + +#include + +#if defined(CONFIG_RTL8367C_ASICDRV_TEST) +rtl8367c_aclrulesmi Rtl8370sVirtualAclRuleTable[RTL8367C_ACLRULENO]; +rtk_uint16 Rtl8370sVirtualAclActTable[RTL8367C_ACLRULENO][RTL8367C_ACL_ACT_TABLE_LEN]; +#endif + +/* + Exchange structure type define with MMI and SMI +*/ +static void _rtl8367c_aclRuleStSmi2User( rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi) +{ + rtk_uint8 *care_ptr, *data_ptr; + rtk_uint8 care_tmp, data_tmp; + rtk_uint32 i; + + pAclUser->data_bits.active_portmsk = (((pAclSmi->data_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->data_bits.rule_info >> 8) & 0x00FF); + pAclUser->data_bits.type = (pAclSmi->data_bits.rule_info & 0x0007); + pAclUser->data_bits.tag_exist = (pAclSmi->data_bits.rule_info & 0x00F8) >> 3; + + care_ptr = (rtk_uint8*)&pAclSmi->care_bits; + data_ptr = (rtk_uint8*)&pAclSmi->data_bits; + + for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++) + { + care_tmp = *(care_ptr + i) ^ (*(data_ptr + i)); + data_tmp = *(data_ptr + i); + + *(care_ptr + i) = care_tmp; + *(data_ptr + i) = data_tmp; + } + + care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext; + data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext; + care_tmp = (*care_ptr) ^ (*data_ptr); + data_tmp = (*data_ptr); + *care_ptr = care_tmp; + *data_ptr = data_tmp; + + for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) + pAclUser->data_bits.field[i] = pAclSmi->data_bits.field[i]; + + pAclUser->valid = pAclSmi->valid; + + pAclUser->care_bits.active_portmsk = (((pAclSmi->care_bits_ext.rule_info >> 1) & 0x0007) << 8) | ((pAclSmi->care_bits.rule_info >> 8) & 0x00FF); + pAclUser->care_bits.type = (pAclSmi->care_bits.rule_info & 0x0007); + pAclUser->care_bits.tag_exist = (pAclSmi->care_bits.rule_info & 0x00F8) >> 3; + + for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) + pAclUser->care_bits.field[i] = pAclSmi->care_bits.field[i]; +} + +/* + Exchange structure type define with MMI and SMI +*/ +static void _rtl8367c_aclRuleStUser2Smi(rtl8367c_aclrule *pAclUser, rtl8367c_aclrulesmi *pAclSmi) +{ + rtk_uint8 *care_ptr, *data_ptr; + rtk_uint8 care_tmp, data_tmp; + rtk_uint32 i; + + pAclSmi->data_bits_ext.rule_info = ((pAclUser->data_bits.active_portmsk >> 8) & 0x7) << 1; + pAclSmi->data_bits.rule_info = ((pAclUser->data_bits.active_portmsk & 0xff) << 8) | ((pAclUser->data_bits.tag_exist & 0x1F) << 3) | (pAclUser->data_bits.type & 0x07); + + for(i = 0;i < RTL8367C_ACLRULEFIELDNO; i++) + pAclSmi->data_bits.field[i] = pAclUser->data_bits.field[i]; + + pAclSmi->valid = pAclUser->valid; + + pAclSmi->care_bits_ext.rule_info = ((pAclUser->care_bits.active_portmsk >> 8) & 0x7) << 1; + pAclSmi->care_bits.rule_info = ((pAclUser->care_bits.active_portmsk & 0xff) << 8) | ((pAclUser->care_bits.tag_exist & 0x1F) << 3) | (pAclUser->care_bits.type & 0x07); + + for(i = 0; i < RTL8367C_ACLRULEFIELDNO; i++) + pAclSmi->care_bits.field[i] = pAclUser->care_bits.field[i]; + + care_ptr = (rtk_uint8*)&pAclSmi->care_bits; + data_ptr = (rtk_uint8*)&pAclSmi->data_bits; + + for ( i = 0; i < sizeof(struct acl_rule_smi_st); i++) + { + care_tmp = *(care_ptr + i) & ~(*(data_ptr + i)); + data_tmp = *(care_ptr + i) & *(data_ptr + i); + + *(care_ptr + i) = care_tmp; + *(data_ptr + i) = data_tmp; + } + + care_ptr = (rtk_uint8*)&pAclSmi->care_bits_ext; + data_ptr = (rtk_uint8*)&pAclSmi->data_bits_ext; + care_tmp = *care_ptr & ~(*data_ptr); + data_tmp = *care_ptr & *data_ptr; + + *care_ptr = care_tmp; + *data_ptr = data_tmp; +} + +/* + Exchange structure type define with MMI and SMI +*/ +static void _rtl8367c_aclActStSmi2User(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi) +{ + pAclUser->cact = (pAclSmi[0] & 0x00C0) >> 6; + pAclUser->cvidx_cact = (pAclSmi[0] & 0x003F) | (((pAclSmi[3] & 0x0008) >> 3) << 6); + + pAclUser->sact = (pAclSmi[0] & 0xC000) >> 14; + pAclUser->svidx_sact = ((pAclSmi[0] & 0x3F00) >> 8) | (((pAclSmi[3] & 0x0010) >> 4) << 6); + + pAclUser->aclmeteridx = (pAclSmi[1] & 0x003F) | (((pAclSmi[3] & 0x0020) >> 5) << 6); + + pAclUser->fwdact = (pAclSmi[1] & 0xC000) >> 14; + pAclUser->fwdpmask = ((pAclSmi[1] & 0x3FC0) >> 6) | (((pAclSmi[3] & 0x01C0) >> 6) << 8); + + pAclUser->priact = (pAclSmi[2] & 0x00C0) >> 6; + pAclUser->pridx = (pAclSmi[2] & 0x003F) | (((pAclSmi[3] & 0x0200) >> 9) << 6); + + pAclUser->aclint = (pAclSmi[2] & 0x2000) >> 13; + pAclUser->gpio_en = (pAclSmi[2] & 0x1000) >> 12; + pAclUser->gpio_pin = (pAclSmi[2] & 0x0F00) >> 8; + + pAclUser->cact_ext = (pAclSmi[2] & 0xC000) >> 14; + pAclUser->tag_fmt = (pAclSmi[3] & 0x0003); + pAclUser->fwdact_ext = (pAclSmi[3] & 0x0004) >> 2; +} + +/* + Exchange structure type define with MMI and SMI +*/ +static void _rtl8367c_aclActStUser2Smi(rtl8367c_acl_act_t *pAclUser, rtk_uint16 *pAclSmi) +{ + pAclSmi[0] |= (pAclUser->cvidx_cact & 0x003F); + pAclSmi[0] |= (pAclUser->cact & 0x0003) << 6; + pAclSmi[0] |= (pAclUser->svidx_sact & 0x003F) << 8; + pAclSmi[0] |= (pAclUser->sact & 0x0003) << 14; + + pAclSmi[1] |= (pAclUser->aclmeteridx & 0x003F); + pAclSmi[1] |= (pAclUser->fwdpmask & 0x00FF) << 6; + pAclSmi[1] |= (pAclUser->fwdact & 0x0003) << 14; + + pAclSmi[2] |= (pAclUser->pridx & 0x003F); + pAclSmi[2] |= (pAclUser->priact & 0x0003) << 6; + pAclSmi[2] |= (pAclUser->gpio_pin & 0x000F) << 8; + pAclSmi[2] |= (pAclUser->gpio_en & 0x0001) << 12; + pAclSmi[2] |= (pAclUser->aclint & 0x0001) << 13; + pAclSmi[2] |= (pAclUser->cact_ext & 0x0003) << 14; + + pAclSmi[3] |= (pAclUser->tag_fmt & 0x0003); + pAclSmi[3] |= (pAclUser->fwdact_ext & 0x0001) << 2; + pAclSmi[3] |= ((pAclUser->cvidx_cact & 0x0040) >> 6) << 3; + pAclSmi[3] |= ((pAclUser->svidx_sact & 0x0040) >> 6) << 4; + pAclSmi[3] |= ((pAclUser->aclmeteridx & 0x0040) >> 6) << 5; + pAclSmi[3] |= ((pAclUser->fwdpmask & 0x0700) >> 8) << 6; + pAclSmi[3] |= ((pAclUser->pridx & 0x0040) >> 6) << 9; +} + +/* Function Name: + * rtl8367c_setAsicAcl + * Description: + * Set port ACL function enable/disable + * Input: + * port - Physical port number (0~10) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicAcl(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicAcl + * Description: + * Get port ACL function enable/disable + * Input: + * port - Physical port number (0~10) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicAcl(rtk_uint32 port, rtk_uint32* pEnabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_ACL_ENABLE_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicAclUnmatchedPermit + * Description: + * Set port ACL function unmatched permit action + * Input: + * port - Physical port number (0~10) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicAclUnmatchedPermit + * Description: + * Get port ACL function unmatched permit action + * Input: + * port - Physical port number (0~10) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicAclUnmatchedPermit(rtk_uint32 port, rtk_uint32* pEnabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_ACL_UNMATCH_PERMIT_REG, port, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicAclRule + * Description: + * Set ACL rule content + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * pAclRule - ACL rule structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * System supported 95 shared 289-bit ACL ingress rule. Index was available at range 0-95 only. + * If software want to modify ACL rule, the ACL function should be disabled at first or unspecified + * ACL action will be executed. + * One ACL rule structure has three parts setting: + * Bit 0-147 Data Bits of this Rule + * Bit 148 Valid Bit + * Bit 149-296 Care Bits of this Rule + * There are four kinds of field in Data Bits and Care Bits: Active Portmask, Type, Tag Exist, and 8 fields + */ +ret_t rtl8367c_setAsicAclRule(rtk_uint32 index, rtl8367c_aclrule* pAclRule) +{ + rtl8367c_aclrulesmi aclRuleSmi; + rtk_uint16* tableAddr; + rtk_uint32 regAddr; + rtk_uint32 regData; + rtk_uint32 i; + ret_t retVal; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi)); + + _rtl8367c_aclRuleStUser2Smi(pAclRule, &aclRuleSmi); + + /* Write valid bit = 0 */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + if(index >= 64) + regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); + else + regData = RTL8367C_ACLRULETBADDR(DATABITS, index); + retVal = rtl8367c_setAsicReg(regAddr,regData); + if(retVal !=RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0x1, 0); + if(retVal !=RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal !=RT_ERR_OK) + return retVal; + + + + /* Write ACS_ADR register */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + if(index >= 64) + regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index); + else + regData = RTL8367C_ACLRULETBADDR(CAREBITS, index); + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write Care Bits to ACS_DATA registers */ + tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits; + regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; + + for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) + { + regData = *tableAddr; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr++; + tableAddr++; + } + retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.care_bits_ext.rule_info >> 1) & 0x0007); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write ACS_CMD register */ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,regData); + if(retVal != RT_ERR_OK) + return retVal; + + + + /* Write ACS_ADR register for data bits */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + if(index >= 64) + regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); + else + regData = RTL8367C_ACLRULETBADDR(DATABITS, index); + + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write Data Bits to ACS_DATA registers */ + tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits; + regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; + + for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) + { + regData = *tableAddr; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr++; + tableAddr++; + } + + retVal = rtl8367c_setAsicRegBit(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), 0, aclRuleSmi.valid); + if(retVal != RT_ERR_OK) + return retVal; + retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_WRDATA_REG(RTL8367C_ACLRULETBLEN), (0x0007 << 1), (aclRuleSmi.data_bits_ext.rule_info >> 1) & 0x0007); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write ACS_CMD register for care bits*/ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLRULE); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + +#ifdef CONFIG_RTL8367C_ASICDRV_TEST + memcpy(&Rtl8370sVirtualAclRuleTable[index], &aclRuleSmi, sizeof(rtl8367c_aclrulesmi)); +#endif + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicAclRule + * Description: + * Get ACL rule content + * Input: + * index - ACL rule index (0-63) of 64 ACL rules + * pAclRule - ACL rule structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-63) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclRule(rtk_uint32 index, rtl8367c_aclrule *pAclRule) +{ + rtl8367c_aclrulesmi aclRuleSmi; + rtk_uint32 regAddr, regData; + ret_t retVal; + rtk_uint16* tableAddr; + rtk_uint32 i; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + memset(&aclRuleSmi, 0x00, sizeof(rtl8367c_aclrulesmi)); + + /* Write ACS_ADR register for data bits */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + if(index >= 64) + regData = RTL8367C_ACLRULETBADDR2(DATABITS, index); + else + regData = RTL8367C_ACLRULETBADDR(DATABITS, index); + + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + + /* Write ACS_CMD register */ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Data Bits */ + regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; + tableAddr = (rtk_uint16*)&aclRuleSmi.data_bits; + for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *tableAddr = regData; + + regAddr ++; + tableAddr ++; + } + + /* Read Valid Bit */ + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + aclRuleSmi.valid = regData & 0x1; + /* Read active_portmsk_ext Bits */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + aclRuleSmi.data_bits_ext.rule_info = (regData % 0x0007) << 1; + + + /* Write ACS_ADR register for carebits*/ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + if(index >= 64) + regData = RTL8367C_ACLRULETBADDR2(CAREBITS, index); + else + regData = RTL8367C_ACLRULETBADDR(CAREBITS, index); + + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write ACS_CMD register */ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLRULE); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Care Bits */ + regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; + tableAddr = (rtk_uint16*)&aclRuleSmi.care_bits; + for(i = 0; i < RTL8367C_ACLRULETBLEN; i++) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *tableAddr = regData; + + regAddr ++; + tableAddr ++; + } + /* Read active_portmsk_ext care Bits */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_RDDATA_REG(RTL8367C_ACLRULETBLEN), 0x7<<1, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + aclRuleSmi.care_bits_ext.rule_info = (regData & 0x0007) << 1; + +#ifdef CONFIG_RTL8367C_ASICDRV_TEST + memcpy(&aclRuleSmi,&Rtl8370sVirtualAclRuleTable[index], sizeof(rtl8367c_aclrulesmi)); +#endif + + _rtl8367c_aclRuleStSmi2User(pAclRule, &aclRuleSmi); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclNot + * Description: + * Set rule comparison result inversion / no inversion + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * not - 1: inverse, 0: don't inverse + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * None + */ +ret_t rtl8367c_setAsicAclNot(rtk_uint32 index, rtk_uint32 not) +{ + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(index < 64) + return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not); + else + return rtl8367c_setAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), not); + +} +/* Function Name: + * rtl8367c_getAsicAcl + * Description: + * Get rule comparison result inversion / no inversion + * Input: + * index - ACL rule index (0-95) of 95 ACL rules + * pNot - 1: inverse, 0: don't inverse + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclNot(rtk_uint32 index, rtk_uint32* pNot) +{ + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(index < 64) + return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot); + else + return rtl8367c_getAsicRegBit(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_NOT_OFFSET(index), pNot); + +} +/* Function Name: + * rtl8367c_setAsicAclTemplate + * Description: + * Set fields of a ACL Template + * Input: + * index - ACL template index(0~4) + * pAclType - ACL type structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL template index(0~4) + * Note: + * The API can set type field of the 5 ACL rule templates. + * Each type has 8 fields. One field means what data in one field of a ACL rule means + * 8 fields of ACL rule 0~95 is described by one type in ACL group + */ +ret_t rtl8367c_setAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t* pAclType) +{ + ret_t retVal; + rtk_uint32 i; + rtk_uint32 regAddr, regData; + + if(index >= RTL8367C_ACLTEMPLATENO) + return RT_ERR_OUT_OF_RANGE; + + regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index); + + for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++) + { + regData = pAclType->field[i*2+1]; + regData = regData << 8 | pAclType->field[i*2]; + + retVal = rtl8367c_setAsicReg(regAddr + i, regData); + + if(retVal != RT_ERR_OK) + return retVal; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicAclTemplate + * Description: + * Get fields of a ACL Template + * Input: + * index - ACL template index(0~4) + * pAclType - ACL type structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL template index(0~4) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclTemplate(rtk_uint32 index, rtl8367c_acltemplate_t *pAclType) +{ + ret_t retVal; + rtk_uint32 i; + rtk_uint32 regData, regAddr; + + if(index >= RTL8367C_ACLTEMPLATENO) + return RT_ERR_OUT_OF_RANGE; + + regAddr = RTL8367C_ACL_RULE_TEMPLATE_CTRL_REG(index); + + for(i = 0; i < (RTL8367C_ACLRULEFIELDNO/2); i++) + { + retVal = rtl8367c_getAsicReg(regAddr + i,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pAclType->field[i*2] = regData & 0xFF; + pAclType->field[i*2 + 1] = (regData >> 8) & 0xFF; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclAct + * Description: + * Set ACL rule matched Action + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * pAclAct - ACL action structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * None + */ +ret_t rtl8367c_setAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t* pAclAct) +{ + rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN]; + ret_t retVal; + rtk_uint32 regAddr, regData; + rtk_uint16* tableAddr; + rtk_uint32 i; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); + _rtl8367c_aclActStUser2Smi(pAclAct, aclActSmi); + + /* Write ACS_ADR register for data bits */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + regData = index; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write Data Bits to ACS_DATA registers */ + tableAddr = aclActSmi; + regAddr = RTL8367C_TABLE_ACCESS_WRDATA_BASE; + + for(i = 0; i < RTL8367C_ACLACTTBLEN; i++) + { + regData = *tableAddr; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr++; + tableAddr++; + } + + /* Write ACS_CMD register for care bits*/ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE, TB_TARGET_ACLACT); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + +#ifdef CONFIG_RTL8367C_ASICDRV_TEST + memcpy(&Rtl8370sVirtualAclActTable[index][0], aclActSmi, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); +#endif + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicAclAct + * Description: + * Get ACL rule matched Action + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * pAclAct - ACL action structure for setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclAct(rtk_uint32 index, rtl8367c_acl_act_t *pAclAct) +{ + rtk_uint16 aclActSmi[RTL8367C_ACL_ACT_TABLE_LEN]; + ret_t retVal; + rtk_uint32 regAddr, regData; + rtk_uint16 *tableAddr; + rtk_uint32 i; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + memset(aclActSmi, 0x00, sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); + + /* Write ACS_ADR register for data bits */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + regData = index; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write ACS_CMD register */ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_ACLACT); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Data Bits */ + regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; + tableAddr = aclActSmi; + for(i = 0; i < RTL8367C_ACLACTTBLEN; i++) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *tableAddr = regData; + + regAddr ++; + tableAddr ++; + } + +#ifdef CONFIG_RTL8367C_ASICDRV_TEST + memcpy(aclActSmi, &Rtl8370sVirtualAclActTable[index][0], sizeof(rtk_uint16) * RTL8367C_ACL_ACT_TABLE_LEN); +#endif + + _rtl8367c_aclActStSmi2User(pAclAct, aclActSmi); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclActCtrl + * Description: + * Set ACL rule matched Action Control Bits + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * aclActCtrl - 6 ACL Control Bits + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * ACL Action Control Bits Indicate which actions will be take when a rule matches + */ +ret_t rtl8367c_setAsicAclActCtrl(rtk_uint32 index, rtk_uint32 aclActCtrl) +{ + ret_t retVal; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(index >= 64) + retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl); + else + retVal = rtl8367c_setAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), aclActCtrl); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicAclActCtrl + * Description: + * Get ACL rule matched Action Control Bits + * Input: + * index - ACL rule index (0-95) of 96 ACL rules + * pAclActCtrl - 6 ACL Control Bits + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL rule index (0-95) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclActCtrl(rtk_uint32 index, rtk_uint32 *pAclActCtrl) +{ + ret_t retVal; + rtk_uint32 regData; + + if(index > RTL8367C_ACLRULEMAX) + return RT_ERR_OUT_OF_RANGE; + + if(index >= 64) + retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL2_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), ®Data); + else + retVal = rtl8367c_getAsicRegBits(RTL8367C_ACL_ACTION_CTRL_REG(index), RTL8367C_ACL_OP_ACTION_MASK(index), ®Data); + + if(retVal != RT_ERR_OK) + return retVal; + + *pAclActCtrl = regData; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclPortRange + * Description: + * Set ACL TCP/UDP range check + * Input: + * index - TCP/UDP port range check table index + * type - Range check type + * upperPort - TCP/UDP port range upper bound + * lowerPort - TCP/UDP port range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid TCP/UDP port range check table index + * Note: + * None + */ +ret_t rtl8367c_setAsicAclPortRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperPort, rtk_uint32 lowerPort) +{ + ret_t retVal; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, type); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, upperPort); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, lowerPort); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicAclPortRange + * Description: + * Get ACL TCP/UDP range check + * Input: + * index - TCP/UDP port range check table index + * pType - Range check type + * pUpperPort - TCP/UDP port range upper bound + * pLowerPort - TCP/UDP port range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid TCP/UDP port range check table index + * Note: + * None + */ +ret_t rtl8367c_getAsicAclPortRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperPort, rtk_uint32* pLowerPort) +{ + ret_t retVal; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL2 + index*3, RTL8367C_ACL_SDPORT_RANGE_ENTRY0_CTRL2_MASK, pType); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL1 + index*3, pUpperPort); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_SDPORT_RANGE_ENTRY0_CTRL0 + index*3, pLowerPort); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclVidRange + * Description: + * Set ACL VID range check + * Input: + * index - ACL VID range check index(0~15) + * type - Range check type + * upperVid - VID range upper bound + * lowerVid - VID range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL VID range check index(0~15) + * Note: + * None + */ +ret_t rtl8367c_setAsicAclVidRange(rtk_uint32 index, rtk_uint32 type, rtk_uint32 upperVid, rtk_uint32 lowerVid) +{ + ret_t retVal; + rtk_uint32 regData; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + regData = ((type << RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET) & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) | + (upperVid & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK); + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, regData); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, lowerVid); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicAclVidRange + * Description: + * Get ACL VID range check + * Input: + * index - ACL VID range check index(0~15) + * pType - Range check type + * pUpperVid - VID range upper bound + * pLowerVid - VID range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL VID range check index(0~15) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclVidRange(rtk_uint32 index, rtk_uint32* pType, rtk_uint32* pUpperVid, rtk_uint32* pLowerVid) +{ + ret_t retVal; + rtk_uint32 regData; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL1 + index*2, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pType = (regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_MASK) >> RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_TYPE_OFFSET; + *pUpperVid = regData & RTL8367C_ACL_VID_RANGE_ENTRY0_CTRL1_CHECK0_HIGH_MASK; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_VID_RANGE_ENTRY0_CTRL0 + index*2, pLowerVid); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicAclIpRange + * Description: + * Set ACL IP range check + * Input: + * index - ACL IP range check index(0~15) + * type - Range check type + * upperIp - IP range upper bound + * lowerIp - IP range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL IP range check index(0~15) + * Note: + * None + */ +ret_t rtl8367c_setAsicAclIpRange(rtk_uint32 index, rtk_uint32 type, ipaddr_t upperIp, ipaddr_t lowerIp) +{ + ret_t retVal; + rtk_uint32 regData; + ipaddr_t ipData; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, type); + if(retVal != RT_ERR_OK) + return retVal; + + ipData = upperIp; + + regData = ipData & 0xFFFF; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regData = (ipData>>16) & 0xFFFF; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, regData); + if(retVal != RT_ERR_OK) + return retVal; + + ipData = lowerIp; + + regData = ipData & 0xFFFF; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regData = (ipData>>16) & 0xFFFF; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, regData); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicAclIpRange + * Description: + * Get ACL IP range check + * Input: + * index - ACL IP range check index(0~15) + * pType - Range check type + * pUpperIp - IP range upper bound + * pLowerIp - IP range lower bound + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid ACL IP range check index(0~15) + * Note: + * None + */ +ret_t rtl8367c_getAsicAclIpRange(rtk_uint32 index, rtk_uint32* pType, ipaddr_t* pUpperIp, ipaddr_t* pLowerIp) +{ + ret_t retVal; + rtk_uint32 regData; + ipaddr_t ipData; + + if(index > RTL8367C_ACLRANGEMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL4 + index*5, RTL8367C_ACL_IP_RANGE_ENTRY0_CTRL4_MASK, pType); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL2 + index*5, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + ipData = regData; + + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL3 + index*5, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + ipData = (regData <<16) | ipData; + *pUpperIp = ipData; + + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL0 + index*5, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + ipData = regData; + + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_ACL_IP_RANGE_ENTRY0_CTRL1 + index*5, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + ipData = (regData << 16) | ipData; + *pLowerIp = ipData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicAclGpioPolarity + * Description: + * Set ACL Goip control polarity + * Input: + * polarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +ret_t rtl8367c_setAsicAclGpioPolarity(rtk_uint32 polarity) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, polarity); +} +/* Function Name: + * rtl8367c_getAsicAclGpioPolarity + * Description: + * Get ACL Goip control polarity + * Input: + * pPolarity - 1: High, 0: Low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * none + */ +ret_t rtl8367c_getAsicAclGpioPolarity(rtk_uint32* pPolarity) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_ACL_GPIO_POLARITY, RTL8367C_ACL_GPIO_POLARITY_OFFSET, pPolarity); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c new file mode 100644 index 000000000000..ec9c332e1620 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_cputag.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Proprietary CPU-tag related function drivers + * + */ +#include +/* Function Name: + * rtl8367c_setAsicCputagEnable + * Description: + * Set CPU tag function enable/disable + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid enable/disable input + * Note: + * If CPU tag function is disabled, CPU tag will not be added to frame + * forwarded to CPU port, and all ports cannot parse CPU tag. + */ +ret_t rtl8367c_setAsicCputagEnable(rtk_uint32 enabled) +{ + if(enabled > 1) + return RT_ERR_ENABLE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicCputagEnable + * Description: + * Get CPU tag function enable/disable + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagEnable(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_EN_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicCputagTrapPort + * Description: + * Set CPU tag trap port + * Input: + * port - port number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * API can set destination port of trapping frame + */ +ret_t rtl8367c_setAsicCputagTrapPort(rtk_uint32 port) +{ + ret_t retVal; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, port & 7); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, (port>>3) & 1); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicCputagTrapPort + * Description: + * Get CPU tag trap port + * Input: + * pPort - port number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagTrapPort(rtk_uint32 *pPort) +{ + ret_t retVal; + rtk_uint32 tmpPort; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_MASK, &tmpPort); + if(retVal != RT_ERR_OK) + return retVal; + *pPort = tmpPort; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TRAP_PORT_EXT_MASK, &tmpPort); + if(retVal != RT_ERR_OK) + return retVal; + *pPort |= (tmpPort & 1) << 3; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicCputagPortmask + * Description: + * Set ports that can parse CPU tag + * Input: + * portmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicCputagPortmask(rtk_uint32 portmask) +{ + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_CPU_PORT_MASK_REG, portmask); +} +/* Function Name: + * rtl8367c_getAsicCputagPortmask + * Description: + * Get ports that can parse CPU tag + * Input: + * pPortmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_CPU_PORT_MASK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicCputagInsertMode + * Description: + * Set CPU-tag insert mode + * Input: + * mode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Actions not allowed by the function + * Note: + * None + */ +ret_t rtl8367c_setAsicCputagInsertMode(rtk_uint32 mode) +{ + if(mode >= CPUTAG_INSERT_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, mode); +} +/* Function Name: + * rtl8367c_getAsicCputagInsertMode + * Description: + * Get CPU-tag insert mode + * Input: + * pMode - 0: insert to all packets; 1: insert to trapped packets; 2: don't insert + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagInsertMode(rtk_uint32 *pMode) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_INSERTMODE_MASK, pMode); +} +/* Function Name: + * rtl8367c_setAsicCputagPriorityRemapping + * Description: + * Set queue assignment of CPU port + * Input: + * srcPri - internal priority (0~7) + * newPri - internal priority after remapping (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 newPri) +{ + if((srcPri > RTL8367C_PRIMAX) || (newPri > RTL8367C_PRIMAX)) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), newPri); +} +/* Function Name: + * rtl8367c_getAsicCputagPriorityRemapping + * Description: + * Get queue assignment of CPU port + * Input: + * srcPri - internal priority (0~7) + * pNewPri - internal priority after remapping (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagPriorityRemapping(rtk_uint32 srcPri, rtk_uint32 *pNewPri) +{ + if(srcPri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_REG(srcPri), RTL8367C_QOS_PRIPORITY_REMAPPING_IN_CPU_MASK(srcPri), pNewPri); +} +/* Function Name: + * rtl8367c_setAsicCputagPosition + * Description: + * Set CPU tag insert position + * Input: + * position - 1: After entire packet(before CRC field), 0: After MAC_SA (Default) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicCputagPosition(rtk_uint32 position) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, position); +} +/* Function Name: + * rtl8367c_getAsicCputagPosition + * Description: + * Get CPU tag insert position + * Input: + * pPostion - 1: After entire packet(before CRC field), 0: After MAC_SA (Default) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagPosition(rtk_uint32* pPostion) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_POSITION_OFFSET, pPostion); +} + +/* Function Name: + * rtl8367c_setAsicCputagMode + * Description: + * Set CPU tag mode + * Input: + * mode - 1: 4bytes mode, 0: 8bytes mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters + * Note: + * If CPU tag function is disabled, CPU tag will not be added to frame + * forwarded to CPU port, and all ports cannot parse CPU tag. + */ +ret_t rtl8367c_setAsicCputagMode(rtk_uint32 mode) +{ + if(mode > 1) + return RT_ERR_INPUT; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, mode); +} +/* Function Name: + * rtl8367c_getAsicCputagMode + * Description: + * Get CPU tag mode + * Input: + * pMode - 1: 4bytes mode, 0: 8bytes mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagMode(rtk_uint32 *pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_FORMAT_OFFSET, pMode); +} +/* Function Name: + * rtl8367c_setAsicCputagRxMinLength + * Description: + * Set CPU tag mode + * Input: + * mode - 1: 64bytes, 0: 72bytes + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters + * Note: + * If CPU tag function is disabled, CPU tag will not be added to frame + * forwarded to CPU port, and all ports cannot parse CPU tag. + */ +ret_t rtl8367c_setAsicCputagRxMinLength(rtk_uint32 mode) +{ + if(mode > 1) + return RT_ERR_INPUT; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, mode); +} +/* Function Name: + * rtl8367c_getAsicCputagRxMinLength + * Description: + * Get CPU tag mode + * Input: + * pMode - 1: 64bytes, 0: 72bytes + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicCputagRxMinLength(rtk_uint32 *pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_CPU_CTRL, RTL8367C_CPU_TAG_RXBYTECOUNT_OFFSET, pMode); +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c new file mode 100644 index 000000000000..73153e177ee9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_dot1x.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : 802.1X related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsic1xPBEnConfig + * Description: + * Set 802.1x port-based port enable configuration + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsic1xPBEnConfig + * Description: + * Get 802.1x port-based port enable configuration + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsic1xPBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_ENABLE_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsic1xPBAuthConfig + * Description: + * Set 802.1x port-based authorised port configuration + * Input: + * port - Physical port number (0~7) + * auth - 1: authorised, 0: non-authorised + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 auth) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, auth); +} +/* Function Name: + * rtl8367c_getAsic1xPBAuthConfig + * Description: + * Get 802.1x port-based authorised port configuration + * Input: + * port - Physical port number (0~7) + * pAuth - 1: authorised, 0: non-authorised + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsic1xPBAuthConfig(rtk_uint32 port, rtk_uint32 *pAuth) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_AUTH_REG, port, pAuth); +} +/* Function Name: + * rtl8367c_setAsic1xPBOpdirConfig + * Description: + * Set 802.1x port-based operational direction + * Input: + * port - Physical port number (0~7) + * opdir - Operation direction 1: IN, 0:BOTH + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32 opdir) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, opdir); +} +/* Function Name: + * rtl8367c_getAsic1xPBOpdirConfig + * Description: + * Get 802.1x port-based operational direction + * Input: + * port - Physical port number (0~7) + * pOpdir - Operation direction 1: IN, 0:BOTH + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsic1xPBOpdirConfig(rtk_uint32 port, rtk_uint32* pOpdir) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_PORT_OPDIR_REG, port, pOpdir); +} +/* Function Name: + * rtl8367c_setAsic1xMBEnConfig + * Description: + * Set 802.1x mac-based port enable configuration + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsic1xMBEnConfig + * Description: + * Get 802.1x mac-based port enable configuration + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsic1xMBEnConfig(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_MAC_ENABLE_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsic1xMBOpdirConfig + * Description: + * Set 802.1x mac-based operational direction + * Input: + * opdir - Operation direction 1: IN, 0:BOTH + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsic1xMBOpdirConfig(rtk_uint32 opdir) +{ + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, opdir); +} +/* Function Name: + * rtl8367c_getAsic1xMBOpdirConfig + * Description: + * Get 802.1x mac-based operational direction + * Input: + * pOpdir - Operation direction 1: IN, 0:BOTH + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsic1xMBOpdirConfig(rtk_uint32 *pOpdir) +{ + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_MAC_OPDIR_OFFSET, pOpdir); +} +/* Function Name: + * rtl8367c_setAsic1xProcConfig + * Description: + * Set 802.1x unauth. behavior configuration + * Input: + * port - Physical port number (0~7) + * proc - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_DOT1X_PROC - Unauthorized behavior error + * Note: + * None + */ +ret_t rtl8367c_setAsic1xProcConfig(rtk_uint32 port, rtk_uint32 proc) +{ + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(proc >= DOT1X_UNAUTH_END) + return RT_ERR_DOT1X_PROC; + + if(port < 8) + { + return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc); + } + else + { + return rtl8367c_setAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),proc); + } +} +/* Function Name: + * rtl8367c_getAsic1xProcConfig + * Description: + * Get 802.1x unauth. behavior configuration + * Input: + * port - Physical port number (0~7) + * pProc - 802.1x unauth. behavior configuration 0:drop 1:trap to CPU 2:Guest VLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsic1xProcConfig(rtk_uint32 port, rtk_uint32* pProc) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_UNAUTH_ACT_BASE, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_DOT1X_UNAUTH_ACT_W1, RTL8367C_DOT1X_UNAUTH_ACT_MASK(port),pProc); +} +/* Function Name: + * rtl8367c_setAsic1xGuestVidx + * Description: + * Set 802.1x guest vlan index + * Input: + * index - 802.1x guest vlan index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_DOT1X_GVLANIDX - Invalid cvid index + * Note: + * None + */ +ret_t rtl8367c_setAsic1xGuestVidx(rtk_uint32 index) +{ + if(index >= RTL8367C_CVIDXNO) + return RT_ERR_DOT1X_GVLANIDX; + + return rtl8367c_setAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, index); +} +/* Function Name: + * rtl8367c_getAsic1xGuestVidx + * Description: + * Get 802.1x guest vlan index + * Input: + * pIndex - 802.1x guest vlan index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsic1xGuestVidx(rtk_uint32 *pIndex) +{ + return rtl8367c_getAsicRegBits(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVIDX_MASK, pIndex); +} +/* Function Name: + * rtl8367c_setAsic1xGVOpdir + * Description: + * Set 802.1x guest vlan talk to auth. DA + * Input: + * enabled - 0:disable 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsic1xGVOpdir(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsic1xGVOpdir + * Description: + * Get 802.1x guest vlan talk to auth. DA + * Input: + * pEnabled - 0:disable 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsic1xGVOpdir(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_DOT1X_CFG_REG, RTL8367C_DOT1X_GVOPDIR_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsic1xTrapPriority + * Description: + * Set 802.1x Trap priority + * Input: + * priority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsic1xTrapPriority(rtk_uint32 priority) +{ + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK,priority); +} +/* Function Name: + * rtl8367c_getAsic1xTrapPriority + * Description: + * Get 802.1x Trap priority + * Input: + * pPriority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsic1xTrapPriority(rtk_uint32 *pPriority) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_DOT1X_PRIORTY_MASK, pPriority); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c new file mode 100644 index 000000000000..811ee4795441 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eav.c @@ -0,0 +1,877 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Ethernet AV related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicEavMacAddress + * Description: + * Set PTP MAC address + * Input: + * mac - PTP mac + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicEavMacAddress(ether_addr_t mac) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint8 *accessPtr; + rtk_uint32 i; + + accessPtr = (rtk_uint8*)&mac; + + regData = *accessPtr; + accessPtr ++; + regData = (regData << 8) | *accessPtr; + accessPtr ++; + for(i = 0; i <=2; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_REG_MAC_ADDR_H - i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regData = *accessPtr; + accessPtr ++; + regData = (regData << 8) | *accessPtr; + accessPtr ++; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicEavMacAddress + * Description: + * Get PTP MAC address + * Input: + * None + * Output: + * pMac - PTP mac + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEavMacAddress(ether_addr_t *pMac) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint8 *accessPtr; + rtk_uint32 i; + + accessPtr = (rtk_uint8*)pMac; + + for(i = 0; i <= 2; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC_ADDR_H - i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = (regData & 0xFF00) >> 8; + accessPtr ++; + *accessPtr = regData & 0xFF; + accessPtr ++; + } + + return retVal; +} + +/* Function Name: + * rtl8367c_setAsicEavTpid + * Description: + * Set PTP parser tag TPID. + * Input: + * outerTag - outer tag TPID + * innerTag - inner tag TPID + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicEavTpid(rtk_uint32 outerTag, rtk_uint32 innerTag) +{ + ret_t retVal; + + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_OTAG_TPID, outerTag)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_ITAG_TPID, innerTag)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicEavTpid + * Description: + * Get PTP parser tag TPID. + * Input: + * None + * Output: + * pOuterTag - outer tag TPID + * pInnerTag - inner tag TPID + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEavTpid(rtk_uint32* pOuterTag, rtk_uint32* pInnerTag) +{ + ret_t retVal; + + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_OTAG_TPID, pOuterTag)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_ITAG_TPID, pInnerTag)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicEavSysTime + * Description: + * Set PTP system time + * Input: + * second - seconds + * nanoSecond - nano seconds + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * The time granularity is 8 nano seconds. + */ +ret_t rtl8367c_setAsicEavSysTime(rtk_uint32 second, rtk_uint32 nanoSecond) +{ + ret_t retVal; + rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l; + rtk_uint32 nano_second_8; + rtk_uint32 regData, busyFlag, count; + + if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX) + return RT_ERR_INPUT; + + regData = 0; + sec_h = second >>16; + sec_l = second & 0xFFFF; + nano_second_8 = nanoSecond >> 3; + nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK; + nsec8_l = nano_second_8 &0xFFFF; + + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK) + return retVal; + + regData = nsec8_h | (PTP_TIME_WRITE<= PTP_TIME_ADJ_END) + return RT_ERR_INPUT; + if(nanoSecond > RTL8367C_EAV_NANOSECONDMAX) + return RT_ERR_INPUT; + + regData = 0; + sec_h = second >>16; + sec_l = second & 0xFFFF; + nano_second_8 = nanoSecond >> 3; + nsec8_h = (nano_second_8 >>16) & RTL8367C_PTP_TIME_NSEC_H_NSEC_MASK; + nsec8_l = nano_second_8 &0xFFFF; + + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_H_SEC, sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_SEC_L_SEC, sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_NSEC_L_NSEC, nsec8_l)) != RT_ERR_OK) + return retVal; + + if (PTP_TIME_ADJ_INC == type) + regData = nsec8_h | (PTP_TIME_INC<=PTP_TIME_CTRL_END) + return RT_ERR_INPUT; + + regData = 0; + if (PTP_TIME_CTRL_START == control) + regData = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK; + else + regData = 0; + + if((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PTP_TIME_CFG, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicEavSysTimeCtrl + * Description: + * Get PTP system time control + * Input: + * None + * Output: + * pControl - start or stop + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEavSysTimeCtrl(rtk_uint32* pControl) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 mask; + + mask = RTL8367C_CFG_TIMER_EN_FRC_MASK | RTL8367C_CFG_TIMER_1588_EN_MASK; + + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PTP_TIME_CFG, ®Data)) != RT_ERR_OK) + return retVal; + + if( (regData & mask) == mask) + *pControl = PTP_TIME_CTRL_START; + else if( (regData & mask) == 0) + *pControl = PTP_TIME_CTRL_STOP; + else + return RT_ERR_NOT_ALLOWED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicEavInterruptMask + * Description: + * Set PTP interrupt enable mask + * Input: + * imr - Interrupt mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * [0]:TX_SYNC, + * [1]:TX_DELAY, + * [2]:TX_PDELAY_REQ, + * [3]:TX_PDELAY_RESP, + * [4]:RX_SYNC, + * [5]:RX_DELAY, + * [6]:RX_PDELAY_REQ, + * [7]:RX_PDELAY_RESP, + */ +ret_t rtl8367c_setAsicEavInterruptMask(rtk_uint32 imr) +{ + if ((imr&(RTL8367C_PTP_INTR_MASK<<8))>0) + return RT_ERR_INPUT; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, imr); +} +/* Function Name: + * rtl8367c_getAsicEavInterruptMask + * Description: + * Get PTP interrupt enable mask + * Input: + * pImr - Interrupt mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * [0]:TX_SYNC, + * [1]:TX_DELAY, + * [2]:TX_PDELAY_REQ, + * [3]:TX_PDELAY_RESP, + * [4]:RX_SYNC, + * [5]:RX_DELAY, + * [6]:RX_PDELAY_REQ, + * [7]:RX_PDELAY_RESP, + */ +ret_t rtl8367c_getAsicEavInterruptMask(rtk_uint32* pImr) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_TIME_CFG2, RTL8367C_PTP_INTR_MASK, pImr); +} + +/* Function Name: + * rtl8367c_getAsicEavInterruptStatus + * Description: + * Get PTP interrupt port status mask + * Input: + * pIms - Interrupt mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * [0]:p0 interrupt, + * [1]:p1 interrupt, + * [2]:p2 interrupt, + * [3]:p3 interrupt, + * [4]:p4 interrupt, + */ +ret_t rtl8367c_getAsicEavInterruptStatus(rtk_uint32* pIms) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_PTP_INTERRUPT_CFG, RTL8367C_PTP_PORT_MASK, pIms); +} + +/* Function Name: + * rtl8367c_setAsicInterruptMask + * Description: + * Clear interrupt enable mask + * Input: + * ims - Interrupt status mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * This API can be used to clear ASIC interrupt status and register will be cleared by writing 1. + * [0]:TX_SYNC, + * [1]:TX_DELAY, + * [2]:TX_PDELAY_REQ, + * [3]:TX_PDELAY_RESP, + * [4]:RX_SYNC, + * [5]:RX_DELAY, + * [6]:RX_PDELAY_REQ, + * [7]:RX_PDELAY_RESP, + */ +ret_t rtl8367c_setAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32 ims) +{ + + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(port < 5) + return rtl8367c_setAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK,ims); + else if(port == 5) + return rtl8367c_setAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); + else if(port == 6) + return rtl8367c_setAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); + else if(port == 7) + return rtl8367c_setAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); + else if(port == 8) + return rtl8367c_setAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); + else if(port == 9) + return rtl8367c_setAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,ims); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicInterruptStatus + * Description: + * Get interrupt enable mask + * Input: + * pIms - Interrupt status mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * [0]:TX_SYNC, + * [1]:TX_DELAY, + * [2]:TX_PDELAY_REQ, + * [3]:TX_PDELAY_RESP, + * [4]:RX_SYNC, + * [5]:RX_DELAY, + * [6]:RX_PDELAY_REQ, + * [7]:RX_PDELAY_RESP, + */ +ret_t rtl8367c_getAsicEavPortInterruptStatus(rtk_uint32 port, rtk_uint32* pIms) +{ + + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + if(port < 5) + return rtl8367c_getAsicRegBits(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_PTP_INTR_MASK, pIms); + else if(port == 5) + return rtl8367c_getAsicRegBits(RTL8367C_REG_P5_EAV_CFG, RTL8367C_PTP_INTR_MASK, pIms); + else if(port == 6) + return rtl8367c_getAsicRegBits(RTL8367C_REG_P6_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); + else if(port == 7) + return rtl8367c_getAsicRegBits(RTL8367C_REG_P7_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); + else if(port == 8) + return rtl8367c_getAsicRegBits(RTL8367C_REG_P8_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); + else if(port == 9) + return rtl8367c_getAsicRegBits(RTL8367C_REG_P9_EAV_CFG, RTL8367C_PTP_INTR_MASK,pIms); + + return RT_ERR_OK; + +} + + +/* Function Name: + * rtl8367c_setAsicEavPortEnable + * Description: + * Set per-port EAV function enable/disable + * Input: + * port - Physical port number (0~9) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * If EAV function is enabled, PTP event message packet will be attached PTP timestamp for trapping + */ +ret_t rtl8367c_setAsicEavPortEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(port < 5) + return rtl8367c_setAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + else if(port == 5) + return rtl8367c_setAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + else if(port == 6) + return rtl8367c_setAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + else if(port == 7) + return rtl8367c_setAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + else if(port == 8) + return rtl8367c_setAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + else if(port == 9) + return rtl8367c_setAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, enabled); + + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicEavPortEnable + * Description: + * Get per-port EAV function enable/disable + * Input: + * port - Physical port number (0~9) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicEavPortEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + + + if(port < 5) + return rtl8367c_getAsicRegBit(RTL8367C_EAV_PORT_CFG_REG(port), RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + else if(port == 5) + return rtl8367c_getAsicRegBit(RTL8367C_REG_P5_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + else if(port == 6) + return rtl8367c_getAsicRegBit(RTL8367C_REG_P6_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + else if(port == 7) + return rtl8367c_getAsicRegBit(RTL8367C_REG_P7_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + else if(port == 8) + return rtl8367c_getAsicRegBit(RTL8367C_REG_P8_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + else if(port == 9) + return rtl8367c_getAsicRegBit(RTL8367C_REG_P9_EAV_CFG, RTL8367C_EAV_CFG_PTP_PHY_EN_EN_OFFSET, pEnabled); + + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicEavPortTimeStamp + * Description: + * Get PTP port time stamp + * Input: + * port - Physical port number (0~9) + * type - PTP packet type + * Output: + * timeStamp - seconds + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * The time granularity is 8 nano seconds. + */ +ret_t rtl8367c_getAsicEavPortTimeStamp(rtk_uint32 port, rtk_uint32 type, rtl8367c_ptp_time_stamp_t* timeStamp) +{ + ret_t retVal; + rtk_uint32 sec_h, sec_l, nsec8_h, nsec8_l; + rtk_uint32 nano_second_8; + + if(port > 9) + return RT_ERR_PORT_ID; + if(type >= PTP_PKT_TYPE_END) + return RT_ERR_INPUT; + + if(port < 5){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SEQ_ID(port, type), &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_H(port) , &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_SEC_L(port), &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_NSEC_H(port) , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT_NSEC_L(port) , &nsec8_l)) != RT_ERR_OK) + return retVal; + }else if(port == 5){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P5_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P5_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) + return retVal; + }else if(port == 6){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P6_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P6_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) + return retVal; + }else if(port == 7){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P7_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P7_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) + return retVal; + }else if(port == 8){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P8_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P8_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) + return retVal; + }else if(port == 9){ + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_TX_SYNC_SEQ_ID+type, &timeStamp->sequence_id))!= RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_31_16, &sec_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_SEC_15_0, &sec_l)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_P9_PORT_NSEC_26_16 , RTL8367C_PORT_NSEC_H_MASK,&nsec8_h)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicReg(RTL8367C_REG_P9_PORT_NSEC_15_0, &nsec8_l)) != RT_ERR_OK) + return retVal; + } + + timeStamp->second = (sec_h<<16) | sec_l; + nano_second_8 = (nsec8_h<<16) | nsec8_l; + timeStamp->nano_second = nano_second_8<<3; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtl8367c_setAsicEavTrap + * Description: + * Set per-port PTP packet trap to CPU + * Input: + * port - Physical port number (0~5) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * If EAV trap enabled, switch will trap PTP packet to CPU + */ +ret_t rtl8367c_setAsicEavTrap(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicEavTimeSyncEn + * Description: + * Get per-port EPTP packet trap to CPU + * Input: + * port - Physical port number (0~5) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicEavTrap(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_PTP_PORT0_CFG1 + (port * 0x20), RTL8367C_PTP_PORT0_CFG1_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicEavEnable + * Description: + * Set per-port EAV function enable/disable + * Input: + * port - Physical port number (0~5) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * If EAV function is enabled, PTP event message packet will be attached PTP timestamp for trapping + */ +ret_t rtl8367c_setAsicEavEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicEavEnable + * Description: + * Get per-port EAV function enable/disable + * Input: + * port - Physical port number (0~5) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicEavEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port > RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_EAV_CTRL0, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicEavPriRemapping + * Description: + * Set non-EAV streaming priority remapping + * Input: + * srcpriority - Priority value + * priority - Absolute priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 priority) +{ + if(srcpriority > RTL8367C_PRIMAX || priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),priority); +} +/* Function Name: + * rtl8367c_getAsicEavPriRemapping + * Description: + * Get non-EAV streaming priority remapping + * Input: + * srcpriority - Priority value + * pPriority - Absolute priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicEavPriRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority) +{ + if(srcpriority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_EAV_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_EAV_PRIORITY_REMAPPING_MASK(srcpriority),pPriority); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c new file mode 100644 index 000000000000..f4dda6a6ae6d --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_eee.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 48989 $ + * $Date: 2014-07-01 15:45:24 +0800 (週二, 01 七月 2014) $ + * + * Purpose : RTL8370 switch high-level API for RTL8367C + * Feature : + * + */ + +#include +#include + +/* +@func ret_t | rtl8367c_setAsicEee100M | Set eee force mode function enable/disable. +@parm rtk_uint32 | port | The port number. +@parm rtk_uint32 | enabled | 1: enabled, 0: disabled. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input parameter. +@comm + This API set the 100M EEE enable function. + +*/ +ret_t rtl8367c_setAsicEee100M(rtk_uint32 port, rtk_uint32 enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if (enable > 1) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) + return retVal; + + if(enable) + regData |= (0x0001 << 1); + else + regData &= ~(0x0001 << 1); + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_getAsicEee100M | Get 100M eee enable/disable. +@parm rtk_uint32 | port | The port number. +@parm rtk_uint32* | enabled | 1: enabled, 0: disabled. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input parameter. +@comm + This API get the 100M EEE function. +*/ +ret_t rtl8367c_getAsicEee100M(rtk_uint32 port, rtk_uint32 *enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) + return retVal; + + *enable = (regData & (0x0001 << 1)) ? ENABLED : DISABLED; + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_setAsicEeeGiga | Set eee force mode function enable/disable. +@parm rtk_uint32 | port | The port number. +@parm rtk_uint32 | enabled | 1: enabled, 0: disabled. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input parameter. +@comm + This API set the 100M EEE enable function. + +*/ +ret_t rtl8367c_setAsicEeeGiga(rtk_uint32 port, rtk_uint32 enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if (enable > 1) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) + return retVal; + + if(enable) + regData |= (0x0001 << 2); + else + regData &= ~(0x0001 << 2); + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, regData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_getAsicEeeGiga | Get 100M eee enable/disable. +@parm rtk_uint32 | port | The port number. +@parm rtk_uint32* | enabled | 1: enabled, 0: disabled. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input parameter. +@comm + This API get the 100M EEE function. +*/ +ret_t rtl8367c_getAsicEeeGiga(rtk_uint32 port, rtk_uint32 *enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 regData; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, EEE_OCP_PHY_ADDR, ®Data)) != RT_ERR_OK) + return retVal; + + *enable = (regData & (0x0001 << 2)) ? ENABLED : DISABLED; + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c new file mode 100644 index 000000000000..b7b102243903 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_fc.c @@ -0,0 +1,1354 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Flow control related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicFlowControlSelect + * Description: + * Set system flow control type + * Input: + * select - System flow control type 1: Ingress flow control 0:Egress flow control + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSelect(rtk_uint32 select) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, select); +} +/* Function Name: + * rtl8367c_getAsicFlowControlSelect + * Description: + * Get system flow control type + * Input: + * pSelect - System flow control type 1: Ingress flow control 0:Egress flow control + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSelect(rtk_uint32 *pSelect) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_FLOWCTRL_TYPE_OFFSET, pSelect); +} +/* Function Name: + * rtl8367c_setAsicFlowControlJumboMode + * Description: + * Set Jumbo threshold for flow control + * Input: + * enabled - Jumbo mode flow control 1: Enable 0:Disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlJumboMode(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicFlowControlJumboMode + * Description: + * Get Jumbo threshold for flow control + * Input: + * pEnabled - Jumbo mode flow control 1: Enable 0:Disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlJumboMode(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_MODE_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicFlowControlJumboModeSize + * Description: + * Set Jumbo size for Jumbo mode flow control + * Input: + * size - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlJumboModeSize(rtk_uint32 size) +{ + if(size >= FC_JUMBO_SIZE_END) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, size); +} +/* Function Name: + * rtl8367c_getAsicFlowControlJumboModeSize + * Description: + * Get Jumbo size for Jumbo mode flow control + * Input: + * pSize - Jumbo size 0:3Kbytes 1:4Kbytes 2:6Kbytes 3:9Kbytes + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlJumboModeSize(rtk_uint32* pSize) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SIZE, RTL8367C_JUMBO_SIZE_MASK, pSize); +} + +/* Function Name: + * rtl8367c_setAsicFlowControlQueueEgressEnable + * Description: + * Set flow control ability for each queue + * Input: + * port - Physical port number (0~7) + * qid - Queue id + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, enabled); +} +/* Function Name: + * rtl8367c_getAsicFlowControlQueueEgressEnable + * Description: + * Get flow control ability for each queue + * Input: + * port - Physical port number (0~7) + * qid - Queue id + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlQueueEgressEnable(rtk_uint32 port, rtk_uint32 qid, rtk_uint32* pEnabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG(port), RTL8367C_FLOWCRTL_EGRESS_QUEUE_ENABLE_REG_OFFSET(port)+ qid, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicFlowControlDropAll + * Description: + * Set system-based drop parameters + * Input: + * dropall - Whole system drop threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlDropAll(rtk_uint32 dropall) +{ + if(dropall >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, dropall); +} +/* Function Name: + * rtl8367c_getAsicFlowControlDropAll + * Description: + * Get system-based drop parameters + * Input: + * pDropall - Whole system drop threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlDropAll(rtk_uint32* pDropall) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_CTRL0, RTL8367C_DROP_ALL_THRESHOLD_MASK, pDropall); +} +/* Function Name: + * rtl8367c_setAsicFlowControlPauseAll + * Description: + * Set system-based all ports enable flow control parameters + * Input: + * threshold - Whole system pause all threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPauseAllThreshold(rtk_uint32 threshold) +{ + if(threshold >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, threshold); +} +/* Function Name: + * rtl8367c_getAsicFlowControlPauseAllThreshold + * Description: + * Get system-based all ports enable flow control parameters + * Input: + * pThreshold - Whole system pause all threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPauseAllThreshold(rtk_uint32 *pThreshold) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_ALL_ON, RTL8367C_FLOWCTRL_ALL_ON_THRESHOLD_MASK, pThreshold); +} +/* Function Name: + * rtl8367c_setAsicFlowControlSystemThreshold + * Description: + * Set system-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSystemThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSystemThreshold + * Description: + * Get system-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSystemThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_OFF, RTL8367C_FLOWCTRL_SYS_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SYS_ON, RTL8367C_FLOWCTRL_SYS_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlSharedThreshold + * Description: + * Set share-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSharedThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSharedThreshold + * Description: + * Get share-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSharedThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_OFF, RTL8367C_FLOWCTRL_SHARE_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_SHARE_ON, RTL8367C_FLOWCTRL_SHARE_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortThreshold + * Description: + * Set Port-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortThreshold + * Description: + * Get Port-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_OFF, RTL8367C_FLOWCTRL_PORT_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_ON, RTL8367C_FLOWCTRL_PORT_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortPrivateThreshold + * Description: + * Set Port-private-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortPrivateThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortPrivateThreshold + * Description: + * Get Port-private-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortPrivateThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_PORT_PRIVATE_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_PORT_PRIVATE_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlSystemDropThreshold + * Description: + * Set system-based drop parameters + * Input: + * onThreshold - Drop turn ON threshold + * offThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSystemDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSystemDropThreshold + * Description: + * Get system-based drop parameters + * Input: + * pOnThreshold - Drop turn ON threshold + * pOffThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSystemDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_OFF, RTL8367C_FLOWCTRL_FCOFF_SYS_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SYS_ON, RTL8367C_FLOWCTRL_FCOFF_SYS_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlSharedDropThreshold + * Description: + * Set share-based fdrop parameters + * Input: + * onThreshold - Drop turn ON threshold + * offThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSharedDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, offThreshold); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSharedDropThreshold + * Description: + * Get share-based fdrop parameters + * Input: + * pOnThreshold - Drop turn ON threshold + * pOffThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSharedDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_OFF, RTL8367C_FLOWCTRL_FCOFF_SHARE_OFF_MASK, pOffThreshold); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_SHARE_ON, RTL8367C_FLOWCTRL_FCOFF_SHARE_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortDropThreshold + * Description: + * Set Port-based drop parameters + * Input: + * onThreshold - Drop turn ON threshold + * offThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortDropThreshold + * Description: + * Get Port-based drop parameters + * Input: + * pOnThreshold - Drop turn ON threshold + * pOffThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_OFF_MASK, pOffThreshold); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortPrivateDropThreshold + * Description: + * Set Port-private-based drop parameters + * Input: + * onThreshold - Drop turn ON threshold + * offThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortPrivateDropThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortPrivateDropThreshold + * Description: + * Get Port-private-based drop parameters + * Input: + * pOnThreshold - Drop turn ON threshold + * pOffThreshold - Drop turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortPrivateDropThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_OFF_MASK, pOffThreshold); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_FCOFF_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_FCOFF_PORT_PRIVATE_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlSystemJumboThreshold + * Description: + * Set Jumbo system-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSystemJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSystemJumboThreshold + * Description: + * Get Jumbo system-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSystemJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_OFF, RTL8367C_FLOWCTRL_JUMBO_SYS_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SYS_ON, RTL8367C_FLOWCTRL_JUMBO_SYS_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlSharedJumboThreshold + * Description: + * Set Jumbo share-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlSharedJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlSharedJumboThreshold + * Description: + * Get Jumbo share-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlSharedJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_OFF, RTL8367C_FLOWCTRL_JUMBO_SHARE_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_SHARE_ON, RTL8367C_FLOWCTRL_JUMBO_SHARE_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortJumboThreshold + * Description: + * Set Jumbo Port-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortJumboThreshold + * Description: + * Get Jumbo Port-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_ON_MASK, pOnThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicFlowControlPortPrivateJumboThreshold + * Description: + * Set Jumbo Port-private-based flow control parameters + * Input: + * onThreshold - Flow control turn ON threshold + * offThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 onThreshold, rtk_uint32 offThreshold) +{ + ret_t retVal; + + if((onThreshold >= RTL8367C_PAGE_NUMBER) || (offThreshold >= RTL8367C_PAGE_NUMBER)) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, offThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, onThreshold); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicFlowControlPortPrivateJumboThreshold + * Description: + * Get Jumbo Port-private-based flow control parameters + * Input: + * pOnThreshold - Flow control turn ON threshold + * pOffThreshold - Flow control turn OFF threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlPortPrivateJumboThreshold(rtk_uint32 *pOnThreshold, rtk_uint32 *pOffThreshold) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_OFF_MASK, pOffThreshold); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_JUMBO_PORT_PRIVATE_ON, RTL8367C_FLOWCTRL_JUMBO_PORT_PRIVATE_ON_MASK, pOnThreshold); + + return retVal; +} + + + +/* Function Name: + * rtl8367c_setAsicEgressFlowControlQueueDropThreshold + * Description: + * Set Queue-based egress flow control turn on or ingress flow control drop on threshold + * Input: + * qid - The queue id + * threshold - Queue-based flown control/drop turn ON threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_setAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 threshold) +{ + if( threshold >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, threshold); +} +/* Function Name: + * rtl8367c_getAsicEgressFlowControlQueueDropThreshold + * Description: + * Get Queue-based egress flow control turn on or ingress flow control drop on threshold + * Input: + * qid - The queue id + * pThreshold - Queue-based flown control/drop turn ON threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_getAsicEgressFlowControlQueueDropThreshold(rtk_uint32 qid, rtk_uint32 *pThreshold) +{ + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_QUEUE_DROP_ON_REG(qid), RTL8367C_FLOWCTRL_QUEUE_DROP_ON_MASK, pThreshold); +} +/* Function Name: + * rtl8367c_setAsicEgressFlowControlPortDropThreshold + * Description: + * Set port-based egress flow control turn on or ingress flow control drop on threshold + * Input: + * port - Physical port number (0~7) + * threshold - Queue-based flown control/drop turn ON threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 threshold) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(threshold >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, threshold); +} +/* Function Name: + * rtl8367c_setAsicEgressFlowControlPortDropThreshold + * Description: + * Set port-based egress flow control turn on or ingress flow control drop on threshold + * Input: + * port - Physical port number (0~7) + * pThreshold - Queue-based flown control/drop turn ON threshold + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicEgressFlowControlPortDropThreshold(rtk_uint32 port, rtk_uint32 *pThreshold) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_DROP_ON_REG(port), RTL8367C_FLOWCTRL_PORT_DROP_ON_MASK, pThreshold); +} +/* Function Name: + * rtl8367c_setAsicEgressFlowControlPortDropGap + * Description: + * Set port-based egress flow control turn off or ingress flow control drop off gap + * Input: + * gap - Flow control/drop turn OFF threshold = turn ON threshold - gap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicEgressFlowControlPortDropGap(rtk_uint32 gap) +{ + if(gap >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, gap); +} +/* Function Name: + * rtl8367c_getAsicEgressFlowControlPortDropGap + * Description: + * Get port-based egress flow control turn off or ingress flow control drop off gap + * Input: + * pGap - Flow control/drop turn OFF threshold = turn ON threshold - gap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEgressFlowControlPortDropGap(rtk_uint32 *pGap) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT_GAP, RTL8367C_FLOWCTRL_PORT_GAP_MASK, pGap); +} +/* Function Name: + * rtl8367c_setAsicEgressFlowControlQueueDropGap + * Description: + * Set Queue-based egress flow control turn off or ingress flow control drop off gap + * Input: + * gap - Flow control/drop turn OFF threshold = turn ON threshold - gap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicEgressFlowControlQueueDropGap(rtk_uint32 gap) +{ + if(gap >= RTL8367C_PAGE_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, gap); +} +/* Function Name: + * rtl8367c_getAsicEgressFlowControlQueueDropGap + * Description: + * Get Queue-based egress flow control turn off or ingress flow control drop off gap + * Input: + * pGap - Flow control/drop turn OFF threshold = turn ON threshold - gap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEgressFlowControlQueueDropGap(rtk_uint32 *pGap) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_QUEUE_GAP, RTL8367C_FLOWCTRL_QUEUE_GAP_MASK, pGap); +} +/* Function Name: + * rtl8367c_getAsicEgressQueueEmptyPortMask + * Description: + * Get queue empty port mask + * Input: + * pPortmask - Queue empty port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicEgressQueueEmptyPortMask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, pPortmask); +} +/* Function Name: + * rtl8367c_getAsicTotalPage + * Description: + * Get system total page usage number + * Input: + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTotalPage(rtk_uint32 *pPageCount) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_COUNTER, RTL8367C_FLOWCTRL_TOTAL_PAGE_COUNTER_MASK, pPageCount); +} +/* Function Name: + * rtl8367c_getAsicPulbicPage + * Description: + * Get system public page usage number + * Input: + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPulbicPage(rtk_uint32 *pPageCount) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_COUNTER, RTL8367C_FLOWCTRL_PUBLIC_PAGE_COUNTER_MASK, pPageCount); +} +/* Function Name: + * rtl8367c_getAsicMaxTotalPage + * Description: + * Get system total page max usage number + * Input: + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMaxTotalPage(rtk_uint32 *pPageCount) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_TOTAL_PAGE_MAX, RTL8367C_FLOWCTRL_TOTAL_PAGE_MAX_MASK, pPageCount); +} +/* Function Name: + * rtl8367c_getAsicPulbicPage + * Description: + * Get system public page max usage number + * Input: + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMaxPulbicPage(rtk_uint32 *pPageCount) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PUBLIC_PAGE_MAX, RTL8367C_FLOWCTRL_PUBLIC_PAGE_MAX_MASK, pPageCount); +} +/* Function Name: + * rtl8367c_getAsicPortPage + * Description: + * Get per-port page usage number + * Input: + * port - Physical port number (0~7) + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortPage(rtk_uint32 port, rtk_uint32 *pPageCount) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT8_PAGE_COUNTER+port - 8, RTL8367C_FLOWCTRL_PORT_PAGE_COUNTER_MASK, pPageCount); +} +/* Function Name: + * rtl8367c_getAsicPortPage + * Description: + * Get per-port page max usage number + * Input: + * port - Physical port number (0~7) + * pPageCount - page usage number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortPageMax(rtk_uint32 port, rtk_uint32 *pPageCount) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_FLOWCTRL_PORT_PAGE_MAX_REG(port), RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_FLOWCTRL_PORT0_PAGE_MAX+port-8, RTL8367C_FLOWCTRL_PORT_PAGE_MAX_MASK, pPageCount); + + +} + +/* Function Name: + * rtl8367c_setAsicFlowControlEgressPortIndep + * Description: + * Set per-port egress flow control independent + * Input: + * port - Physical port number (0~7) + * enabled - Egress port flow control usage 1:enable 0:disable. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 enable) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20), RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,enable); +} + +/* Function Name: + * rtl8367c_getAsicFlowControlEgressPortIndep + * Description: + * Get per-port egress flow control independent + * Input: + * port - Physical port number (0~7) + * enabled - Egress port flow control usage 1:enable 0:disable. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicFlowControlEgressPortIndep(rtk_uint32 port, rtk_uint32 *pEnable) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT0_MISC_CFG + (port *0x20),RTL8367C_PORT0_MISC_CFG_FLOWCTRL_INDEP_OFFSET,pEnable); +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c new file mode 100644 index 000000000000..3fb5f57b914b --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_green.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Green Ethernet related functions + * + */ +#include + +/* Function Name: + * rtl8367c_getAsicGreenPortPage + * Description: + * Get per-Port ingress page usage per second + * Input: + * port - Physical port number (0~7) + * pPage - page number of ingress packet occurring per second + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * Ingress traffic occurring page number per second for high layer green feature usage + */ +ret_t rtl8367c_getAsicGreenPortPage(rtk_uint32 port, rtk_uint32* pPage) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 pageMeter; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pageMeter = regData; + + retVal = rtl8367c_getAsicReg(RTL8367C_PAGEMETER_PORT_REG(port) + 1, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pageMeter = pageMeter + (regData << 16); + + *pPage = pageMeter; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicGreenTrafficType + * Description: + * Set traffic type for each priority + * Input: + * priority - internal priority (0~7) + * traffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32 traffictype) +{ + + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, (traffictype?1:0)); +} +/* Function Name: + * rtl8367c_getAsicGreenTrafficType + * Description: + * Get traffic type for each priority + * Input: + * priority - internal priority (0~7) + * pTraffictype - high/low traffic type, 1:high priority traffic type, 0:low priority traffic type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicGreenTrafficType(rtk_uint32 priority, rtk_uint32* pTraffictype) +{ + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_CFG, priority, pTraffictype); +} + +/* Function Name: + * rtl8367c_setAsicGreenHighPriorityTraffic + * Description: + * Set indicator which ASIC had received high priority traffic + * Input: + * port - Physical port number (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicGreenHighPriorityTraffic(rtk_uint32 port) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, 1); +} + + +/* Function Name: + * rtl8367c_getAsicGreenHighPriorityTraffic + * Description: + * Get indicator which ASIC had received high priority traffic or not + * Input: + * port - Physical port number (0~7) + * pIndicator - Have received high priority traffic indicator. If 1 means ASCI had received high priority in 1second checking period + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicGreenHighPriorityTraffic(rtk_uint32 port, rtk_uint32* pIndicator) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_HIGHPRI_INDICATOR, port, pIndicator); +} + +/* +@func rtk_int32 | rtl8367c_setAsicGreenEthernet | Set green Ethernet function. +@parm rtk_uint32 | green | Green feature function usage 1:enable 0:disable. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@comm + The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic + detect the cable length and then select different power mode for best performance with minimums power consumption. Link down + ports will enter power saving mode in 10 seconds after the cable disconnected if power saving function is enabled. +*/ +ret_t rtl8367c_setAsicGreenEthernet(rtk_uint32 port, rtk_uint32 green) +{ + ret_t retVal; + rtk_uint32 checkCounter; + rtk_uint32 regData; + rtk_uint32 phy_status; + rtk_uint32 patchData[6][2] = { {0x809A, 0x8911}, {0x80A3, 0x9233}, {0x80AC, 0xA444}, {0x809F, 0x6B20}, {0x80A8, 0x6B22}, {0x80B1, 0x6B23} }; + rtk_uint32 idx; + rtk_uint32 data; + + if (green > 1) + return RT_ERR_INPUT; + + /* 0xa420[2:0] */ + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA420, ®Data)) != RT_ERR_OK) + return retVal; + phy_status = (regData & 0x0007); + + if(phy_status == 3) + { + /* 0xb820[4] = 1 */ + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, ®Data)) != RT_ERR_OK) + return retVal; + + regData |= (0x0001 << 4); + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK) + return retVal; + + /* wait 0xb800[6] = 1 */ + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, ®Data); + if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) ) + { + checkCounter --; + if(0 == checkCounter) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + else + checkCounter = 0; + } + } + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, &data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (data) + { + case 0x0276: + case 0x0597: + case 0x6367: + if(green) + { + for(idx = 0; idx < 6; idx++ ) + { + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, patchData[idx][0])) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, patchData[idx][1])) != RT_ERR_OK) + return retVal; + } + } + break; + default: + break;; + } + + + + /* 0xa436 = 0x8011 */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK) + return retVal; + + /* wr 0xa438[15] = 0: disable, 1: enable */ + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, ®Data)) != RT_ERR_OK) + return retVal; + + if(green) + regData |= 0x8000; + else + regData &= 0x7FFF; + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA438, regData)) != RT_ERR_OK) + return retVal; + + if(phy_status == 3) + { + /* 0xb820[4] = 0 */ + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB820, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= ~(0x0001 << 4); + + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xB820, regData)) != RT_ERR_OK) + return retVal; + + /* wait 0xb800[6] = 0 */ + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicPHYOCPReg(port, 0xB800, ®Data); + if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) ) + { + checkCounter --; + if(0 == checkCounter) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + else + checkCounter = 0; + } + } + + return RT_ERR_OK; +} + +/* +@func rtk_int32 | rtl8367c_getAsicGreenEthernet | Get green Ethernet function. +@parm rtk_uint32 | *green | Green feature function usage 1:enable 0:disable. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@comm + The API can set Green Ethernet function to reduce power consumption. While green feature is enabled, ASIC will automatic + detect the cable length and then select different power mode for best performance with minimums power consumption. Link down + ports will enter power saving mode in 10 seconds after the cable disconnected if power saving function is enabled. +*/ +ret_t rtl8367c_getAsicGreenEthernet(rtk_uint32 port, rtk_uint32* green) +{ + ret_t retVal; + rtk_uint32 regData; + + /* 0xa436 = 0x8011 */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xA436, 0x8011)) != RT_ERR_OK) + return retVal; + + /* wr 0xa438[15] = 0: disable, 1: enable */ + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xA438, ®Data)) != RT_ERR_OK) + return retVal; + + if(regData & 0x8000) + *green = ENABLED; + else + *green = DISABLED; + + return RT_ERR_OK; +} + + +/* +@func ret_t | rtl8367c_setAsicPowerSaving | Set power saving mode +@parm rtk_uint32 | phy | phy number +@parm rtk_uint32 | enable | enable power saving mode. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_PORT_ID | Invalid port number. +@comm + The API can set power saving mode per phy. +*/ +ret_t rtl8367c_setAsicPowerSaving(rtk_uint32 phy, rtk_uint32 enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData; + rtk_uint32 regData; + rtk_uint32 phy_status; + rtk_uint32 checkCounter; + + if (enable > 1) + return RT_ERR_INPUT; + + /* 0xa420[2:0] */ + if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xA420, ®Data)) != RT_ERR_OK) + return retVal; + + phy_status = (regData & 0x0007); + + if(phy_status == 3) + { + /* 0xb820[4] = 1 */ + if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, ®Data)) != RT_ERR_OK) + return retVal; + + regData |= (0x0001 << 4); + + if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK) + return retVal; + + /* wait 0xb800[6] = 1 */ + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, ®Data); + if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0040) ) + { + checkCounter --; + if(0 == checkCounter) + { + return RT_ERR_BUSYWAIT_TIMEOUT; + } + } + else + checkCounter = 0; + } + } + + if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK) + return retVal; + + phyData = phyData & ~(0x0001 << 2); + phyData = phyData | (enable << 2); + + if ((retVal = rtl8367c_setAsicPHYReg(phy,PHY_POWERSAVING_REG,phyData))!=RT_ERR_OK) + return retVal; + + if(phy_status == 3) + { + /* 0xb820[4] = 0 */ + if((retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB820, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= ~(0x0001 << 4); + + if((retVal = rtl8367c_setAsicPHYOCPReg(phy, 0xB820, regData)) != RT_ERR_OK) + return retVal; + + /* wait 0xb800[6] = 0 */ + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicPHYOCPReg(phy, 0xB800, ®Data); + if( (retVal != RT_ERR_OK) || ((regData & 0x0040) != 0x0000) ) + { + checkCounter --; + if(0 == checkCounter) + { + return RT_ERR_BUSYWAIT_TIMEOUT; + } + } + else + checkCounter = 0; + } + } + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_getAsicPowerSaving | Get power saving mode +@parm rtk_uint32 | port | The port number +@parm rtk_uint32* | enable | enable power saving mode. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_PORT_ID | Invalid port number. +@comm + The API can get power saving mode per phy. +*/ +ret_t rtl8367c_getAsicPowerSaving(rtk_uint32 phy, rtk_uint32* enable) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyData; + + if(NULL == enable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPHYReg(phy,PHY_POWERSAVING_REG,&phyData))!=RT_ERR_OK) + return retVal; + + if ((phyData & 0x0004) > 0) + *enable = 1; + else + *enable = 0; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c new file mode 100644 index 000000000000..1b8ef59d9537 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_hsb.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Field selector related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicFieldSelector + * Description: + * Set user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * format - Format of field selector + * offset - Retrieving data offset + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * System support 16 user defined field selectors. + * Each selector can be enabled or disable. User can defined retrieving 16-bits in many predefiend + * standard l2/l3/l4 payload. + */ +ret_t rtl8367c_setAsicFieldSelector(rtk_uint32 index, rtk_uint32 format, rtk_uint32 offset) +{ + rtk_uint32 regData; + + if(index > RTL8367C_FIELDSEL_FORMAT_NUMBER) + return RT_ERR_OUT_OF_RANGE; + + if(format >= FIELDSEL_FORMAT_END) + return RT_ERR_OUT_OF_RANGE; + + regData = (((format << RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET) & RTL8367C_FIELD_SELECTOR_FORMAT_MASK ) | + ((offset << RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET) & RTL8367C_FIELD_SELECTOR_OFFSET_MASK )); + + return rtl8367c_setAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), regData); +} +/* Function Name: + * rtl8367c_getAsicFieldSelector + * Description: + * Get user defined field selectors in HSB + * Input: + * index - index of field selector 0-15 + * pFormat - Format of field selector + * pOffset - Retrieving data offset + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicFieldSelector(rtk_uint32 index, rtk_uint32* pFormat, rtk_uint32* pOffset) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicReg(RTL8367C_FIELD_SELECTOR_REG(index), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pFormat = ((regData & RTL8367C_FIELD_SELECTOR_FORMAT_MASK) >> RTL8367C_FIELD_SELECTOR_FORMAT_OFFSET); + *pOffset = ((regData & RTL8367C_FIELD_SELECTOR_OFFSET_MASK) >> RTL8367C_FIELD_SELECTOR_OFFSET_OFFSET); + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c new file mode 100644 index 000000000000..69f20a0188b5 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_i2c.c @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 38651 $ + * $Date: 2016-02-27 14:32:56 +0800 (周三, 17 四月 2016) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : I2C related functions + * + */ + + +#include +#include +#include + + + +/* Function Name: + * rtl8367c_setAsicI2C_checkBusIdle + * Description: + * Check i2c bus status idle or not + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_BUSYWAIT_TIMEOUT - i2c bus is busy + * Note: + * This API can check i2c bus status. + */ +ret_t rtl8367c_setAsicI2C_checkBusIdle(void) +{ + rtk_uint32 regData; + ret_t retVal; + + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_M_I2C_BUS_IDLE_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + + if(regData == 0x0001) + return RT_ERR_OK; /*i2c is idle*/ + else + return RT_ERR_BUSYWAIT_TIMEOUT; /*i2c is busy*/ +} + + +/* Function Name: + * rtl8367c_setAsicI2CStartCmd + * Description: + * Set I2C start command + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set i2c start command ,start a i2c traffic . + */ +ret_t rtl8367c_setAsicI2CStartCmd(void) +{ + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0000, Start Command; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x0001; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; +} + +/* Function Name: + * rtl8367c_setAsicI2CStopCmd + * Description: + * Set I2C stop command + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set i2c stop command ,stop a i2c traffic. + */ +ret_t rtl8367c_setAsicI2CStopCmd(void) +{ + + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0001, Stop Command; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x0003; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; +} + +/* Function Name: + * rtl8367c_setAsicI2CTxOneCharCmd + * Description: + * Set I2C Tx a char command, with a 8-bit data + * Input: + * oneChar - 8-bit data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set i2c Tx command and with a 8-bit data. + */ +ret_t rtl8367c_setAsicI2CTxOneCharCmd(rtk_uint8 oneChar) +{ + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0010, tx one char; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= 0xFFE0; + regData |= 0x0005; + regData &= 0x00FF; + regData |= (rtk_uint16) (oneChar << 8); + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; +} + + +/* Function Name: + * rtl8367c_setAsicI2CcheckRxAck + * Description: + * Check if rx an Ack + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can check if rx an ack from i2c slave. + */ +ret_t rtl8367c_setAsicI2CcheckRxAck(void) +{ + rtk_uint32 regData; + ret_t retVal; + rtk_uint32 count = 0; + + do{ + count++; + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_SLV_ACK_FLAG_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( (regData != 0x1) && (count < TIMEROUT_FOR_MICROSEMI) ); + + if(regData != 0x1) + return RT_ERR_FAILED; + else + return RT_ERR_OK; +} + + +/* Function Name: + * rtl8367c_setAsicI2CRxOneCharCmd + * Description: + * Set I2C Rx command and get 8-bit data + * Input: + * None + * Output: + * pValue - 8bit-data + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set I2C Rx command and get 8-bit data. + */ +ret_t rtl8367c_setAsicI2CRxOneCharCmd(rtk_uint8 *pValue) +{ + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0011, Rx one char; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x0007; + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + }while( (regData & 0x1) != 0x0); + + *pValue = (rtk_uint8)(regData >> 8); + return RT_ERR_OK ; + +} + +/* Function Name: + * rtl8367c_setAsicI2CTxAckCmd + * Description: + * Set I2C Tx ACK command + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set I2C Tx ack command. + */ +ret_t rtl8367c_setAsicI2CTxAckCmd(void) +{ + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0100, tx ACK Command; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x0009; + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; + +} + + +/* Function Name: + * rtl8367c_setAsicI2CTxNoAckCmd + * Description: + * Set I2C master Tx noACK command + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set I2C master Tx noACK command. + */ +ret_t rtl8367c_setAsicI2CTxNoAckCmd(void) +{ + rtk_uint32 regData; + ret_t retVal; + + /* Bits [4-1] = 0b0101, tx noACK Command; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x000b; + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; + +} + +/* Function Name: + * rtl8367c_setAsicI2CSoftRSTseqCmd + * Description: + * set I2C master tx soft reset command + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * Note: + * This API can set I2C master tx soft reset command. + */ +ret_t rtl8367c_setAsicI2CSoftRSTseqCmd(void) +{ + + rtk_uint32 regData; + ret_t retVal; + + /*Bits [4-1] = 0b0110, tx soft reset Command; Bit [0] = 1, Trigger the Command */ + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xFFE0; + regData |= 0x000d; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_CTL_STA_REG, regData)) != RT_ERR_OK) + return retVal; + + + /* wait for command finished */ + do{ + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_M_I2C_CTL_STA_REG, RTL8367C_I2C_CMD_EXEC_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + }while( regData != 0x0); + + return RT_ERR_OK ; +} + + +/* Function Name: + * rtl8367c_setAsicI2CGpioPinGroup + * Description: + * set I2C function used gpio pins + * Input: + * pinGroup_ID - gpio pins group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_INPUT _ Invalid input parameter + * Note: + * This API can set I2C function used gpio pins. + * There are three group gpio pins + */ +ret_t rtl8367c_setAsicI2CGpioPinGroup(rtk_uint32 pinGroup_ID) +{ + rtk_uint32 regData; + ret_t retVal; + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, ®Data)) != RT_ERR_OK) + return retVal; + if( pinGroup_ID==0 ) + { + regData &= 0x0FFF; + regData |= 0x5000; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) + return retVal; + } + + else if( pinGroup_ID==1 ) + { + regData &= 0x0FFF; + regData |= 0xA000; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) + return retVal; + } + + else if( pinGroup_ID==2 ) + { + regData &= 0x0FFF; + regData |= 0xF000; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, regData)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK ; + +} + +/* Function Name: + * rtl8367c_setAsicI2CGpioPinGroup + * Description: + * set I2C function used gpio pins + * Input: + * pinGroup_ID - gpio pins group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_INPUT _ Invalid input parameter + * Note: + * This API can set I2C function used gpio pins. + * There are three group gpio pins + */ +ret_t rtl8367c_getAsicI2CGpioPinGroup(rtk_uint32 * pPinGroup_ID) +{ + + rtk_uint32 regData; + ret_t retVal; + if( (retVal = rtl8367c_getAsicReg(RTL8367C_REG_M_I2C_SYS_CTL, ®Data)) != RT_ERR_OK) + return retVal; + regData &= 0xF000 ; + regData = (regData >> 12); + + if( regData == 0x5 ) + *pPinGroup_ID = 0; + else if(regData == 0xA) + *pPinGroup_ID = 1; + else if(regData == 0xF) + *pPinGroup_ID = 2; + else + return RT_ERR_FAILED; + return RT_ERR_OK ; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c new file mode 100644 index 000000000000..c915d2d61878 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_igmp.c @@ -0,0 +1,2109 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : IGMP related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicIgmp + * Description: + * Set IGMP/MLD state + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIgmp(rtk_uint32 enabled) +{ + ret_t retVal; + + /* Enable/Disable H/W IGMP/MLD */ + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, enabled); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicIgmp + * Description: + * Get IGMP/MLD state + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIgmp(rtk_uint32 *ptr_enabled) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_EN_OFFSET, ptr_enabled); + return retVal; +} +/* Function Name: + * rtl8367c_setAsicIpMulticastVlanLeaky + * Description: + * Set IP multicast VLAN Leaky function + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * When enabling this function, + * if the lookup result(forwarding portmap) of IP Multicast packet is over VLAN boundary, + * the packet can be forwarded across VLAN + */ +ret_t rtl8367c_setAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 enabled) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, enabled); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicIpMulticastVlanLeaky + * Description: + * Get IP multicast VLAN Leaky function + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicIpMulticastVlanLeaky(rtk_uint32 port, rtk_uint32 *ptr_enabled) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IPMCAST_VLAN_LEAKY, port, ptr_enabled); + + return retVal; +} + +/* Function Name: + * rtl8367c_setAsicIGMPTableFullOP + * Description: + * Set Table Full operation + * Input: + * operation - The operation should be taken when the IGMP table is full. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter is out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPTableFullOP(rtk_uint32 operation) +{ + ret_t retVal; + + if(operation >= TABLE_FULL_OP_END) + return RT_ERR_OUT_OF_RANGE; + + /* Table full Operation */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, operation); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPTableFullOP + * Description: + * Get Table Full operation + * Input: + * None + * Output: + * poperation - The operation should be taken when the IGMP table is full. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPTableFullOP(rtk_uint32 *poperation) +{ + ret_t retVal; + rtk_uint32 value; + + /* Table full Operation */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_TABLE_FULL_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *poperation = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPCRCErrOP + * Description: + * Set the operation when ASIC receive a Checksum error packet + * Input: + * operation -The operation when ASIC receive a Checksum error packet + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter is out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPCRCErrOP(rtk_uint32 operation) +{ + ret_t retVal; + + if(operation >= CRC_ERR_OP_END) + return RT_ERR_OUT_OF_RANGE; + + /* CRC Error Operation */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, operation); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPCRCErrOP + * Description: + * Get the operation when ASIC receive a Checksum error packet + * Input: + * None + * Output: + * poperation - The operation of Checksum error packet + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPCRCErrOP(rtk_uint32 *poperation) +{ + ret_t retVal; + rtk_uint32 value; + + /* CRC Error Operation */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_CKS_ERR_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *poperation = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPFastLeaveEn + * Description: + * Enable/Disable Fast Leave + * Input: + * enabled - 1:enable Fast Leave; 0:disable Fast Leave + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPFastLeaveEn(rtk_uint32 enabled) +{ + ret_t retVal; + + /* Fast Leave */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, (enabled >= 1) ? 1 : 0); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPFastLeaveEn + * Description: + * Get Fast Leave state + * Input: + * None + * Output: + * penabled - 1:enable Fast Leave; 0:disable Fast Leave + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPFastLeaveEn(rtk_uint32 *penabled) +{ + ret_t retVal; + rtk_uint32 value; + + /* Fast Leave */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_FAST_LEAVE_EN_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *penabled = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPLeaveTimer + * Description: + * Set the Leave timer of IGMP/MLD + * Input: + * leave_timer - Leave timer + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter is out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPLeaveTimer(rtk_uint32 leave_timer) +{ + ret_t retVal; + + if(leave_timer > RTL8367C_MAX_LEAVE_TIMER) + return RT_ERR_OUT_OF_RANGE; + + /* Leave timer */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, leave_timer); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPLeaveTimer + * Description: + * Get the Leave timer of IGMP/MLD + * Input: + * None + * Output: + * pleave_timer - Leave timer + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPLeaveTimer(rtk_uint32 *pleave_timer) +{ + ret_t retVal; + rtk_uint32 value; + + /* Leave timer */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_TIMER_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *pleave_timer = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPQueryInterval + * Description: + * Set Query Interval of IGMP/MLD + * Input: + * interval - Query Interval + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter is out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPQueryInterval(rtk_uint32 interval) +{ + ret_t retVal; + + if(interval > RTL8367C_MAX_QUERY_INT) + return RT_ERR_OUT_OF_RANGE; + + /* Query Interval */ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, interval); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPQueryInterval + * Description: + * Get Query Interval of IGMP/MLD + * Input: + * None + * Output: + * pinterval - Query Interval + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPQueryInterval(rtk_uint32 *pinterval) +{ + ret_t retVal; + rtk_uint32 value; + + /* Query Interval */ + retVal = rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG2, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *pinterval = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPRobVar + * Description: + * Set Robustness Variable of IGMP/MLD + * Input: + * rob_var - Robustness Variable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter is out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPRobVar(rtk_uint32 rob_var) +{ + ret_t retVal; + + if(rob_var > RTL8367C_MAX_ROB_VAR) + return RT_ERR_OUT_OF_RANGE; + + /* Robustness variable */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBUSTNESS_VAR_MASK, rob_var); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPRobVar + * Description: + * Get Robustness Variable of IGMP/MLD + * Input: + * none + * Output: + * prob_var - Robustness Variable + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPRobVar(rtk_uint32 *prob_var) +{ + ret_t retVal; + rtk_uint32 value; + + /* Robustness variable */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_ROBUSTNESS_VAR_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + + *prob_var = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPStaticRouterPort + * Description: + * Set IGMP static router port mask + * Input: + * pmsk - Static portmask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPStaticRouterPort(rtk_uint32 pmsk) +{ + if(pmsk > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk); +} + +/* Function Name: + * rtl8367c_getAsicIGMPStaticRouterPort + * Description: + * Get IGMP static router port mask + * Input: + * pmsk - Static portmask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPStaticRouterPort(rtk_uint32 *pmsk) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_STATIC_ROUTER_PORT, RTL8367C_IGMP_STATIC_ROUTER_PORT_MASK, pmsk); +} + +/* Function Name: + * rtl8367c_setAsicIGMPAllowDynamicRouterPort + * Description: + * Set IGMP dynamic router port allow mask + * Input: + * pmsk - Allow dynamic router port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPAllowDynamicRouterPort(rtk_uint32 pmsk) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pmsk); +} + +/* Function Name: + * rtl8367c_getAsicIGMPAllowDynamicRouterPort + * Description: + * Get IGMP dynamic router port allow mask + * Input: + * None. + * Output: + * pPmsk - Allow dynamic router port mask + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPAllowDynamicRouterPort(rtk_uint32 *pPmsk) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_IGMP_MLD_CFG4, pPmsk); +} + +/* Function Name: + * rtl8367c_getAsicIGMPdynamicRouterPort1 + * Description: + * Get 1st dynamic router port and timer + * Input: + * port - Physical port number (0~7) + * timer - router port timer + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPdynamicRouterPort1(rtk_uint32 *port, rtk_uint32 *timer) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_1_MASK, port); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_1_MASK, timer); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPdynamicRouterPort2 + * Description: + * Get 2nd dynamic router port and timer + * Input: + * port - Physical port number (0~7) + * timer - router port timer + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPdynamicRouterPort2(rtk_uint32 *port, rtk_uint32 *timer) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_2_MASK, port); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_DYNAMIC_ROUTER_PORT, RTL8367C_D_ROUTER_PORT_TMR_2_MASK, timer); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPSuppression + * Description: + * Set the suppression function + * Input: + * report_supp_enabled - Report suppression, 1:Enable, 0:disable + * leave_supp_enabled - Leave suppression, 1:Enable, 0:disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPSuppression(rtk_uint32 report_supp_enabled, rtk_uint32 leave_supp_enabled) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPSuppression + * Description: + * Get the suppression function + * Input: + * report_supp_enabled - Report suppression, 1:Enable, 0:disable + * leave_supp_enabled - Leave suppression, 1:Enable, 0:disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPSuppression(rtk_uint32 *report_supp_enabled, rtk_uint32 *leave_supp_enabled) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_REPORT_SUPPRESSION_MASK, report_supp_enabled); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_LEAVE_SUPPRESSION_MASK, leave_supp_enabled); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPQueryRX + * Description: + * Set port-based Query packet RX allowance + * Input: + * port - port number + * allow_query - allowance of Query packet RX, 1:Allow, 0:Drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 allow_query) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* Allow Query */ + if (port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, allow_query); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPQueryRX + * Description: + * Get port-based Query packet RX allowance + * Input: + * port - port number + * Output: + * allow_query - allowance of Query packet RX, 1:Allow, 0:Drop + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPQueryRX(rtk_uint32 port, rtk_uint32 *allow_query) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* Allow Query */ + if (port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_QUERY_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + *allow_query = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPReportRX + * Description: + * Set port-based Report packet RX allowance + * Input: + * port - port number + * allow_report - allowance of Report packet RX, 1:Allow, 0:Drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 allow_report) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + /* Allow Report */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, allow_report); + if(retVal != RT_ERR_OK) + return retVal; + } + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPReportRX + * Description: + * Get port-based Report packet RX allowance + * Input: + * port - port number + * Output: + * allow_report - allowance of Report packet RX, 1:Allow, 0:Drop + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPReportRX(rtk_uint32 port, rtk_uint32 *allow_report) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + /* Allow Report */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_REPORT_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + *allow_report = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPLeaveRX + * Description: + * Set port-based Leave packet RX allowance + * Input: + * port - port number + * allow_leave - allowance of Leave packet RX, 1:Allow, 0:Drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 allow_leave) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + /* Allow Leave */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, allow_leave); + if(retVal != RT_ERR_OK) + return retVal; + } + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPLeaveRX + * Description: + * Get port-based Leave packet RX allowance + * Input: + * port - port number + * Output: + * allow_leave - allowance of Leave packet RX, 1:Allow, 0:Drop + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPLeaveRX(rtk_uint32 port, rtk_uint32 *allow_leave) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + /* Allow Leave */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_LEAVE_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *allow_leave = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPMRPRX + * Description: + * Set port-based Multicast Routing Protocol packet RX allowance + * Input: + * port - port number + * allow_mrp - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 allow_mrp) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + /* Allow Multicast Routing Protocol */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, allow_mrp); + if(retVal != RT_ERR_OK) + return retVal; + } + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPMRPRX + * Description: + * Get port-based Multicast Routing Protocol packet RX allowance + * Input: + * port - port number + * Output: + * allow_mrp - allowance of Multicast Routing Protocol packet RX, 1:Allow, 0:Drop + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPMRPRX(rtk_uint32 port, rtk_uint32 *allow_mrp) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* Allow Multicast Routing Protocol */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MRP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + *allow_mrp = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPMcDataRX + * Description: + * Set port-based Multicast data packet RX allowance + * Input: + * port - port number + * allow_mcdata - allowance of Multicast data packet RX, 1:Allow, 0:Drop + * Output: + * none + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 allow_mcdata) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* Allow Multicast Data */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, allow_mcdata); + if(retVal != RT_ERR_OK) + return retVal; + } + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPMcDataRX + * Description: + * Get port-based Multicast data packet RX allowance + * Input: + * port - port number + * Output: + * allow_mcdata - allowance of Multicast data packet RX, 1:Allow, 0:Drop + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPMcDataRX(rtk_uint32 port, rtk_uint32 *allow_mcdata) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* Allow Multicast data */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_ALLOW_MC_DATA_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *allow_mcdata = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPv1Opeartion + * Description: + * Set port-based IGMPv1 Control packet action + * Input: + * port - port number + * igmpv1_op - IGMPv1 control packet action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 igmpv1_op) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(igmpv1_op >= PROTOCOL_OP_END) + return RT_ERR_INPUT; + + /* IGMPv1 operation */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, igmpv1_op); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPv1Opeartion + * Description: + * Get port-based IGMPv1 Control packet action + * Input: + * port - port number + * Output: + * igmpv1_op - IGMPv1 control packet action + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPv1Opeartion(rtk_uint32 port, rtk_uint32 *igmpv1_op) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* IGMPv1 operation */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV1_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *igmpv1_op = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPv2Opeartion + * Description: + * Set port-based IGMPv2 Control packet action + * Input: + * port - port number + * igmpv2_op - IGMPv2 control packet action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 igmpv2_op) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(igmpv2_op >= PROTOCOL_OP_END) + return RT_ERR_INPUT; + + /* IGMPv2 operation */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, igmpv2_op); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPv2Opeartion + * Description: + * Get port-based IGMPv2 Control packet action + * Input: + * port - port number + * Output: + * igmpv2_op - IGMPv2 control packet action + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPv2Opeartion(rtk_uint32 port, rtk_uint32 *igmpv2_op) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* IGMPv2 operation */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV2_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *igmpv2_op = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPv3Opeartion + * Description: + * Set port-based IGMPv3 Control packet action + * Input: + * port - port number + * igmpv3_op - IGMPv3 control packet action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 igmpv3_op) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(igmpv3_op >= PROTOCOL_OP_END) + return RT_ERR_INPUT; + + /* IGMPv3 operation */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, igmpv3_op); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPv3Opeartion + * Description: + * Get port-based IGMPv3 Control packet action + * Input: + * port - port number + * Output: + * igmpv3_op - IGMPv3 control packet action + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPv3Opeartion(rtk_uint32 port, rtk_uint32 *igmpv3_op) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* IGMPv3 operation */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_IGMPV3_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *igmpv3_op = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicMLDv1Opeartion + * Description: + * Set port-based MLDv1 Control packet action + * Input: + * port - port number + * mldv1_op - MLDv1 control packet action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 mldv1_op) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(mldv1_op >= PROTOCOL_OP_END) + return RT_ERR_INPUT; + + /* MLDv1 operation */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, mldv1_op); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicMLDv1Opeartion + * Description: + * Get port-based MLDv1 Control packet action + * Input: + * port - port number + * Output: + * mldv1_op - MLDv1 control packet action + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMLDv1Opeartion(rtk_uint32 port, rtk_uint32 *mldv1_op) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* MLDv1 operation */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv1_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *mldv1_op = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicMLDv2Opeartion + * Description: + * Set port-based MLDv2 Control packet action + * Input: + * port - port number + * mldv2_op - MLDv2 control packet action + * Output: + * none + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 mldv2_op) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(mldv2_op >= PROTOCOL_OP_END) + return RT_ERR_INPUT; + + /* MLDv2 operation */ + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, mldv2_op); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicMLDv2Opeartion + * Description: + * Get port-based MLDv2 Control packet action + * Input: + * port - port number + * Output: + * mldv2_op - MLDv2 control packet action + * Return: + * RT_ERR_OK - Success + * RT_ERR_PORT_ID - Error PORT ID + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMLDv2Opeartion(rtk_uint32 port, rtk_uint32 *mldv2_op) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + /* MLDv2 operation */ + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT0_CONTROL + port, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT8_CONTROL + port - 8, RTL8367C_IGMP_PORT0_CONTROL_MLDv2_OP_MASK, &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *mldv2_op = value; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPPortMAXGroup + * Description: + * Set per-port Max group number + * Input: + * port - Physical port number (0~7) + * max_group - max IGMP group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 max_group) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(max_group > RTL8367C_IGMP_MAX_GOUP) + return RT_ERR_OUT_OF_RANGE; + + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), max_group); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicIGMPPortMAXGroup + * Description: + * Get per-port Max group number + * Input: + * port - Physical port number (0~7) + * max_group - max IGMP group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPPortMAXGroup(rtk_uint32 port, rtk_uint32 *max_group) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_MAX_GROUP + (port/2), RTL8367C_PORT0_MAX_GROUP_MASK << (RTL8367C_PORT1_MAX_GROUP_OFFSET * (port%2)), &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *max_group = value; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicIGMPPortCurrentGroup + * Description: + * Get per-port current group number + * Input: + * port - Physical port number (0~7) + * current_group - current IGMP group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPPortCurrentGroup(rtk_uint32 port, rtk_uint32 *current_group) +{ + ret_t retVal; + rtk_uint32 value; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT01_CURRENT_GROUP + (port/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_PORT89_CURRENT_GROUP + ((port - 8)/2), RTL8367C_PORT0_CURRENT_GROUP_MASK << (RTL8367C_PORT1_CURRENT_GROUP_OFFSET * (port%2)), &value); + if(retVal != RT_ERR_OK) + return retVal; + } + + *current_group = value; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicIGMPGroup + * Description: + * Get IGMP group + * Input: + * idx - Group index (0~255) + * valid - valid bit + * grp - IGMP group + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Group index is out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPGroup(rtk_uint32 idx, rtk_uint32 *valid, rtl8367c_igmpgroup *grp) +{ + ret_t retVal; + rtk_uint32 regAddr, regData; + rtk_uint32 i; + rtk_uint32 groupInfo = 0; + + if(idx > RTL8367C_IGMP_MAX_GOUP) + return RT_ERR_OUT_OF_RANGE; + + /* Write ACS_ADR register for data bits */ + regAddr = RTL8367C_TABLE_ACCESS_ADDR_REG; + regData = idx; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write ACS_CMD register */ + regAddr = RTL8367C_TABLE_ACCESS_CTRL_REG; + regData = RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ, TB_TARGET_IGMP_GROUP); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Data Bits */ + regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE; + for(i = 0 ;i <= 1; i++) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + groupInfo |= ((regData & 0xFFFF) << (i * 16)); + regAddr ++; + } + + grp->p0_timer = groupInfo & 0x00000007; + grp->p1_timer = (groupInfo >> 3) & 0x00000007; + grp->p2_timer = (groupInfo >> 6) & 0x00000007; + grp->p3_timer = (groupInfo >> 9) & 0x00000007; + grp->p4_timer = (groupInfo >> 12) & 0x00000007; + grp->p5_timer = (groupInfo >> 15) & 0x00000007; + grp->p6_timer = (groupInfo >> 18) & 0x00000007; + grp->p7_timer = (groupInfo >> 21) & 0x00000007; + grp->report_supp_flag = (groupInfo >> 24) & 0x00000001; + grp->p8_timer = (groupInfo >> 25) & 0x00000007; + grp->p9_timer = (groupInfo >> 28) & 0x00000007; + grp->p10_timer = (groupInfo >> 31) & 0x00000001; + + regAddr = RTL8367C_TABLE_ACCESS_RDDATA_BASE + 2; + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + grp->p10_timer |= (regData & 0x00000003) << 1; + + /* Valid bit */ + retVal = rtl8367c_getAsicReg(RTL8367C_IGMP_GROUP_USAGE_REG(idx), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *valid = ((regData & (0x0001 << (idx %16))) != 0) ? 1 : 0; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicIpMulticastPortIsoLeaky + * Description: + * Set IP multicast Port Isolation leaky + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 enabled) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), enabled); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIpMulticastPortIsoLeaky + * Description: + * Get IP multicast Port Isolation leaky + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIpMulticastPortIsoLeaky(rtk_uint32 port, rtk_uint32 *enabled) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_IPMCAST_PORTISO_LEAKY_REG, (0x0001 << port), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *enabled = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPReportLeaveFlood + * Description: + * Set IGMP/MLD Report/Leave flood + * Input: + * flood - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPReportLeaveFlood(rtk_uint32 flood) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, flood); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPReportLeaveFlood + * Description: + * Get IGMP/MLD Report/Leave flood + * Input: + * None + * Output: + * pflood - 0: Reserved, 1: flooding to router ports, 2: flooding to all ports, 3: flooding to router port or to all ports if there is no router port + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPReportLeaveFlood(rtk_uint32 *pFlood) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_IGMP_MLD_CFG3, RTL8367C_REPORT_LEAVE_FORWARD_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pFlood = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPDropLeaveZero + * Description: + * Set the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * drop - 1: Drop, 0:Bypass + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPDropLeaveZero(rtk_uint32 drop) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, drop); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPDropLeaveZero + * Description: + * Get the function of dropping Leave packet with group IP = 0.0.0.0 + * Input: + * None + * Output: + * pDrop - 1: Drop, 0:Bypass + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPDropLeaveZero(rtk_uint32 *pDrop) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG1, RTL8367C_DROP_LEAVE_ZERO_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pDrop = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPBypassStormCTRL + * Description: + * Set the function of bypass storm control for IGMP/MLD packet + * Input: + * bypass - 1: Bypass, 0:not bypass + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPBypassStormCTRL(rtk_uint32 bypass) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, bypass); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPBypassStormCTRL + * Description: + * Set the function of bypass storm control for IGMP/MLD packet + * Input: + * None + * Output: + * pBypass - 1: Bypass, 0:not bypass + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPBypassStormCTRL(rtk_uint32 *pBypass) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_DISCARD_STORM_FILTER_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pBypass = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPIsoLeaky + * Description: + * Set Port Isolation leaky for IGMP/MLD packet + * Input: + * leaky - 1: Leaky, 0:not leaky + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPIsoLeaky(rtk_uint32 leaky) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, leaky); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPIsoLeaky + * Description: + * Get Port Isolation leaky for IGMP/MLD packet + * Input: + * None + * Output: + * pLeaky - 1: Leaky, 0:not leaky + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPIsoLeaky(rtk_uint32 *pLeaky) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_PORTISO_LEAKY_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pLeaky = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPVLANLeaky + * Description: + * Set VLAN leaky for IGMP/MLD packet + * Input: + * leaky - 1: Leaky, 0:not leaky + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPVLANLeaky(rtk_uint32 leaky) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, leaky); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPVLANLeaky + * Description: + * Get VLAN leaky for IGMP/MLD packet + * Input: + * None + * Output: + * pLeaky - 1: Leaky, 0:not leaky + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPVLANLeaky(rtk_uint32 *pLeaky) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG0, RTL8367C_IGMP_MLD_VLAN_LEAKY_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pLeaky = regData; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicIGMPBypassGroup + * Description: + * Set IGMP/MLD Bypass group + * Input: + * bypassType - Bypass type + * enabled - enabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 enabled) +{ + ret_t retVal; + rtk_uint32 offset; + + switch(bypassType) + { + case BYPASS_224_0_0_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET; + break; + case BYPASS_224_0_1_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET; + break; + case BYPASS_239_255_255_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET; + break; + case BYPASS_IPV6_00XX: + offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET; + break; + default: + return RT_ERR_INPUT; + } + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, enabled); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicIGMPBypassGroup + * Description: + * Get IGMP/MLD Bypass group + * Input: + * bypassType - Bypass type + * Output: + * pEnabled - enabled + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicIGMPBypassGroup(rtk_uint32 bypassType, rtk_uint32 *pEnabled) +{ + ret_t retVal; + rtk_uint32 offset; + + switch(bypassType) + { + case BYPASS_224_0_0_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_0_OFFSET; + break; + case BYPASS_224_0_1_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_224_0_1_OFFSET; + break; + case BYPASS_239_255_255_X: + offset = RTL8367C_IGMP_MLD_IP4_BYPASS_239_255_255_OFFSET; + break; + case BYPASS_IPV6_00XX: + offset = RTL8367C_IGMP_MLD_IP6_BYPASS_OFFSET; + break; + default: + return RT_ERR_INPUT; + } + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_IGMP_MLD_CFG3, offset, pEnabled); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c new file mode 100644 index 000000000000..13a7b14246a1 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_inbwctrl.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Ingress bandwidth control related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicPortIngressBandwidth + * Description: + * Set per-port total ingress bandwidth + * Input: + * port - Physical port number (0~7) + * bandwidth - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable + * preifg - Include preamble and IFG, 0:Exclude, 1:Include + * enableFC - Action when input rate exceeds. 0: Drop 1: Flow Control + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32 bandwidth, rtk_uint32 preifg, rtk_uint32 enableFC) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 regAddr; + + /* Invalid input parameter */ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(bandwidth > RTL8367C_QOS_GRANULARTY_MAX) + return RT_ERR_OUT_OF_RANGE; + + regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port); + regData = bandwidth & RTL8367C_QOS_GRANULARTY_LSB_MASK; + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr += 1; + regData = (bandwidth & RTL8367C_QOS_GRANULARTY_MSB_MASK) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET; + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_PORT_MISC_CFG_REG(port); + retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, preifg); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_PORT_MISC_CFG_REG(port); + retVal = rtl8367c_setAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, enableFC); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicPortIngressBandwidth + * Description: + * Get per-port total ingress bandwidth + * Input: + * port - Physical port number (0~7) + * pBandwidth - The total ingress bandwidth (unit: 8Kbps), 0x1FFFF:disable + * pPreifg - Include preamble and IFG, 0:Exclude, 1:Include + * pEnableFC - Action when input rate exceeds. 0: Drop 1: Flow Control + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortIngressBandwidth(rtk_uint32 port, rtk_uint32* pBandwidth, rtk_uint32* pPreifg, rtk_uint32* pEnableFC) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 regAddr; + + /* Invalid input parameter */ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + regAddr = RTL8367C_INGRESSBW_PORT_RATE_LSB_REG(port); + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pBandwidth = regData; + + regAddr += 1; + retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_INGRESSBW_PORT0_RATE_CTRL1_INGRESSBW_RATE16_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pBandwidth |= (regData << RTL8367C_QOS_GRANULARTY_MSB_OFFSET); + + regAddr = RTL8367C_PORT_MISC_CFG_REG(port); + retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_IFG_OFFSET, pPreifg); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_PORT_MISC_CFG_REG(port); + retVal = rtl8367c_getAsicRegBit(regAddr, RTL8367C_PORT0_MISC_CFG_INGRESSBW_FLOWCTRL_OFFSET, pEnableFC); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPortIngressBandwidthBypass + * Description: + * Set ingress bandwidth control bypass 8899, RMA 01-80-C2-00-00-xx and IGMP + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortIngressBandwidthBypass(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortIngressBandwidthBypass + * Description: + * Set ingress bandwidth control bypass 8899, RMA 01-80-C2-00-00-xx and IGMP + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortIngressBandwidthBypass(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_SW_DUMMY0, RTL8367C_INGRESSBW_BYPASS_EN_OFFSET, pEnabled); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c new file mode 100644 index 000000000000..1d5ccfc904ae --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_interrupt.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Interrupt related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicInterruptPolarity + * Description: + * Set interrupt trigger polarity + * Input: + * polarity - 0:pull high 1: pull low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicInterruptPolarity(rtk_uint32 polarity) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, polarity); +} +/* Function Name: + * rtl8367c_getAsicInterruptPolarity + * Description: + * Get interrupt trigger polarity + * Input: + * pPolarity - 0:pull high 1: pull low + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicInterruptPolarity(rtk_uint32* pPolarity) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_INTR_CTRL, RTL8367C_INTR_CTRL_OFFSET, pPolarity); +} +/* Function Name: + * rtl8367c_setAsicInterruptMask + * Description: + * Set interrupt enable mask + * Input: + * imr - Interrupt mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicInterruptMask(rtk_uint32 imr) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMR, imr); +} +/* Function Name: + * rtl8367c_getAsicInterruptMask + * Description: + * Get interrupt enable mask + * Input: + * pImr - Interrupt mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicInterruptMask(rtk_uint32* pImr) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMR, pImr); +} +/* Function Name: + * rtl8367c_setAsicInterruptMask + * Description: + * Clear interrupt enable mask + * Input: + * ims - Interrupt status mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * This API can be used to clear ASIC interrupt status and register will be cleared by writing 1. + * [0]:Link change, + * [1]:Share meter exceed, + * [2]:Learn number over, + * [3]:Speed Change, + * [4]:Tx special congestion + * [5]:1 second green feature + * [6]:loop detection + * [7]:interrupt from 8051 + * [8]:Cable diagnostic finish + * [9]:ACL action interrupt trigger + * [11]: Silent Start + */ +ret_t rtl8367c_setAsicInterruptStatus(rtk_uint32 ims) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_INTR_IMS, ims); +} +/* Function Name: + * rtl8367c_getAsicInterruptStatus + * Description: + * Get interrupt enable mask + * Input: + * pIms - Interrupt status mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicInterruptStatus(rtk_uint32* pIms) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_INTR_IMS, pIms); +} +/* Function Name: + * rtl8367c_setAsicInterruptRelatedStatus + * Description: + * Clear interrupt status + * Input: + * type - per port Learn over, per-port speed change, per-port special congest, share meter exceed status + * status - exceed status, write 1 to clear + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32 status) +{ + CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR, + RTL8367C_REG_SPEED_CHANGE_INDICATOR, + RTL8367C_REG_SPECIAL_CONGEST_INDICATOR, + RTL8367C_REG_PORT_LINKDOWN_INDICATOR, + RTL8367C_REG_PORT_LINKUP_INDICATOR, + RTL8367C_REG_METER_OVERRATE_INDICATOR0, + RTL8367C_REG_METER_OVERRATE_INDICATOR1, + RTL8367C_REG_RLDP_LOOPED_INDICATOR, + RTL8367C_REG_RLDP_RELEASED_INDICATOR, + RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR}; + + if(type >= INTRST_END ) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicReg(indicatorAddress[type], status); +} +/* Function Name: + * rtl8367c_getAsicInterruptRelatedStatus + * Description: + * Get interrupt status + * Input: + * type - per port Learn over, per-port speed change, per-port special congest, share meter exceed status + * pStatus - exceed status, write 1 to clear + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicInterruptRelatedStatus(rtk_uint32 type, rtk_uint32* pStatus) +{ + CONST rtk_uint32 indicatorAddress[INTRST_END] = {RTL8367C_REG_LEARN_OVER_INDICATOR, + RTL8367C_REG_SPEED_CHANGE_INDICATOR, + RTL8367C_REG_SPECIAL_CONGEST_INDICATOR, + RTL8367C_REG_PORT_LINKDOWN_INDICATOR, + RTL8367C_REG_PORT_LINKUP_INDICATOR, + RTL8367C_REG_METER_OVERRATE_INDICATOR0, + RTL8367C_REG_METER_OVERRATE_INDICATOR1, + RTL8367C_REG_RLDP_LOOPED_INDICATOR, + RTL8367C_REG_RLDP_RELEASED_INDICATOR, + RTL8367C_REG_SYSTEM_LEARN_OVER_INDICATOR}; + + if(type >= INTRST_END ) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_getAsicReg(indicatorAddress[type], pStatus); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c new file mode 100644 index 000000000000..6f2617f5aa02 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_led.c @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : LED related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicLedIndicateInfoConfig + * Description: + * Set Leds indicated information mode + * Input: + * ledno - LED group number. There are 1 to 1 led mapping to each port in each led group + * config - Support 16 types configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * The API can set LED indicated information configuration for each LED group with 1 to 1 led mapping to each port. + * Definition LED Statuses Description + * 0000 LED_Off LED pin Tri-State. + * 0001 Dup/Col Collision, Full duplex Indicator. Blinking every 43ms when collision happens. Low for full duplex, and high for half duplex mode. + * 0010 Link/Act Link, Activity Indicator. Low for link established. Link/Act Blinks every 43ms when the corresponding port is transmitting or receiving. + * 0011 Spd1000 1000Mb/s Speed Indicator. Low for 1000Mb/s. + * 0100 Spd100 100Mb/s Speed Indicator. Low for 100Mb/s. + * 0101 Spd10 10Mb/s Speed Indicator. Low for 10Mb/s. + * 0110 Spd1000/Act 1000Mb/s Speed/Activity Indicator. Low for 1000Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. + * 0111 Spd100/Act 100Mb/s Speed/Activity Indicator. Low for 100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. + * 1000 Spd10/Act 10Mb/s Speed/Activity Indicator. Low for 10Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. + * 1001 Spd100 (10)/Act 10/100Mb/s Speed/Activity Indicator. Low for 10/100Mb/s. Blinks every 43ms when the corresponding port is transmitting or receiving. + * 1010 Fiber Fiber link Indicator. Low for Fiber. + * 1011 Fault Auto-negotiation Fault Indicator. Low for Fault. + * 1100 Link/Rx Link, Activity Indicator. Low for link established. Link/Rx Blinks every 43ms when the corresponding port is transmitting. + * 1101 Link/Tx Link, Activity Indicator. Low for link established. Link/Tx Blinks every 43ms when the corresponding port is receiving. + * 1110 Master Link on Master Indicator. Low for link Master established. + * 1111 LED_Force Force LED output, LED output value reference + */ +ret_t rtl8367c_setAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32 config) +{ + ret_t retVal; + CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO] = {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK}; + + if(ledno >= RTL8367C_LEDGROUPNO) + return RT_ERR_OUT_OF_RANGE; + + if(config >= LEDCONF_END) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 0); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], config); +} +/* Function Name: + * rtl8367c_getAsicLedIndicateInfoConfig + * Description: + * Get Leds indicated information mode + * Input: + * ledno - LED group number. There are 1 to 1 led mapping to each port in each led group + * pConfig - Support 16 types configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicLedIndicateInfoConfig(rtk_uint32 ledno, rtk_uint32* pConfig) +{ + CONST rtk_uint16 bits[RTL8367C_LEDGROUPNO]= {RTL8367C_LED0_CFG_MASK, RTL8367C_LED1_CFG_MASK, RTL8367C_LED2_CFG_MASK}; + + if(ledno >= RTL8367C_LEDGROUPNO) + return RT_ERR_OUT_OF_RANGE; + + /* Get register value */ + return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, bits[ledno], pConfig); +} +/* Function Name: + * rtl8367c_setAsicLedGroupMode + * Description: + * Set Led Group mode + * Input: + * mode - LED mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicLedGroupMode(rtk_uint32 mode) +{ + ret_t retVal; + + /* Invalid input parameter */ + if(mode >= RTL8367C_LED_MODE_END) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, 1); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, mode); +} +/* Function Name: + * rtl8367c_getAsicLedGroupMode + * Description: + * Get Led Group mode + * Input: + * pMode - LED mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLedGroupMode(rtk_uint32* pMode) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_LED_CONFIG_SEL_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if(regData!=1) + return RT_ERR_FAILED; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_CONFIGURATION, RTL8367C_DATA_LED_MASK, pMode); +} +/* Function Name: + * rtl8367c_setAsicForceLeds + * Description: + * Set group LED mode + * Input: + * port - Physical port number (0~7) + * group - LED group number + * mode - LED mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32 mode) +{ + rtk_uint16 regAddr; + ret_t retVal; + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(group >= RTL8367C_LEDGROUPNO) + return RT_ERR_OUT_OF_RANGE; + + if(mode >= LEDFORCEMODE_END) + return RT_ERR_OUT_OF_RANGE; + /* Set Related Registers */ + if(port < 8){ + regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1); + if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << (port * 2), mode)) != RT_ERR_OK) + return retVal; + }else if(port >= 8){ + regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1); + if((retVal = rtl8367c_setAsicRegBits(regAddr, 0x3 << ((port-8) * 2), mode)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicForceLed + * Description: + * Get group LED mode + * Input: + * port - Physical port number (0~7) + * group - LED group number + * pMode - LED mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicForceLed(rtk_uint32 port, rtk_uint32 group, rtk_uint32* pMode) +{ + rtk_uint16 regAddr; + ret_t retVal; + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(group >= RTL8367C_LEDGROUPNO) + return RT_ERR_INPUT; + + /* Get Related Registers */ + if(port < 8){ + regAddr = RTL8367C_LED_FORCE_MODE_BASE + (group << 1); + if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << (port * 2), pMode)) != RT_ERR_OK) + return retVal; + }else if(port >= 8){ + regAddr = RTL8367C_REG_CPU_FORCE_LED0_CFG1 + (group << 1); + if((retVal = rtl8367c_getAsicRegBits(regAddr, 0x3 << ((port-8) * 2), pMode)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicForceGroupLed + * Description: + * Turn on/off Led of all ports + * Input: + * group - LED group number + * mode - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicForceGroupLed(rtk_uint32 groupmask, rtk_uint32 mode) +{ + ret_t retVal; + rtk_uint32 i,bitmask; + CONST rtk_uint16 bits[3]= {0x0004,0x0010,0x0040}; + + /* Invalid input parameter */ + if(groupmask > RTL8367C_LEDGROUPMASK) + return RT_ERR_OUT_OF_RANGE; + + if(mode >= LEDFORCEMODE_END) + return RT_ERR_OUT_OF_RANGE; + + bitmask = 0; + for(i = 0; i < RTL8367C_LEDGROUPNO; i++) + { + if(groupmask & (1 << i)) + { + bitmask = bitmask | bits[i]; + } + + } + + retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, bitmask); + + retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, mode); + + if(LEDFORCEMODE_NORMAL == mode) + retVal = rtl8367c_setAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, 0); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicForceGroupLed + * Description: + * Turn on/off Led of all ports + * Input: + * group - LED group number + * pMode - 0b00:normal mode, 0b01:force blink, 0b10:force off, 0b11:force on + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicForceGroupLed(rtk_uint32* groupmask, rtk_uint32* pMode) +{ + ret_t retVal; + rtk_uint32 i,regData; + CONST rtk_uint16 bits[3] = {0x0004,0x0010,0x0040}; + + /* Get Related Registers */ + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_LED_FORCE_MODE_MASK, ®Data)) != RT_ERR_OK) + return retVal; + + for(i = 0; i< RTL8367C_LEDGROUPNO; i++) + { + if((regData & bits[i]) == bits[i]) + { + *groupmask = *groupmask | (1 << i); + } + } + + return rtl8367c_getAsicRegBits(RTL8367C_LED_FORCE_CTRL, RTL8367C_FORCE_MODE_MASK, pMode); +} +/* Function Name: + * rtl8367c_setAsicLedBlinkRate + * Description: + * Set led blinking rate at mode 0 to mode 3 + * Input: + * blinkRate - Support 6 blink rates + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * LED blink rate can be at 43ms, 84ms, 120ms, 170ms, 340ms and 670ms + */ +ret_t rtl8367c_setAsicLedBlinkRate(rtk_uint32 blinkRate) +{ + if(blinkRate >= LEDBLINKRATE_END) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, blinkRate); +} +/* Function Name: + * rtl8367c_getAsicLedBlinkRate + * Description: + * Get led blinking rate at mode 0 to mode 3 + * Input: + * pBlinkRate - Support 6 blink rates + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLedBlinkRate(rtk_uint32* pBlinkRate) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_SEL_LEDRATE_MASK, pBlinkRate); +} +/* Function Name: + * rtl8367c_setAsicLedForceBlinkRate + * Description: + * Set LEd blinking rate for force mode led + * Input: + * blinkRate - Support 6 blink rates + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicLedForceBlinkRate(rtk_uint32 blinkRate) +{ + if(blinkRate >= LEDFORCERATE_END) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, blinkRate); +} +/* Function Name: + * rtl8367c_getAsicLedForceBlinkRate + * Description: + * Get LED blinking rate for force mode led + * Input: + * pBlinkRate - Support 6 blink rates + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLedForceBlinkRate(rtk_uint32* pBlinkRate) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_LED_MODE, RTL8367C_FORCE_RATE_MASK, pBlinkRate); +} + +/* +@func ret_t | rtl8367c_setAsicLedGroupEnable | Turn on/off Led of all system ports +@parm rtk_uint32 | group | LED group id. +@parm rtk_uint32 | portmask | LED port mask. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_PORT_ID | Invalid port number. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode. + */ +ret_t rtl8367c_setAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 portmask) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 regDataMask; + + if ( group >= RTL8367C_LEDGROUPNO ) + return RT_ERR_INPUT; + + regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2; + regDataMask = 0xFF << ((group%2)*8); + retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, portmask&0xff); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_REG_PARA_LED_IO_EN3; + regDataMask = 0x3 << (group*2); + retVal = rtl8367c_setAsicRegBits(regAddr, regDataMask, (portmask>>8)&0x7); + if(retVal != RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_getAsicLedGroupEnable | Get on/off status of Led of all system ports +@parm rtk_uint32 | group | LED group id. +@parm rtk_uint32 | *portmask | LED port mask. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_PORT_ID | Invalid port number. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can turn on/off leds of dedicated port while indicated information configuration of LED group is set to force mode. + */ +ret_t rtl8367c_getAsicLedGroupEnable(rtk_uint32 group, rtk_uint32 *portmask) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 regDataMask,regData; + + if ( group >= RTL8367C_LEDGROUPNO ) + return RT_ERR_INPUT; + + regAddr = RTL8367C_REG_PARA_LED_IO_EN1 + group/2; + regDataMask = 0xFF << ((group%2)*8); + retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, portmask); + if(retVal != RT_ERR_OK) + return retVal; + + + regAddr = RTL8367C_REG_PARA_LED_IO_EN3; + regDataMask = 0x3 << (group*2); + retVal = rtl8367c_getAsicRegBits(regAddr, regDataMask, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *portmask = (regData << 8) | *portmask; + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_setAsicLedOperationMode | Set LED operation mode +@parm rtk_uint32 | mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode) +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can turn on/off led serial mode and set signal to active high/low. + */ +ret_t rtl8367c_setAsicLedOperationMode(rtk_uint32 mode) +{ + ret_t retVal; + + /* Invalid input parameter */ + if( mode >= LEDOP_END) + return RT_ERR_INPUT; + + switch(mode) + { + case LEDOP_PARALLEL: + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 0))!= RT_ERR_OK) + return retVal; + /*Disable serial CLK mode*/ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 0))!= RT_ERR_OK) + return retVal; + /*Disable serial DATA mode*/ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 0))!= RT_ERR_OK) + return retVal; + break; + case LEDOP_SERIAL: + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, 1))!= RT_ERR_OK) + return retVal; + /*Enable serial CLK mode*/ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_CLK_EN_OFFSET, 1))!= RT_ERR_OK) + return retVal; + /*Enable serial DATA mode*/ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCAN0_LED_IO_EN1,RTL8367C_LED_SERI_DATA_EN_OFFSET, 1))!= RT_ERR_OK) + return retVal; + break; + default: + return RT_ERR_INPUT; + break; + } + + return RT_ERR_OK; +} + + +/* +@func ret_t | rtl8367c_getAsicLedOperationMode | Get LED OP mode setup +@parm rtk_uint32*| mode | LED mode. 1:scan mode 1, 2:parallel mode, 3:mdx mode (serial mode) +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can get LED serial mode setup and get signal active high/low. + */ +ret_t rtl8367c_getAsicLedOperationMode(rtk_uint32 *mode) +{ + ret_t retVal; + rtk_uint32 regData; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_SELECT_OFFSET, ®Data))!= RT_ERR_OK) + return retVal; + + if (regData == 1) + *mode = LEDOP_SERIAL; + else if (regData == 0) + *mode = LEDOP_PARALLEL; + else + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* +@func ret_t | rtl8367c_setAsicLedSerialModeConfig | Set LED serial mode +@parm rtk_uint32 | active | Active High or Low. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can turn on/off led serial mode and set signal to active high/low. + */ +ret_t rtl8367c_setAsicLedSerialModeConfig(rtk_uint32 active, rtk_uint32 serimode) +{ + ret_t retVal; + + /* Invalid input parameter */ + if( active >= LEDSERACT_MAX) + return RT_ERR_INPUT; + if( serimode >= LEDSER_MAX) + return RT_ERR_INPUT; + + /* Set Active High or Low */ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active)) != RT_ERR_OK) + return retVal; + + /*set to 8G mode (not 16G mode)*/ + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!= RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + + +/* +@func ret_t | rtl8367c_getAsicLedSerialModeConfig | Get LED serial mode setup +@parm rtk_uint32*| active | Active High or Low. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can get LED serial mode setup and get signal active high/low. + */ +ret_t rtl8367c_getAsicLedSerialModeConfig(rtk_uint32 *active, rtk_uint32 *serimode) +{ + ret_t retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_SERI_LED_ACT_LOW_OFFSET, active))!= RT_ERR_OK) + return retVal; + + /*get to 8G mode (not 16G mode)*/ + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_MODE, RTL8367C_DLINK_TIME_OFFSET, serimode))!= RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* +@func ret_t | rtl8367c_setAsicLedOutputEnable | Set LED output enable +@parm rtk_uint32 | enabled | enable or disable. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can turn on/off LED output Enable + */ +ret_t rtl8367c_setAsicLedOutputEnable(rtk_uint32 enabled) +{ + ret_t retVal; + rtk_uint32 regdata; + + if (enabled == 1) + regdata = 0; + else + regdata = 1; + + /* Enable/Disable H/W IGMP/MLD */ + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, regdata); + + return retVal; +} + + +/* +@func ret_t | rtl8367c_getAsicLedOutputEnable | Get LED serial mode setup +@parm rtk_uint32*| active | Active High or Low. +@rvalue RT_ERR_OK | Success. +@rvalue RT_ERR_SMI | SMI access error. +@rvalue RT_ERR_INPUT | Invalid input value. +@comm + The API can get LED serial mode setup and get signal active high/low. + */ +ret_t rtl8367c_getAsicLedOutputEnable(rtk_uint32 *ptr_enabled) +{ + ret_t retVal; + rtk_uint32 regdata; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LED_SYS_CONFIG, RTL8367C_LED_IO_DISABLE_OFFSET, ®data); + if (retVal != RT_ERR_OK) + return retVal; + + if (regdata == 1) + *ptr_enabled = 0; + else + *ptr_enabled = 1; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicLedSerialOutput + * Description: + * Set serial LED output group and portmask. + * Input: + * output - Serial LED output group + * pmask - Serial LED output portmask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicLedSerialOutput(rtk_uint32 output, rtk_uint32 pmask) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, output); + if (retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pmask); + if (retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicLedSerialOutput + * Description: + * Get serial LED output group and portmask. + * Input: + * None + * Output: + * pOutput - Serial LED output group + * pPmask - Serial LED output portmask + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicLedSerialOutput(rtk_uint32 *pOutput, rtk_uint32 *pPmask) +{ + ret_t retVal; + + if(pOutput == NULL) + return RT_ERR_NULL_POINTER; + + if(pPmask == NULL) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_GROUP_NUM_MASK, pOutput); + if (retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SERIAL_LED_CTRL, RTL8367C_SERIAL_LED_PORT_EN_MASK, pPmask); + if (retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c new file mode 100644 index 000000000000..1521467aa8b4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_lut.c @@ -0,0 +1,1549 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : LUT related functions + * + */ + +#include + +#include + +static void _rtl8367c_fdbStUser2Smi( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi) +{ + /* L3 lookup */ + if(pLutSt->l3lookup) + { + if(pLutSt->l3vidlookup) + { + pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF); + pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16; + + pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF); + pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16; + + pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; + pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13; + pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; + + pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); + pFdbSmi[4] |= (pLutSt->l3_vid & 0x00FF) << 8; + + pFdbSmi[5] |= ((pLutSt->l3_vid & 0x0F00) >> 8); + pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; + pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; + } + else + { + pFdbSmi[0] = (pLutSt->sip & 0x0000FFFF); + pFdbSmi[1] = (pLutSt->sip & 0xFFFF0000) >> 16; + + pFdbSmi[2] = (pLutSt->dip & 0x0000FFFF); + pFdbSmi[3] = (pLutSt->dip & 0x0FFF0000) >> 16; + + pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; + pFdbSmi[3] |= (pLutSt->l3vidlookup & 0x0001) << 13; + pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; + + pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); + pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8; + + pFdbSmi[5] |= (pLutSt->igmp_asic & 0x0001); + pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; + pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; + pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; + pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; + } + } + else if(pLutSt->mac.octet[0] & 0x01) /*Multicast L2 Lookup*/ + { + pFdbSmi[0] |= pLutSt->mac.octet[5]; + pFdbSmi[0] |= pLutSt->mac.octet[4] << 8; + + pFdbSmi[1] |= pLutSt->mac.octet[3]; + pFdbSmi[1] |= pLutSt->mac.octet[2] << 8; + + pFdbSmi[2] |= pLutSt->mac.octet[1]; + pFdbSmi[2] |= pLutSt->mac.octet[0] << 8; + + pFdbSmi[3] |= pLutSt->cvid_fid; + pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; + pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13; + pFdbSmi[3] |= ((pLutSt->mbr & 0x0300) >> 8) << 14; + + pFdbSmi[4] |= (pLutSt->mbr & 0x00FF); + pFdbSmi[4] |= (pLutSt->igmpidx & 0x00FF) << 8; + + pFdbSmi[5] |= pLutSt->igmp_asic; + pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; + pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; + pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; + pFdbSmi[5] |= ((pLutSt->mbr & 0x0400) >> 10) << 7; + } + else /*Asic auto-learning*/ + { + pFdbSmi[0] |= pLutSt->mac.octet[5]; + pFdbSmi[0] |= pLutSt->mac.octet[4] << 8; + + pFdbSmi[1] |= pLutSt->mac.octet[3]; + pFdbSmi[1] |= pLutSt->mac.octet[2] << 8; + + pFdbSmi[2] |= pLutSt->mac.octet[1]; + pFdbSmi[2] |= pLutSt->mac.octet[0] << 8; + + pFdbSmi[3] |= pLutSt->cvid_fid; + pFdbSmi[3] |= (pLutSt->l3lookup & 0x0001) << 12; + pFdbSmi[3] |= (pLutSt->ivl_svl & 0x0001) << 13; + pFdbSmi[3] |= ((pLutSt->spa & 0x0008) >> 3) << 15; + + pFdbSmi[4] |= pLutSt->efid; + pFdbSmi[4] |= (pLutSt->fid & 0x000F) << 3; + pFdbSmi[4] |= (pLutSt->sa_en & 0x0001) << 7; + pFdbSmi[4] |= (pLutSt->spa & 0x0007) << 8; + pFdbSmi[4] |= (pLutSt->age & 0x0007) << 11; + pFdbSmi[4] |= (pLutSt->auth & 0x0001) << 14; + pFdbSmi[4] |= (pLutSt->sa_block & 0x0001) << 15; + + pFdbSmi[5] |= pLutSt->da_block; + pFdbSmi[5] |= (pLutSt->lut_pri & 0x0007) << 1; + pFdbSmi[5] |= (pLutSt->fwd_en & 0x0001) << 4; + pFdbSmi[5] |= (pLutSt->nosalearn & 0x0001) << 5; + } +} + + +static void _rtl8367c_fdbStSmi2User( rtl8367c_luttb *pLutSt, rtk_uint16 *pFdbSmi) +{ + /*L3 lookup*/ + if(pFdbSmi[3] & 0x1000) + { + if(pFdbSmi[3] & 0x2000) + { + pLutSt->sip = pFdbSmi[0] | (pFdbSmi[1] << 16); + pLutSt->dip = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16); + + pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); + pLutSt->l3_vid = ((pFdbSmi[4] & 0xFF00) >> 8) | (pFdbSmi[5] & 0x000F); + + pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; + pLutSt->l3vidlookup = (pFdbSmi[3] & 0x2000) >> 13; + pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; + } + else + { + pLutSt->sip = pFdbSmi[0] | (pFdbSmi[1] << 16); + pLutSt->dip = pFdbSmi[2] | ((pFdbSmi[3] & 0x0FFF) << 16); + + pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; + pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; + + pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); + pLutSt->igmpidx = (pFdbSmi[4] & 0xFF00) >> 8; + + pLutSt->igmp_asic = (pFdbSmi[5] & 0x0001); + pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; + pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; + } + } + else if(pFdbSmi[2] & 0x0100) /*Multicast L2 Lookup*/ + { + pLutSt->mac.octet[0] = (pFdbSmi[2] & 0xFF00) >> 8; + pLutSt->mac.octet[1] = (pFdbSmi[2] & 0x00FF); + pLutSt->mac.octet[2] = (pFdbSmi[1] & 0xFF00) >> 8; + pLutSt->mac.octet[3] = (pFdbSmi[1] & 0x00FF); + pLutSt->mac.octet[4] = (pFdbSmi[0] & 0xFF00) >> 8; + pLutSt->mac.octet[5] = (pFdbSmi[0] & 0x00FF); + + pLutSt->cvid_fid = pFdbSmi[3] & 0x0FFF; + pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; + pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; + + pLutSt->mbr = (pFdbSmi[4] & 0x00FF) | (((pFdbSmi[3] & 0xC000) >> 14) << 8) | (((pFdbSmi[5] & 0x0080) >> 7) << 10); + pLutSt->igmpidx = (pFdbSmi[4] & 0xFF00) >> 8; + + pLutSt->igmp_asic = (pFdbSmi[5] & 0x0001); + pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; + pLutSt->ivl_svl = (pFdbSmi[3] & 0x2000) >> 13; + pLutSt->nosalearn = (pFdbSmi[5] & 0x0020) >> 5; + } + else /*Asic auto-learning*/ + { + pLutSt->mac.octet[0] = (pFdbSmi[2] & 0xFF00) >> 8; + pLutSt->mac.octet[1] = (pFdbSmi[2] & 0x00FF); + pLutSt->mac.octet[2] = (pFdbSmi[1] & 0xFF00) >> 8; + pLutSt->mac.octet[3] = (pFdbSmi[1] & 0x00FF); + pLutSt->mac.octet[4] = (pFdbSmi[0] & 0xFF00) >> 8; + pLutSt->mac.octet[5] = (pFdbSmi[0] & 0x00FF); + + pLutSt->cvid_fid = pFdbSmi[3] & 0x0FFF; + pLutSt->lut_pri = (pFdbSmi[5] & 0x000E) >> 1; + pLutSt->fwd_en = (pFdbSmi[5] & 0x0010) >> 4; + + pLutSt->sa_en = (pFdbSmi[4] & 0x0080) >> 7; + pLutSt->auth = (pFdbSmi[4] & 0x4000) >> 14; + pLutSt->spa = ((pFdbSmi[4] & 0x0700) >> 8) | (((pFdbSmi[3] & 0x8000) >> 15) << 3); + pLutSt->age = (pFdbSmi[4] & 0x3800) >> 11; + pLutSt->fid = (pFdbSmi[4] & 0x0078) >> 3; + pLutSt->efid = (pFdbSmi[4] & 0x0007); + pLutSt->sa_block = (pFdbSmi[4] & 0x8000) >> 15; + + pLutSt->da_block = (pFdbSmi[5] & 0x0001); + pLutSt->l3lookup = (pFdbSmi[3] & 0x1000) >> 12; + pLutSt->ivl_svl = (pFdbSmi[3] & 0x2000) >> 13; + pLutSt->nosalearn = (pFdbSmi[3] & 0x0020) >> 5; + } +} + +/* Function Name: + * rtl8367c_setAsicLutIpMulticastLookup + * Description: + * Set LUT IP multicast lookup function + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutIpMulticastLookup(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicLutIpMulticastLookup + * Description: + * Get LUT IP multicast lookup function + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutIpMulticastLookup(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_HASH_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicLutIpMulticastLookup + * Description: + * Set LUT IP multicast + VID lookup function + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutIpMulticastVidLookup(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, enabled); +} + +/* Function Name: + * rtl8367c_getAsicLutIpMulticastVidLookup + * Description: + * Get LUT IP multicast lookup function + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutIpMulticastVidLookup(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_VID_HASH_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicLutIpLookupMethod + * Description: + * Set LUT IP lookup hash with DIP or {DIP,SIP} pair + * Input: + * type - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash. + * 0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutIpLookupMethod(rtk_uint32 type) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, type); +} +/* Function Name: + * rtl8367c_getAsicLutIpLookupMethod + * Description: + * Get LUT IP lookup hash with DIP or {DIP,SIP} pair + * Input: + * pType - 1: When DIP can be found in IPMC_GROUP_TABLE, use DIP+SIP Hash, otherwise, use DIP+(SIP=0.0.0.0) Hash. + * 0: When DIP can be found in IPMC_GROUP_TABLE, use DIP+(SIP=0.0.0.0) Hash, otherwise use DIP+SIP Hash. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutIpLookupMethod(rtk_uint32* pType) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LUT_IPMC_LOOKUP_OP_OFFSET, pType); +} +/* Function Name: + * rtl8367c_setAsicLutAgeTimerSpeed + * Description: + * Set LUT ageing out speed + * Input: + * timer - Ageing out timer 0:Has been aged out + * speed - Ageing out speed 0-fastest 3-slowest + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicLutAgeTimerSpeed(rtk_uint32 timer, rtk_uint32 speed) +{ + if(timer>RTL8367C_LUT_AGETIMERMAX) + return RT_ERR_OUT_OF_RANGE; + + if(speed >RTL8367C_LUT_AGESPEEDMAX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_CFG, RTL8367C_AGE_TIMER_MASK | RTL8367C_AGE_SPEED_MASK, (timer << RTL8367C_AGE_TIMER_OFFSET) | (speed << RTL8367C_AGE_SPEED_OFFSET)); +} +/* Function Name: + * rtl8367c_getAsicLutAgeTimerSpeed + * Description: + * Get LUT ageing out speed + * Input: + * pTimer - Ageing out timer 0:Has been aged out + * pSpeed - Ageing out speed 0-fastest 3-slowest + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicLutAgeTimerSpeed(rtk_uint32* pTimer, rtk_uint32* pSpeed) +{ + rtk_uint32 regData; + ret_t retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_LUT_CFG, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pTimer = (regData & RTL8367C_AGE_TIMER_MASK) >> RTL8367C_AGE_TIMER_OFFSET; + + *pSpeed = (regData & RTL8367C_AGE_SPEED_MASK) >> RTL8367C_AGE_SPEED_OFFSET; + + return RT_ERR_OK; + +} +/* Function Name: + * rtl8367c_setAsicLutCamTbUsage + * Description: + * Configure LUT CAM table usage + * Input: + * enabled - L2 CAM table usage 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutCamTbUsage(rtk_uint32 enabled) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, enabled ? 0 : 1); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicLutCamTbUsage + * Description: + * Get LUT CAM table usage + * Input: + * pEnabled - L2 CAM table usage 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutCamTbUsage(rtk_uint32* pEnabled) +{ + ret_t retVal; + rtk_uint32 regData; + + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_BCAM_DISABLE_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + + *pEnabled = regData ? 0 : 1; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicLutLearnLimitNo + * Description: + * Set per-Port auto learning limit number + * Input: + * port - Physical port number (0~7) + * number - ASIC auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * None + */ + /*modification: RTL8367C_PORTIDMAX, RTL8367C_LUT_LEARNLIMITMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/ +ret_t rtl8367c_setAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32 number) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(number > RTL8367C_LUT_LEARNLIMITMAX) + return RT_ERR_LIMITED_L2ENTRY_NUM; + + if(port < 8) + return rtl8367c_setAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), number); + else + return rtl8367c_setAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, number); + +} +/* Function Name: + * rtl8367c_getAsicLutLearnLimitNo + * Description: + * Get per-Port auto learning limit number + * Input: + * port - Physical port number (0~7) + * pNumber - ASIC auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ + /*modification: RTL8367C_PORTIDMAX, RTL8367C_LUT_PORT_LEARN_LIMITNO_REG*/ +ret_t rtl8367c_getAsicLutLearnLimitNo(rtk_uint32 port, rtk_uint32* pNumber) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicReg(RTL8367C_LUT_PORT_LEARN_LIMITNO_REG(port), pNumber); + else + return rtl8367c_getAsicReg(RTL8367C_REG_LUT_PORT8_LEARN_LIMITNO+port-8, pNumber); +} + +/* Function Name: + * rtl8367c_setAsicSystemLutLearnLimitNo + * Description: + * Set system auto learning limit number + * Input: + * number - ASIC auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_LIMITED_L2ENTRY_NUM - Invalid auto learning limit number + * Note: + * None + */ + /*modification: RTL8367C_LUT_LEARNLIMITMAX*/ +ret_t rtl8367c_setAsicSystemLutLearnLimitNo(rtk_uint32 number) +{ + if(number > RTL8367C_LUT_LEARNLIMITMAX) + return RT_ERR_LIMITED_L2ENTRY_NUM; + + return rtl8367c_setAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, number); +} + +/* Function Name: + * rtl8367c_getAsicSystemLutLearnLimitNo + * Description: + * Get system auto learning limit number + * Input: + * port - Physical port number (0~7) + * pNumber - ASIC auto learning entries limit number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicSystemLutLearnLimitNo(rtk_uint32 *pNumber) +{ + if(NULL == pNumber) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicReg(RTL8367C_REG_LUT_SYS_LEARN_LIMITNO, pNumber); +} + +/* Function Name: + * rtl8367c_setAsicLutLearnOverAct + * Description: + * Set auto learn over limit number action + * Input: + * action - Learn over action 0:normal, 1:drop 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * None + */ +ret_t rtl8367c_setAsicLutLearnOverAct(rtk_uint32 action) +{ + if(action >= LRNOVERACT_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, action); +} +/* Function Name: + * rtl8367c_getAsicLutLearnOverAct + * Description: + * Get auto learn over limit number action + * Input: + * pAction - Learn over action 0:normal, 1:drop 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutLearnOverAct(rtk_uint32* pAction) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_SECURITY_CTRL, RTL8367C_LUT_LEARN_OVER_ACT_MASK, pAction); +} + +/* Function Name: + * rtl8367c_setAsicSystemLutLearnOverAct + * Description: + * Set system auto learn over limit number action + * Input: + * action - Learn over action 0:normal, 1:drop, 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid learn over action + * Note: + * None + */ +ret_t rtl8367c_setAsicSystemLutLearnOverAct(rtk_uint32 action) +{ + if(action >= LRNOVERACT_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, action); +} + +/* Function Name: + * rtl8367c_getAsicSystemLutLearnOverAct + * Description: + * Get system auto learn over limit number action + * Input: + * pAction - Learn over action 0:normal, 1:drop 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSystemLutLearnOverAct(rtk_uint32 *pAction) +{ + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_OVER_ACT_MASK, pAction); +} + +/* Function Name: + * rtl8367c_setAsicSystemLutLearnPortMask + * Description: + * Set system auto learn limit port mask + * Input: + * portmask - port mask of system learning limit + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Error port mask + * Note: + * None + */ + /*modification: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/ +ret_t rtl8367c_setAsicSystemLutLearnPortMask(rtk_uint32 portmask) +{ + ret_t retVal; + + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, (portmask>>8) & 0x7); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtl8367c_getAsicSystemLutLearnPortMask + * Description: + * Get system auto learn limit port mask + * Input: + * None + * Output: + * pPortmask - port mask of system learning limit + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * None + */ + /*modification: RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK*/ +ret_t rtl8367c_getAsicSystemLutLearnPortMask(rtk_uint32 *pPortmask) +{ + rtk_uint32 tmpmask; + ret_t retVal; + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK_MASK, &tmpmask); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask = tmpmask & 0xff; + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_LUT_LRN_SYS_LMT_CTRL, RTL8367C_LUT_SYSTEM_LEARN_PMASK1_MASK, &tmpmask); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask |= (tmpmask & 0x7) << 8; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicL2LookupTb + * Description: + * Set filtering database entry + * Input: + * pL2Table - L2 table entry writing to 8K+64 filtering database + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicL2LookupTb(rtl8367c_luttb *pL2Table) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE]; + rtk_uint32 tblCmd; + rtk_uint32 busyCounter; + + memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); + _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table); + + if(pL2Table->wait_time == 0) + busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; + else + busyCounter = pL2Table->wait_time; + + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->lookup_busy = regData; + if(!regData) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + accessPtr = smil2Table; + regData = *accessPtr; + for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr ++; + regData = *accessPtr; + + } + + tblCmd = (RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK); + /* Write Command */ + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd); + if(retVal != RT_ERR_OK) + return retVal; + + if(pL2Table->wait_time == 0) + busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; + else + busyCounter = pL2Table->wait_time; + + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->lookup_busy = regData; + if(!regData) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + /*Read access status*/ + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->lookup_hit = regData; + if(!pL2Table->lookup_hit) + return RT_ERR_FAILED; + + /*Read access address*/ + /* + retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->address = regData;*/ + + retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1); + pL2Table->lookup_busy = 0; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicL2LookupTb + * Description: + * Get filtering database entry + * Input: + * pL2Table - L2 table entry writing to 2K+64 filtering database + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving + * Note: + * None + */ +ret_t rtl8367c_getAsicL2LookupTb(rtk_uint32 method, rtl8367c_luttb *pL2Table) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16* accessPtr; + rtk_uint32 i; + rtk_uint16 smil2Table[RTL8367C_LUT_TABLE_SIZE]; + rtk_uint32 busyCounter; + rtk_uint32 tblCmd; + + if(pL2Table->wait_time == 0) + busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; + else + busyCounter = pL2Table->wait_time; + + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->lookup_busy = regData; + if(!pL2Table->lookup_busy) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + + tblCmd = (method << RTL8367C_ACCESS_METHOD_OFFSET) & RTL8367C_ACCESS_METHOD_MASK; + + switch(method) + { + case LUTREADMETHOD_ADDRESS: + case LUTREADMETHOD_NEXT_ADDRESS: + case LUTREADMETHOD_NEXT_L2UC: + case LUTREADMETHOD_NEXT_L2MC: + case LUTREADMETHOD_NEXT_L3MC: + case LUTREADMETHOD_NEXT_L2L3MC: + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, pL2Table->address); + if(retVal != RT_ERR_OK) + return retVal; + break; + case LUTREADMETHOD_MAC: + memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); + _rtl8367c_fdbStUser2Smi(pL2Table, smil2Table); + + accessPtr = smil2Table; + regData = *accessPtr; + for(i=0; iaddress); + if(retVal != RT_ERR_OK) + return retVal; + + tblCmd = tblCmd | ((pL2Table->spa << RTL8367C_TABLE_ACCESS_CTRL_SPA_OFFSET) & RTL8367C_TABLE_ACCESS_CTRL_SPA_MASK); + + break; + default: + return RT_ERR_INPUT; + } + + tblCmd = tblCmd | ((RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_L2)) & (RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK)); + /* Read Command */ + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_CTRL_REG, tblCmd); + if(retVal != RT_ERR_OK) + return retVal; + + if(pL2Table->wait_time == 0) + busyCounter = RTL8367C_LUT_BUSY_CHECK_NO; + else + busyCounter = pL2Table->wait_time; + + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->lookup_busy = regData; + if(!pL2Table->lookup_busy) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_HIT_STATUS_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + pL2Table->lookup_hit = regData; + if(!pL2Table->lookup_hit) + return RT_ERR_L2_ENTRY_NOTFOUND; + + /*Read access address*/ + //retVal = rtl8367c_getAsicRegBits(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_TYPE_MASK | RTL8367C_TABLE_LUT_ADDR_ADDRESS_MASK,®Data); + retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_STATUS_REG, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pL2Table->address = (regData & 0x7ff) | ((regData & 0x4000) >> 3) | ((regData & 0x800) << 1); + + /*read L2 entry */ + memset(smil2Table, 0x00, sizeof(rtk_uint16) * RTL8367C_LUT_TABLE_SIZE); + + accessPtr = smil2Table; + + for(i = 0; i < RTL8367C_LUT_ENTRY_SIZE; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + + accessPtr ++; + } + + _rtl8367c_fdbStSmi2User(pL2Table, smil2Table); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicLutLearnNo + * Description: + * Get per-Port auto learning number + * Input: + * port - Physical port number (0~7) + * pNumber - ASIC auto learning entries number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ + /*modification:RTL8367C_PORTIDMAX, RTL8367C_REG_L2_LRN_CNT_REG, port10 reg is not continuous, wait for updating of base.h*/ +ret_t rtl8367c_getAsicLutLearnNo(rtk_uint32 port, rtk_uint32* pNumber) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 10) + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_REG(port), pNumber); + if (retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_L2_LRN_CNT_CTRL10, pNumber); + if (retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicLutFlushAll + * Description: + * Flush all entries in LUT. Includes static & dynamic entries + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutFlushAll(void) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, 1); +} + +/* Function Name: + * rtl8367c_getAsicLutFlushAllStatus + * Description: + * Get Flush all status, 1:Busy, 0 normal + * Input: + * None + * Output: + * pBusyStatus - Busy state + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicLutFlushAllStatus(rtk_uint32 *pBusyStatus) +{ + if(NULL == pBusyStatus) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL3, RTL8367C_L2_FLUSH_CTRL3_OFFSET, pBusyStatus); +} + +/* Function Name: + * rtl8367c_setAsicLutForceFlush + * Description: + * Set per port force flush setting + * Input: + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ + /*port8~port10 setup is done in a separate register, wait for updating of base.h, reg.h*/ +ret_t rtl8367c_setAsicLutForceFlush(rtk_uint32 portmask) +{ + ret_t retVal; + + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_FORCE_FLUSH_PORTMASK_MASK, portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_PORTMASK1_MASK, (portmask >> 8) & 0x7); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicLutForceFlushStatus + * Description: + * Get per port force flush status + * Input: + * pPortmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ + /*port8~port10 setup is done in a separate register, wait for updating of base.h, reg.h*/ +ret_t rtl8367c_getAsicLutForceFlushStatus(rtk_uint32 *pPortmask) +{ + rtk_uint32 tmpMask; + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_FORCE_FLUSH_REG, RTL8367C_BUSY_STATUS_MASK,&tmpMask); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask = tmpMask & 0xff; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_FORCE_FLUSH1, RTL8367C_BUSY_STATUS1_MASK,&tmpMask); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask |= (tmpMask & 7) << 8; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicLutFlushMode + * Description: + * Set user force L2 pLutSt table flush mode + * Input: + * mode - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Actions not allowed by the function + * Note: + * None + */ +ret_t rtl8367c_setAsicLutFlushMode(rtk_uint32 mode) +{ + if( mode >= FLUSHMDOE_END ) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, mode); +} +/* Function Name: + * rtl8367c_getAsicLutFlushMode + * Description: + * Get user force L2 pLutSt table flush mode + * Input: + * pMode - 0:Port based 1: Port + VLAN based 2:Port + FID/MSTI based + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutFlushMode(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_MODE_MASK, pMode); +} +/* Function Name: + * rtl8367c_setAsicLutFlushType + * Description: + * Get L2 LUT flush type + * Input: + * type - 0: dynamic unicast; 1: both dynamic and static unicast entry + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicLutFlushType(rtk_uint32 type) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,type); +} +/* Function Name: + * rtl8367c_getAsicLutFlushType + * Description: + * Set L2 LUT flush type + * Input: + * pType - 0: dynamic unicast; 1: both dynamic and static unicast entry + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutFlushType(rtk_uint32* pType) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_L2_FLUSH_CTRL2, RTL8367C_LUT_FLUSH_TYPE_OFFSET,pType); +} + + +/* Function Name: + * rtl8367c_setAsicLutFlushVid + * Description: + * Set VID of Port + VID pLutSt flush mode + * Input: + * vid - Vid (0~4095) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) + * Note: + * None + */ +ret_t rtl8367c_setAsicLutFlushVid(rtk_uint32 vid) +{ + if( vid > RTL8367C_VIDMAX ) + return RT_ERR_VLAN_VID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, vid); +} +/* Function Name: + * rtl8367c_getAsicLutFlushVid + * Description: + * Get VID of Port + VID pLutSt flush mode + * Input: + * pVid - Vid (0~4095) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutFlushVid(rtk_uint32* pVid) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_VID_MASK, pVid); +} +/* Function Name: + * rtl8367c_setAsicPortFlusdFid + * Description: + * Set FID of Port + FID pLutSt flush mode + * Input: + * fid - FID/MSTI for force flush + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid FID (0~15) + * Note: + * None + */ +ret_t rtl8367c_setAsicLutFlushFid(rtk_uint32 fid) +{ + if( fid > RTL8367C_FIDMAX ) + return RT_ERR_L2_FID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, fid); +} +/* Function Name: + * rtl8367c_getAsicLutFlushFid + * Description: + * Get FID of Port + FID pLutSt flush mode + * Input: + * pFid - FID/MSTI for force flush + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLutFlushFid(rtk_uint32* pFid) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_L2_FLUSH_CTRL1, RTL8367C_LUT_FLUSH_FID_MASK, pFid); +} +/* Function Name: + * rtl8367c_setAsicLutDisableAging + * Description: + * Set L2 LUT aging per port setting + * Input: + * port - Physical port number (0~7) + * disabled - 0: enable aging; 1: disabling aging + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ + /*modification:RTL8367C_PORTIDMAX*/ +ret_t rtl8367c_setAsicLutDisableAging(rtk_uint32 port, rtk_uint32 disabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, disabled); +} +/* Function Name: + * rtl8367c_getAsicLutDisableAging + * Description: + * Get L2 LUT aging per port setting + * Input: + * port - Physical port number (0~7) + * pDisabled - 0: enable aging; 1: disabling aging + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ + /*modification:RTL8367C_PORTIDMAX*/ +ret_t rtl8367c_getAsicLutDisableAging(rtk_uint32 port, rtk_uint32 *pDisabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_LUT_AGEOUT_CTRL_REG, port, pDisabled); +} + +/* Function Name: + * rtl8367c_setAsicLutIPMCGroup + * Description: + * Set IPMC Group Table + * Input: + * index - the entry index in table (0 ~ 63) + * group_addr - the multicast group address (224.0.0.0 ~ 239.255.255.255) + * vid - VLAN ID + * pmask - portmask + * valid - valid bit + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t group_addr, rtk_uint32 vid, rtk_uint32 pmask, rtk_uint32 valid) +{ + rtk_uint32 regAddr, regData, bitoffset; + ipaddr_t ipData; + ret_t retVal; + + if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX) + return RT_ERR_INPUT; + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + ipData = group_addr; + + if( (ipData & 0xF0000000) != 0xE0000000) /* not in 224.0.0.0 ~ 239.255.255.255 */ + return RT_ERR_INPUT; + + /* Group Address */ + regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2); + regData = ((ipData & 0x0FFFFFFF) >> 16); + + if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) + return retVal; + + regAddr++; + regData = (ipData & 0x0000FFFF); + + if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) + return retVal; + + /* VID */ + regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index; + regData = vid; + + if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) + return retVal; + + /* portmask */ + regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index; + regData = pmask; + + if( (retVal = rtl8367c_setAsicReg(regAddr, regData)) != RT_ERR_OK) + return retVal; + + /* valid */ + regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16); + bitoffset = index % 16; + if( (retVal = rtl8367c_setAsicRegBit(regAddr, bitoffset, valid)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicLutIPMCGroup + * Description: + * Set IPMC Group Table + * Input: + * index - the entry index in table (0 ~ 63) + * Output: + * pGroup_addr - the multicast group address (224.0.0.0 ~ 239.255.255.255) + * pVid - VLAN ID + * pPmask - portmask + * pValid - Valid bit + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicLutIPMCGroup(rtk_uint32 index, ipaddr_t *pGroup_addr, rtk_uint32 *pVid, rtk_uint32 *pPmask, rtk_uint32 *pValid) +{ + rtk_uint32 regAddr, regData, bitoffset; + ipaddr_t ipData; + ret_t retVal; + + if(index > RTL8367C_LUT_IPMCGRP_TABLE_MAX) + return RT_ERR_INPUT; + + if (NULL == pGroup_addr) + return RT_ERR_NULL_POINTER; + + if (NULL == pVid) + return RT_ERR_NULL_POINTER; + + if (NULL == pPmask) + return RT_ERR_NULL_POINTER; + + /* Group address */ + regAddr = RTL8367C_REG_IPMC_GROUP_ENTRY0_H + (index * 2); + if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + *pGroup_addr = (((regData & 0x00000FFF) << 16) | 0xE0000000); + + regAddr++; + if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + ipData = (*pGroup_addr | (regData & 0x0000FFFF)); + *pGroup_addr = ipData; + + /* VID */ + regAddr = RTL8367C_REG_IPMC_GROUP_VID_00 + index; + if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + *pVid = regData; + + /* portmask */ + regAddr = RTL8367C_REG_IPMC_GROUP_PMSK_00 + index; + if( (retVal = rtl8367c_getAsicReg(regAddr, ®Data)) != RT_ERR_OK) + return retVal; + + *pPmask = regData; + + /* valid */ + regAddr = RTL8367C_REG_IPMC_GROUP_VALID_15_0 + (index / 16); + bitoffset = index % 16; + if( (retVal = rtl8367c_getAsicRegBit(regAddr, bitoffset, ®Data)) != RT_ERR_OK) + return retVal; + + *pValid = regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicLutLinkDownForceAging + * Description: + * Set LUT link down aging setting. + * Input: + * enable - link down aging setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicLutLinkDownForceAging(rtk_uint32 enable) +{ + if(enable > 1) + return RT_ERR_ENABLE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, enable ? 0 : 1); +} + +/* Function Name: + * rtl8367c_getAsicLutLinkDownForceAging + * Description: + * Get LUT link down aging setting. + * Input: + * pEnable - link down aging setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicLutLinkDownForceAging(rtk_uint32 *pEnable) +{ + rtk_uint32 value; + ret_t retVal; + + if ((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG, RTL8367C_LINKDOWN_AGEOUT_OFFSET, &value)) != RT_ERR_OK) + return retVal; + + *pEnable = value ? 0 : 1; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicLutIpmcFwdRouterPort + * Description: + * Set IPMC packet forward to router port also or not + * Input: + * enable - 1: Include router port, 0, exclude router port + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE Invalid parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicLutIpmcFwdRouterPort(rtk_uint32 enable) +{ + if(enable > 1) + return RT_ERR_ENABLE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, enable); +} + +/* Function Name: + * rtl8367c_getAsicLutIpmcFwdRouterPort + * Description: + * Get IPMC packet forward to router port also or not + * Input: + * None + * Output: + * pEnable - 1: Include router port, 0, exclude router port + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicLutIpmcFwdRouterPort(rtk_uint32 *pEnable) +{ + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_LUT_CFG2, RTL8367C_LUT_IPMC_FWD_RPORT_OFFSET, pEnable); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c new file mode 100644 index 000000000000..5412591a8245 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_meter.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Shared meter related functions + * + */ +#include +/* Function Name: + * rtl8367c_setAsicShareMeter + * Description: + * Set meter configuration + * Input: + * index - hared meter index (0-31) + * rate - 17-bits rate of share meter, unit is 8Kpbs + * ifg - Including IFG in rate calculation, 1:include 0:exclude + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_setAsicShareMeter(rtk_uint32 index, rtk_uint32 rate, rtk_uint32 ifg) +{ + ret_t retVal; + + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + { + /*19-bits Rate*/ + retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index), rate&0xFFFF); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_METER_RATE_REG(index) + 1, (rate &0x70000) >> 16); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), ifg); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + /*19-bits Rate*/ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), rate&0xFFFF); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, (rate &0x70000) >> 16); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), ifg); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicShareMeter + * Description: + * Get meter configuration + * Input: + * index - hared meter index (0-31) + * pRate - 17-bits rate of share meter, unit is 8Kpbs + * pIfg - Including IFG in rate calculation, 1:include 0:exclude + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_getAsicShareMeter(rtk_uint32 index, rtk_uint32 *pRate, rtk_uint32 *pIfg) +{ + rtk_uint32 regData; + rtk_uint32 regData2; + ret_t retVal; + + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + { + /*17-bits Rate*/ + retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_METER_RATE_REG(index) + 1, ®Data2); + if(retVal != RT_ERR_OK) + return retVal; + + *pRate = ((regData2 << 16) & 0x70000) | regData; + /*IFG*/ + retVal = rtl8367c_getAsicRegBit(RTL8367C_METER_IFG_CTRL_REG(index), RTL8367C_METER_IFG_OFFSET(index), pIfg); + + return retVal; + } + else + { + /*17-bits Rate*/ + retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1), ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_METER32_RATE_CTRL0 + ((index-32) << 1) + 1, ®Data2); + if(retVal != RT_ERR_OK) + return retVal; + + *pRate = ((regData2 << 16) & 0x70000) | regData; + /*IFG*/ + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_METER_IFG_CTRL2 + ((index-32) >> 4), RTL8367C_METER_IFG_OFFSET(index), pIfg); + + return retVal; + } +} +/* Function Name: + * rtl8367c_setAsicShareMeterBucketSize + * Description: + * Set meter related leaky bucket threshold + * Input: + * index - hared meter index (0-31) + * lbthreshold - Leaky bucket threshold of meter + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_setAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 lbthreshold) +{ + + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + return rtl8367c_setAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), lbthreshold); + else + return rtl8367c_setAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, lbthreshold); +} +/* Function Name: + * rtl8367c_getAsicShareMeterBucketSize + * Description: + * Get meter related leaky bucket threshold + * Input: + * index - hared meter index (0-31) + * pLbthreshold - Leaky bucket threshold of meter + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_getAsicShareMeterBucketSize(rtk_uint32 index, rtk_uint32 *pLbthreshold) +{ + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + return rtl8367c_getAsicReg(RTL8367C_METER_BUCKET_SIZE_REG(index), pLbthreshold); + else + return rtl8367c_getAsicReg(RTL8367C_REG_METER32_BUCKET_SIZE + index - 32, pLbthreshold); +} + +/* Function Name: + * rtl8367c_setAsicShareMeterType + * Description: + * Set meter Type + * Input: + * index - shared meter index (0-31) + * Type - 0: kbps, 1: pps + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_setAsicShareMeterType(rtk_uint32 index, rtk_uint32 type) +{ + rtk_uint32 reg; + + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16); + else + reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16); + return rtl8367c_setAsicRegBit(reg, index % 16, type); +} + +/* Function Name: + * rtl8367c_getAsicShareMeterType + * Description: + * Get meter Type + * Input: + * index - shared meter index (0-31) + * Output: + * pType - 0: kbps, 1: pps + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_getAsicShareMeterType(rtk_uint32 index, rtk_uint32 *pType) +{ + rtk_uint32 reg; + + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(NULL == pType) + return RT_ERR_NULL_POINTER; + + if(index < 32) + reg = RTL8367C_REG_METER_MODE_SETTING0 + (index / 16); + else + reg = RTL8367C_REG_METER_MODE_SETTING2 + ((index - 32) / 16); + return rtl8367c_getAsicRegBit(reg, index % 16, pType); +} + + +/* Function Name: + * rtl8367c_setAsicMeterExceedStatus + * Description: + * Clear shared meter status + * Input: + * index - hared meter index (0-31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_setAsicMeterExceedStatus(rtk_uint32 index) +{ + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + return rtl8367c_setAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), 1); + else + return rtl8367c_setAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), 1); + +} +/* Function Name: + * rtl8367c_getAsicMeterExceedStatus + * Description: + * Get shared meter status + * Input: + * index - hared meter index (0-31) + * pStatus - 0: rate doesn't exceed 1: rate exceeds + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * If rate is over rate*8Kbps of a meter, the state bit of this meter is set to 1. + */ +ret_t rtl8367c_getAsicMeterExceedStatus(rtk_uint32 index, rtk_uint32* pStatus) +{ + if(index > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(index < 32) + return rtl8367c_getAsicRegBit(RTL8367C_METER_OVERRATE_INDICATOR_REG(index), RTL8367C_METER_EXCEED_OFFSET(index), pStatus); + else + return rtl8367c_getAsicRegBit(RTL8367C_REG_METER_OVERRATE_INDICATOR2 + ((index - 32) >> 4), RTL8367C_METER_EXCEED_OFFSET(index), pStatus); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c new file mode 100644 index 000000000000..7da098c49fc9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_mib.c @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : MIB related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicMIBsCounterReset + * Description: + * Reset global/queue manage or per-port MIB counter + * Input: + * greset - Global reset + * qmreset - Queue management reset + * portmask - Port reset mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsCounterReset(rtk_uint32 greset, rtk_uint32 qmreset, rtk_uint32 portmask) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 regBits; + + regBits = RTL8367C_GLOBAL_RESET_MASK | + RTL8367C_QM_RESET_MASK | + RTL8367C_MIB_PORT07_MASK | + ((rtk_uint32)0x7 << 13); + regData = ((greset << RTL8367C_GLOBAL_RESET_OFFSET) & RTL8367C_GLOBAL_RESET_MASK) | + ((qmreset << RTL8367C_QM_RESET_OFFSET) & RTL8367C_QM_RESET_MASK) | + (((portmask & 0xFF) << RTL8367C_PORT0_RESET_OFFSET) & RTL8367C_MIB_PORT07_MASK) | + (((portmask >> 8)&0x7) << 13); + + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL0, regBits, (regData >> RTL8367C_PORT0_RESET_OFFSET)); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicMIBsCounter + * Description: + * Get MIBs counter + * Input: + * port - Physical port number (0~7) + * mibIdx - MIB counter index + * pCounter - MIB retrieved counter + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving + * RT_ERR_STAT_CNTR_FAIL - MIB is resetting + * Note: + * Before MIBs counter retrieving, writing accessing address to ASIC at first and check the MIB + * control register status. If busy bit of MIB control is set, that means MIB counter have been + * waiting for preparing, then software must wait after this busy flag reset by ASIC. This driver + * did not recycle reading user desired counter. Software must use driver again to get MIB counter + * if return value is not RT_ERR_OK. + */ +ret_t rtl8367c_getAsicMIBsCounter(rtk_uint32 port, RTL8367C_MIBCOUNTER mibIdx, rtk_uint64* pCounter) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 regData; + rtk_uint32 mibAddr; + rtk_uint32 mibOff=0; + + /* address offset to MIBs counter */ + CONST rtk_uint16 mibLength[RTL8367C_MIBS_NUMBER]= { + 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 4,2,2,2,2,2,2,2,2, + 4,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; + + rtk_uint16 i; + rtk_uint64 mibCounter; + + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(mibIdx >= RTL8367C_MIBS_NUMBER) + return RT_ERR_STAT_INVALID_CNTR; + + if(dot1dTpLearnedEntryDiscards == mibIdx) + { + mibAddr = RTL8367C_MIB_LEARNENTRYDISCARD_OFFSET; + } + else + { + i = 0; + mibOff = RTL8367C_MIB_PORT_OFFSET * port; + + if(port > 7) + mibOff = mibOff + 68; + + while(i < mibIdx) + { + mibOff += mibLength[i]; + i++; + } + + mibAddr = mibOff; + } + + + /*writing access counter address first*/ + /*This address is SRAM address, and SRAM address = MIB register address >> 2*/ + /*then ASIC will prepare 64bits counter wait for being retrieved*/ + /*Write Mib related address to access control register*/ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2)); + if(retVal != RT_ERR_OK) + return retVal; + + + + /* polling busy flag */ + i = 100; + while(i > 0) + { + /*read MIB control register*/ + retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if((regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) == 0) + { + break; + } + + i--; + } + + if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) + return RT_ERR_BUSYWAIT_TIMEOUT; + + if(regData & RTL8367C_RESET_FLAG_MASK) + return RT_ERR_STAT_CNTR_FAIL; + + mibCounter = 0; + i = mibLength[mibIdx]; + if(4 == i) + regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3; + else + regAddr = RTL8367C_MIB_COUNTER_BASE_REG + ((mibOff + 1) % 4); + + while(i) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + mibCounter = (mibCounter << 16) | (regData & 0xFFFF); + + regAddr --; + i --; + + } + + *pCounter = mibCounter; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicMIBsLogCounter + * Description: + * Get MIBs Logging counter + * Input: + * index - The index of 32 logging counter (0 ~ 31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Wrong index + * RT_ERR_BUSYWAIT_TIMEOUT - MIB is busy at retrieving + * RT_ERR_STAT_CNTR_FAIL - MIB is resetting + * Note: + * This API get 32 logging counter + */ +ret_t rtl8367c_getAsicMIBsLogCounter(rtk_uint32 index, rtk_uint32 *pCounter) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 regData; + rtk_uint32 mibAddr; + rtk_uint16 i; + rtk_uint64 mibCounter; + + if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_ENTRY_INDEX; + + mibAddr = RTL8367C_MIB_LOG_CNT_OFFSET + ((index / 2) * 4); + + retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_ADDRESS, (mibAddr >> 2)); + if(retVal != RT_ERR_OK) + return retVal; + + /*read MIB control register*/ + retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if(regData & RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK) + return RT_ERR_BUSYWAIT_TIMEOUT; + + if(regData & RTL8367C_RESET_FLAG_MASK) + return RT_ERR_STAT_CNTR_FAIL; + + mibCounter = 0; + if((index % 2) == 1) + regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 3; + else + regAddr = RTL8367C_MIB_COUNTER_BASE_REG + 1; + + for(i = 0; i <= 1; i++) + { + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + + if(retVal != RT_ERR_OK) + return retVal; + + mibCounter = (mibCounter << 16) | (regData & 0xFFFF); + + regAddr --; + } + + *pCounter = mibCounter; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicMIBsControl + * Description: + * Get MIB control register + * Input: + * pMask - MIB control status mask bit[0]-busy bit[1] + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * Software need to check this control register after doing port resetting or global resetting + */ +ret_t rtl8367c_getAsicMIBsControl(rtk_uint32* pMask) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicReg(RTL8367C_MIB_CTRL_REG, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pMask = regData & (RTL8367C_MIB_CTRL0_BUSY_FLAG_MASK | RTL8367C_RESET_FLAG_MASK); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicMIBsResetValue + * Description: + * Reset all counter to 0 or 1 + * Input: + * value - Reset to value 0 or 1 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsResetValue(rtk_uint32 value) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value); +} +/* Function Name: + * rtl8367c_getAsicMIBsResetValue + * Description: + * Reset all counter to 0 or 1 + * Input: + * value - Reset to value 0 or 1 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMIBsResetValue(rtk_uint32* value) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL0, RTL8367C_RESET_VALUE_OFFSET, value); +} + +/* Function Name: + * rtl8367c_setAsicMIBsUsageMode + * Description: + * MIB update mode + * Input: + * mode - 1: latch all MIBs by timer 0:normal free run counting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsUsageMode(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, mode); +} +/* Function Name: + * rtl8367c_getAsicMIBsUsageMode + * Description: + * MIB update mode + * Input: + * pMode - 1: latch all MIBs by timer 0:normal free run counting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMIBsUsageMode(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_USAGE_MODE_OFFSET, pMode); +} + +/* Function Name: + * rtl8367c_setAsicMIBsTimer + * Description: + * MIB latching timer + * Input: + * timer - latch timer, unit 1 second + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsTimer(rtk_uint32 timer) +{ + return rtl8367c_setAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, timer); +} +/* Function Name: + * rtl8367c_getAsicMIBsTimer + * Description: + * MIB latching timer + * Input: + * pTimer - latch timer, unit 1 second + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMIBsTimer(rtk_uint32* pTimer) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_MIB_CTRL4, RTL8367C_MIB_TIMER_MASK, pTimer); +} +/* Function Name: + * rtl8367c_setAsicMIBsLoggingMode + * Description: + * MIB logging counter mode + * Input: + * index - logging counter mode index (0~15) + * mode - 0:32-bits mode 1:64-bits mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32 mode) +{ + if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,mode); +} +/* Function Name: + * rtl8367c_getAsicMIBsLoggingMode + * Description: + * MIB logging counter mode + * Input: + * index - logging counter mode index (0~15) + * pMode - 0:32-bits mode 1:64-bits mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicMIBsLoggingMode(rtk_uint32 index, rtk_uint32* pMode) +{ + if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL3, index,pMode); +} + +/* Function Name: + * rtl8367c_setAsicMIBsLoggingType + * Description: + * MIB logging counter type + * Input: + * index - logging counter mode index (0~15) + * type - 0:Packet count 1:Byte count + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32 type) +{ + if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,type); +} + +/* Function Name: + * rtl8367c_getAsicMIBsLoggingType + * Description: + * MIB logging counter type + * Input: + * index - logging counter mode index (0~15) + * pType - 0:Packet count 1:Byte count + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicMIBsLoggingType(rtk_uint32 index, rtk_uint32* pType) +{ + if(index > RTL8367C_MIB_MAX_LOG_MODE_IDX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIB_CTRL5, index,pType); +} + +/* Function Name: + * rtl8367c_setAsicMIBsResetLoggingCounter + * Description: + * MIB logging counter type + * Input: + * index - logging counter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicMIBsResetLoggingCounter(rtk_uint32 index) +{ + ret_t retVal; + + if(index > RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_OUT_OF_RANGE; + + if(index < 16) + retVal = rtl8367c_setAsicReg(RTL8367C_REG_MIB_CTRL1, 1< +/* Function Name: + * rtl8367c_setAsicPortMirror + * Description: + * Set port mirror function + * Input: + * source - Source port + * monitor - Monitor (destination) port + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirror(rtk_uint32 source, rtk_uint32 monitor) +{ + ret_t retVal; + + if((source > RTL8367C_PORTIDMAX) || (monitor > RTL8367C_PORTIDMAX)) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, source); + if(retVal != RT_ERR_OK) + return retVal; + + + return rtl8367c_setAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, monitor); +} +/* Function Name: + * rtl8367c_getAsicPortMirror + * Description: + * Get port mirror function + * Input: + * pSource - Source port + * pMonitor - Monitor (destination) port + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirror(rtk_uint32 *pSource, rtk_uint32 *pMonitor) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_SOURCE_PORT_MASK, pSource); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_getAsicRegBits(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_MONITOR_PORT_MASK, pMonitor); +} +/* Function Name: + * rtl8367c_setAsicPortMirrorRxFunction + * Description: + * Set the mirror function on RX of the mirrored + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorRxFunction(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorRxFunction + * Description: + * Get the mirror function on RX of the mirrored + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorRxFunction(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_RX_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicPortMirrorTxFunction + * Description: + * Set the mirror function on TX of the mirrored + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorTxFunction(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorTxFunction + * Description: + * Get the mirror function on TX of the mirrored + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorTxFunction(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_TX_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicPortMirrorIsolation + * Description: + * Set the traffic isolation on monitor port + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorIsolation(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorIsolation + * Description: + * Get the traffic isolation on monitor port + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorIsolation(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_MIRROR_CTRL_REG, RTL8367C_MIRROR_ISO_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorMask + * Description: + * Set mirror source port mask + * Input: + * SourcePortmask - Source Portmask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK- Port Mask Error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorMask(rtk_uint32 SourcePortmask) +{ + if( SourcePortmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, SourcePortmask); +} + +/* Function Name: + * rtl8367c_getAsicPortMirrorMask + * Description: + * Get mirror source port mask + * Input: + * None + * Output: + * pSourcePortmask - Source Portmask + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK- Port Mask Error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorMask(rtk_uint32 *pSourcePortmask) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_MIRROR_SRC_PMSK, RTL8367C_MIRROR_SRC_PMSK_MASK, pSourcePortmask); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorVlanRxLeaky + * Description: + * Set the mirror function of VLAN RX leaky + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorVlanRxLeaky(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorVlanRxLeaky + * Description: + * Get the mirror function of VLAN RX leaky + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorVlanRxLeaky(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_VLAN_LEAKY_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorVlanTxLeaky + * Description: + * Set the mirror function of VLAN TX leaky + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorVlanTxLeaky(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorVlanTxLeaky + * Description: + * Get the mirror function of VLAN TX leaky + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorVlanTxLeaky(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_VLAN_LEAKY_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorIsolationRxLeaky + * Description: + * Set the mirror function of Isolation RX leaky + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorIsolationRxLeaky(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorIsolationRxLeaky + * Description: + * Get the mirror function of VLAN RX leaky + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorIsolationRxLeaky(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_RX_ISOLATION_LEAKY_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorIsolationTxLeaky + * Description: + * Set the mirror function of Isolation TX leaky + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorIsolationTxLeaky(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorIsolationTxLeaky + * Description: + * Get the mirror function of VLAN TX leaky + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorIsolationTxLeaky(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_TX_ISOLATION_LEAKY_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorRealKeep + * Description: + * Set the mirror function of keep format + * Input: + * mode - 1: keep original format, 0: follow VLAN config + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorRealKeep(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, mode); +} +/* Function Name: + * rtl8367c_getAsicPortMirrorRealKeep + * Description: + * Get the mirror function of keep format + * Input: + * pMode - 1: keep original format, 0: follow VLAN config + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorRealKeep(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL2, RTL8367C_MIRROR_REALKEEP_EN_OFFSET, pMode); +} + +/* Function Name: + * rtl8367c_setAsicPortMirrorOverride + * Description: + * Set the mirror function of override + * Input: + * rxMirror - 1: output rx Mirror format, 0: output forward format + * txMirror - 1: output tx Mirror format, 0: output forward format + * aclMirror - 1: output ACL Mirror format, 0: output forward format + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortMirrorOverride(rtk_uint32 rxMirror, rtk_uint32 txMirror, rtk_uint32 aclMirror) +{ + ret_t retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, rxMirror)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, txMirror)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, aclMirror)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicPortMirrorOverride + * Description: + * Get the mirror function of override + * Input: + * None + * Output: + * pRxMirror - 1: output rx Mirror format, 0: output forward format + * pTxMirror - 1: output tx Mirror format, 0: output forward format + * pAclMirror - 1: output ACL Mirror format, 0: output forward format + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortMirrorOverride(rtk_uint32 *pRxMirror, rtk_uint32 *pTxMirror, rtk_uint32 *pAclMirror) +{ + ret_t retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_RX_OVERRIDE_EN_OFFSET, pRxMirror)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_TX_OVERRIDE_EN_OFFSET, pTxMirror)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MIRROR_CTRL3, RTL8367C_MIRROR_ACL_OVERRIDE_EN_OFFSET, pAclMirror)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c new file mode 100644 index 000000000000..2189b151c387 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_misc.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Miscellaneous functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicMacAddress + * Description: + * Set switch MAC address + * Input: + * mac - switch mac + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMacAddress(ether_addr_t mac) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint8 *accessPtr; + rtk_uint32 i; + + accessPtr = (rtk_uint8*)&mac; + + regData = *accessPtr; + accessPtr ++; + regData = (regData << 8) | *accessPtr; + accessPtr ++; + for(i = 0; i <=2; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + regData = *accessPtr; + accessPtr ++; + regData = (regData << 8) | *accessPtr; + accessPtr ++; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicMacAddress + * Description: + * Get switch MAC address + * Input: + * pMac - switch mac + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMacAddress(ether_addr_t *pMac) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint8 *accessPtr; + rtk_uint32 i; + + + accessPtr = (rtk_uint8*)pMac; + + for(i = 0; i <= 2; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_SWITCH_MAC2 - i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = (regData & 0xFF00) >> 8; + accessPtr ++; + *accessPtr = regData & 0xFF; + accessPtr ++; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicDebugInfo + * Description: + * Get per-port packet forward debugging information + * Input: + * port - Physical port number (0~7) + * pDebugifo - per-port packet trap/drop/forward reason + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicDebugInfo(rtk_uint32 port, rtk_uint32 *pDebugifo) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_DEBUG_INFO_REG(port), RTL8367C_DEBUG_INFO_MASK(port), pDebugifo); +} +/* Function Name: + * rtl8367c_setAsicPortJamMode + * Description: + * Set half duplex flow control setting + * Input: + * mode - 0: Back-Pressure 1: DEFER + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortJamMode(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET,mode); +} +/* Function Name: + * rtl8367c_getAsicPortJamMode + * Description: + * Get half duplex flow control setting + * Input: + * pMode - 0: Back-Pressure 1: DEFER + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortJamMode(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_CFG_BACKPRESSURE, RTL8367C_LONGTXE_OFFSET, pMode); +} + +/* Function Name: + * rtl8367c_setAsicMaxLengthCfg + * Description: + * Set Max packet length configuration + * Input: + * cfgId - Configuration ID + * maxLength - Max Length + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 maxLength) +{ + return rtl8367c_setAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, maxLength); +} + +/* Function Name: + * rtl8367c_getAsicMaxLengthCfg + * Description: + * Get Max packet length configuration + * Input: + * cfgId - Configuration ID + * maxLength - Max Length + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMaxLengthCfg(rtk_uint32 cfgId, rtk_uint32 *pMaxLength) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_MAX_LEN_RX_TX_CFG0 + cfgId, RTL8367C_MAX_LEN_RX_TX_CFG0_MASK, pMaxLength); +} + +/* Function Name: + * rtl8367c_setAsicMaxLength + * Description: + * Set Max packet length + * Input: + * port - port ID + * type - 0: 10M/100M speed, 1: giga speed + * cfgId - Configuration ID + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 cfgId) +{ + ret_t retVal; + + if(port < 8) + { + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, cfgId); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, cfgId); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicMaxLength + * Description: + * Get Max packet length + * Input: + * port - port ID + * type - 0: 10M/100M speed, 1: giga speed + * cfgId - Configuration ID + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicMaxLength(rtk_uint32 port, rtk_uint32 type, rtk_uint32 *pCfgId) +{ + ret_t retVal; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG, (type * 8) + port, pCfgId); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_MAX_LENGTH_CFG_EXT, (type * 3) + port - 8, pCfgId); + if(retVal != RT_ERR_OK) + return retVal; + } + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c new file mode 100644 index 000000000000..1556f4500d40 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_oam.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 42321 $ + * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : OAM related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicOamParser + * Description: + * Set OAM parser state + * Input: + * port - Physical port number (0~7) + * parser - Per-Port OAM parser state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_NOT_ALLOWED - Invalid paser state + * Note: + * None + */ +ret_t rtl8367c_setAsicOamParser(rtk_uint32 port, rtk_uint32 parser) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(parser > OAM_PARFWDCPU) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port % 8), parser); +} +/* Function Name: + * rtl8367c_getAsicOamParser + * Description: + * Get OAM parser state + * Input: + * port - Physical port number (0~7) + * pParser - Per-Port OAM parser state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicOamParser(rtk_uint32 port, rtk_uint32* pParser) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_PARSER_CTRL0 + port/8, RTL8367C_OAM_PARSER_MASK(port%8), pParser); +} +/* Function Name: + * rtl8367c_setAsicOamMultiplexer + * Description: + * Set OAM multiplexer state + * Input: + * port - Physical port number (0~7) + * multiplexer - Per-Port OAM multiplexer state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_NOT_ALLOWED - Invalid multiplexer state + * Note: + * None + */ +ret_t rtl8367c_setAsicOamMultiplexer(rtk_uint32 port, rtk_uint32 multiplexer) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(multiplexer > OAM_MULCPU) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), multiplexer); +} +/* Function Name: + * rtl8367c_getAsicOamMultiplexer + * Description: + * Get OAM multiplexer state + * Input: + * port - Physical port number (0~7) + * pMultiplexer - Per-Port OAM multiplexer state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicOamMultiplexer(rtk_uint32 port, rtk_uint32* pMultiplexer) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_OAM_MULTIPLEXER_CTRL0 + port/8, RTL8367C_OAM_MULTIPLEXER_MASK(port%8), pMultiplexer); +} +/* Function Name: + * rtl8367c_setAsicOamCpuPri + * Description: + * Set trap priority for OAM packet + * Input: + * priority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicOamCpuPri(rtk_uint32 priority) +{ + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, priority); +} +/* Function Name: + * rtl8367c_getAsicOamCpuPri + * Description: + * Get trap priority for OAM packet + * Input: + * pPriority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicOamCpuPri(rtk_uint32 *pPriority) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_OAM_PRIOIRTY_MASK, pPriority); +} +/* Function Name: + * rtl8367c_setAsicOamEnable + * Description: + * Set OAM function state + * Input: + * enabled - OAM function usage 1:enable, 0:disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicOamEnable(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicOamEnable + * Description: + * Get OAM function state + * Input: + * pEnabled - OAM function usage 1:enable, 0:disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicOamEnable(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_OAM_CTRL, RTL8367C_OAM_CTRL_OFFSET, pEnabled); +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c new file mode 100644 index 000000000000..fb4db113a987 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_phy.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : PHY related functions + * + */ +#include + +#if defined(MDC_MDIO_OPERATION) +/* Function Name: + * rtl8367c_setAsicPHYOCPReg + * Description: + * Set PHY OCP registers + * Input: + * phyNo - Physical port number (0~7) + * ocpAddr - OCP address + * ocpData - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; + + /* OCP prefix */ + ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) + return retVal; + + /*prepare access address*/ + ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); + ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); + regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; + if((retVal = rtl8367c_setAsicReg(regAddr, ocpData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicPHYOCPReg + * Description: + * Get PHY OCP registers + * Input: + * phyNo - Physical port number (0~7) + * ocpAddr - PHY address + * pRegData - read data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; + /* OCP prefix */ + ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) + return retVal; + + /*prepare access address*/ + ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); + ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); + regAddr = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; + if((retVal = rtl8367c_getAsicReg(regAddr, pRegData)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +#else + +/* Function Name: + * rtl8367c_setAsicPHYOCPReg + * Description: + * Set PHY OCP registers + * Input: + * phyNo - Physical port number (0~7) + * ocpAddr - OCP address + * ocpData - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_setAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 ocpData ) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 busyFlag, checkCounter; + rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; + + /*Check internal phy access busy or not*/ + /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ + retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); + if(retVal != RT_ERR_OK) + return retVal; + + if(busyFlag) + return RT_ERR_BUSYWAIT_TIMEOUT; + + /* OCP prefix */ + ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) + return retVal; + + /*prepare access data*/ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_WRITE_DATA, ocpData); + if(retVal != RT_ERR_OK) + return retVal; + + /*prepare access address*/ + ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); + ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); + regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /*Set WRITE Command*/ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK | RTL8367C_RW_MASK); + + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); + if((retVal != RT_ERR_OK) || busyFlag) + { + checkCounter --; + if(0 == checkCounter) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + else + { + checkCounter = 0; + } + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicPHYOCPReg + * Description: + * Get PHY OCP registers + * Input: + * phyNo - Physical port number (0~7) + * ocpAddr - PHY address + * pRegData - read data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_getAsicPHYOCPReg(rtk_uint32 phyNo, rtk_uint32 ocpAddr, rtk_uint32 *pRegData ) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 busyFlag,checkCounter; + rtk_uint32 ocpAddrPrefix, ocpAddr9_6, ocpAddr5_1; + /*Check internal phy access busy or not*/ + /*retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_INDRECT_ACCESS_STATUS, RTL8367C_INDRECT_ACCESS_STATUS_OFFSET,&busyFlag);*/ + retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); + if(retVal != RT_ERR_OK) + return retVal; + + if(busyFlag) + return RT_ERR_BUSYWAIT_TIMEOUT; + + /* OCP prefix */ + ocpAddrPrefix = ((ocpAddr & 0xFC00) >> 10); + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_GPHY_OCP_MSB_0, RTL8367C_CFG_CPU_OCPADR_MSB_MASK, ocpAddrPrefix)) != RT_ERR_OK) + return retVal; + + /*prepare access address*/ + ocpAddr9_6 = ((ocpAddr >> 6) & 0x000F); + ocpAddr5_1 = ((ocpAddr >> 1) & 0x001F); + regData = RTL8367C_PHY_BASE | (ocpAddr9_6 << 8) | (phyNo << RTL8367C_PHY_OFFSET) | ocpAddr5_1; + retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_ADDRESS, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /*Set READ Command*/ + retVal = rtl8367c_setAsicReg(RTL8367C_REG_INDRECT_ACCESS_CTRL, RTL8367C_CMD_MASK ); + if(retVal != RT_ERR_OK) + return retVal; + + checkCounter = 100; + while(checkCounter) + { + retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_STATUS,&busyFlag); + if((retVal != RT_ERR_OK) || busyFlag) + { + checkCounter --; + if(0 == checkCounter) + return RT_ERR_FAILED; + } + else + { + checkCounter = 0; + } + } + + /*get PHY register*/ + retVal = rtl8367c_getAsicReg(RTL8367C_REG_INDRECT_ACCESS_READ_DATA, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *pRegData = regData; + + return RT_ERR_OK; +} + +#endif + +/* Function Name: + * rtl8367c_setAsicPHYReg + * Description: + * Set PHY registers + * Input: + * phyNo - Physical port number (0~7) + * phyAddr - PHY address (0~31) + * phyData - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_setAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 phyData ) +{ + rtk_uint32 ocp_addr; + + if(phyAddr > RTL8367C_PHY_REGNOMAX) + return RT_ERR_PHY_REG_ID; + + ocp_addr = 0xa400 + phyAddr*2; + + return rtl8367c_setAsicPHYOCPReg(phyNo, ocp_addr, phyData); +} +/* Function Name: + * rtl8367c_getAsicPHYReg + * Description: + * Get PHY registers + * Input: + * phyNo - Physical port number (0~7) + * phyAddr - PHY address (0~31) + * pRegData - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PHY_REG_ID - invalid PHY address + * RT_ERR_PHY_ID - invalid PHY no + * RT_ERR_BUSYWAIT_TIMEOUT - PHY access busy + * Note: + * None + */ +ret_t rtl8367c_getAsicPHYReg(rtk_uint32 phyNo, rtk_uint32 phyAddr, rtk_uint32 *pRegData ) +{ + rtk_uint32 ocp_addr; + + if(phyAddr > RTL8367C_PHY_REGNOMAX) + return RT_ERR_PHY_REG_ID; + + ocp_addr = 0xa400 + phyAddr*2; + + return rtl8367c_getAsicPHYOCPReg(phyNo, ocp_addr, pRegData); +} + + +/* Function Name: + * rtl8367c_setAsicSdsReg + * Description: + * Set Serdes registers + * Input: + * sdsId - sdsid (0~1) + * sdsReg - reg address (0~31) + * sdsPage - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + + * Note: + * None + */ + +ret_t rtl8367c_setAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 value) +{ + rtk_uint32 retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0|sdsId)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtl8367c_getAiscSdsReg + * Description: + * Get Serdes registers + * Input: + * sdsId - sdsid (0~1) + * sdsReg - reg address (0~31) + * sdsPage - Writing data + * Output: + * None + * Return: + * RT_ERR_OK - Success + + * Note: + * None + */ +ret_t rtl8367c_getAsicSdsReg(rtk_uint32 sdsId, rtk_uint32 sdsReg, rtk_uint32 sdsPage, rtk_uint32 *value) +{ + rtk_uint32 retVal, busy; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (sdsPage<<5) | sdsReg)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x0080|sdsId)) != RT_ERR_OK) + return retVal; + + while(1) + { + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_CMD, &busy))!=RT_ERR_OK) + return retVal; + + if ((busy & 0x100) == 0) + break; + } + + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_SDS_INDACS_DATA, value))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + + + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c new file mode 100644 index 000000000000..fae046639d78 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_port.c @@ -0,0 +1,5752 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76333 $ + * $Date: 2017-03-09 09:33:15 +0800 (週四, 09 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port security related functions + * + */ + +#include + +#include + + +#define FIBER2_AUTO_INIT_SIZE 2038 +rtk_uint8 Fiber2_Auto[FIBER2_AUTO_INIT_SIZE] = { +0x02,0x05,0x8F,0xE4,0xF5,0xA8,0xD2,0xAF, +0x22,0x00,0x00,0x02,0x07,0x2C,0xC5,0xF0, +0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, +0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, +0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, +0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, +0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, +0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, +0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, +0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, +0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, +0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, +0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, +0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, +0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, +0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, +0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, +0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, +0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, +0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, +0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, +0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, +0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, +0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, +0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, +0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, +0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, +0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, +0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, +0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, +0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, +0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, +0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, +0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, +0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, +0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0x80,0x7C,0x04,0x7F,0x01, +0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C, +0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB, +0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, +0x12,0x07,0xAB,0x7D,0x81,0x7C,0x04,0x7F, +0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0x82,0x7C,0x04, +0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB,0x7D, +0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0x60,0x7C,0x69,0x7F,0x02, +0x7E,0x66,0x12,0x07,0xAB,0x7D,0x83,0x7C, +0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB, +0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, +0x12,0x07,0xAB,0x7D,0x28,0x7C,0x97,0x7F, +0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x84, +0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0x85,0x7C,0x9D, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, +0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xAB,0x7D,0x10,0x7C, +0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB, +0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x00, +0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x66,0xEF,0x44,0x40,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x66,0xEF,0x54,0xBF,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x66,0xEF,0x54,0xFD,0x54,0xFE, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xAB,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x66,0xEF,0x44,0x02,0x44,0x01, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xAB,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xAB,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xAB,0xE4, +0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, +0x3F,0x7E,0x1D,0x12,0x07,0xAB,0x7D,0x40, +0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, +0xAB,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, +0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, +0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, +0x13,0x12,0x07,0xAB,0x12,0x07,0xDB,0x12, +0x01,0x27,0x12,0x06,0x1B,0x12,0x07,0x8A, +0x12,0x06,0xEA,0x7D,0x41,0x7C,0x00,0x7F, +0x36,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF, +0xFE,0xFD,0x80,0x26,0x7F,0xFF,0x7E,0xFF, +0x7D,0x05,0x7C,0x00,0x90,0x06,0x24,0x12, +0x01,0x0F,0xC3,0x12,0x00,0xF2,0x50,0x1B, +0x90,0x06,0x24,0x12,0x01,0x03,0xEF,0x24, +0x01,0xFF,0xE4,0x3E,0xFE,0xE4,0x3D,0xFD, +0xE4,0x3C,0xFC,0x90,0x06,0x24,0x12,0x01, +0x1B,0x80,0xD1,0xC2,0x00,0xC2,0x01,0xD2, +0xA9,0xD2,0x8C,0x7F,0x01,0x7E,0x62,0x12, +0x07,0x66,0xEF,0x30,0xE2,0x07,0xE4,0x90, +0x06,0x2C,0xF0,0x80,0xEE,0x90,0x06,0x2C, +0xE0,0x70,0x12,0x12,0x04,0xF0,0x90,0x06, +0x2C,0x74,0x01,0xF0,0xE4,0x90,0x06,0x33, +0xF0,0xA3,0xF0,0x80,0xD6,0xC3,0x90,0x06, +0x34,0xE0,0x94,0x62,0x90,0x06,0x33,0xE0, +0x94,0x00,0x40,0xC7,0xE4,0xF0,0xA3,0xF0, +0x12,0x04,0xF0,0x90,0x06,0x2C,0x74,0x01, +0xF0,0x80,0xB8,0x75,0x0F,0x80,0x75,0x0E, +0x7E,0x75,0x0D,0xAA,0x75,0x0C,0x83,0xE4, +0xF5,0x10,0x7F,0x36,0x7E,0x13,0x12,0x07, +0x66,0xEE,0xC4,0xF8,0x54,0xF0,0xC8,0xEF, +0xC4,0x54,0x0F,0x48,0x54,0x07,0xFB,0x7A, +0x00,0xEA,0x70,0x4A,0xEB,0x14,0x60,0x1C, +0x14,0x60,0x27,0x24,0xFE,0x60,0x31,0x14, +0x60,0x3C,0x24,0x05,0x70,0x38,0x75,0x0B, +0x00,0x75,0x0A,0xC2,0x75,0x09,0xEB,0x75, +0x08,0x0B,0x80,0x36,0x75,0x0B,0x40,0x75, +0x0A,0x59,0x75,0x09,0x73,0x75,0x08,0x07, +0x80,0x28,0x75,0x0B,0x00,0x75,0x0A,0xE1, +0x75,0x09,0xF5,0x75,0x08,0x05,0x80,0x1A, +0x75,0x0B,0xA0,0x75,0x0A,0xAC,0x75,0x09, +0xB9,0x75,0x08,0x03,0x80,0x0C,0x75,0x0B, +0x00,0x75,0x0A,0x62,0x75,0x09,0x3D,0x75, +0x08,0x01,0x75,0x89,0x11,0xE4,0x7B,0x60, +0x7A,0x09,0xF9,0xF8,0xAF,0x0B,0xAE,0x0A, +0xAD,0x09,0xAC,0x08,0x12,0x00,0x60,0xAA, +0x06,0xAB,0x07,0xC3,0xE4,0x9B,0xFB,0xE4, +0x9A,0xFA,0x78,0x17,0xF6,0xAF,0x03,0xEF, +0x08,0xF6,0x18,0xE6,0xF5,0x8C,0x08,0xE6, +0xF5,0x8A,0x74,0x0D,0x2B,0xFB,0xE4,0x3A, +0x18,0xF6,0xAF,0x03,0xEF,0x08,0xF6,0x75, +0x88,0x10,0x53,0x8E,0xC7,0xD2,0xA9,0x22, +0x7F,0x10,0x7E,0x13,0x12,0x07,0x66,0x90, +0x06,0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE, +0x44,0x10,0xFE,0x90,0x06,0x2D,0xF0,0xA3, +0xEF,0xF0,0x54,0xEF,0xFF,0x90,0x06,0x2D, +0xEE,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD,0x7F, +0x10,0x7E,0x13,0x12,0x07,0xAB,0xE4,0xFF, +0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF,0x64, +0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C,0x00, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, +0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xAB,0xE4,0xFD,0xFC, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D, +0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xAB,0x7F,0x10,0x7E, +0x13,0x12,0x07,0x66,0x90,0x06,0x2D,0xEE, +0xF0,0xA3,0xEF,0xF0,0xEE,0x54,0xEF,0x90, +0x06,0x2D,0xF0,0xFC,0xA3,0xEF,0xF0,0xFD, +0x7F,0x10,0x7E,0x13,0x02,0x07,0xAB,0x78, +0x7F,0xE4,0xF6,0xD8,0xFD,0x75,0x81,0x3C, +0x02,0x05,0xD6,0x02,0x03,0x2F,0xE4,0x93, +0xA3,0xF8,0xE4,0x93,0xA3,0x40,0x03,0xF6, +0x80,0x01,0xF2,0x08,0xDF,0xF4,0x80,0x29, +0xE4,0x93,0xA3,0xF8,0x54,0x07,0x24,0x0C, +0xC8,0xC3,0x33,0xC4,0x54,0x0F,0x44,0x20, +0xC8,0x83,0x40,0x04,0xF4,0x56,0x80,0x01, +0x46,0xF6,0xDF,0xE4,0x80,0x0B,0x01,0x02, +0x04,0x08,0x10,0x20,0x40,0x80,0x90,0x07, +0xE7,0xE4,0x7E,0x01,0x93,0x60,0xBC,0xA3, +0xFF,0x54,0x3F,0x30,0xE5,0x09,0x54,0x1F, +0xFE,0xE4,0x93,0xA3,0x60,0x01,0x0E,0xCF, +0x54,0xC0,0x25,0xE0,0x60,0xA8,0x40,0xB8, +0xE4,0x93,0xA3,0xFA,0xE4,0x93,0xA3,0xF8, +0xE4,0x93,0xA3,0xC8,0xC5,0x82,0xC8,0xCA, +0xC5,0x83,0xCA,0xF0,0xA3,0xC8,0xC5,0x82, +0xC8,0xCA,0xC5,0x83,0xCA,0xDF,0xE9,0xDE, +0xE7,0x80,0xBE,0x7D,0x40,0x7C,0x17,0x7F, +0x11,0x7E,0x1D,0x12,0x07,0xAB,0x7F,0x41, +0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20, +0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E, +0x1D,0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15, +0x7F,0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D, +0x07,0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12, +0x07,0xAB,0x7D,0x40,0x7C,0x11,0x7F,0x00, +0x7E,0x62,0x12,0x07,0xAB,0x02,0x02,0x2F, +0x7D,0xC0,0x7C,0x16,0x7F,0x11,0x7E,0x1D, +0x12,0x07,0xAB,0x7D,0xBB,0x7C,0x15,0x7F, +0xEB,0x7E,0x13,0x12,0x07,0xAB,0x7D,0x0D, +0x7C,0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07, +0xAB,0x7F,0x41,0x7E,0x1D,0x12,0x07,0x66, +0xEF,0x44,0x20,0x44,0x80,0xFD,0xAC,0x06, +0x7F,0x41,0x7E,0x1D,0x12,0x07,0xAB,0x7D, +0x00,0x7C,0x21,0x7F,0x00,0x7E,0x62,0x12, +0x07,0xAB,0x02,0x02,0x2F,0x7D,0x40,0x7C, +0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xAB, +0x7D,0xBB,0x7C,0x15,0x7F,0xEB,0x7E,0x13, +0x12,0x07,0xAB,0x7D,0x0C,0x7C,0x00,0x7F, +0xE7,0x7E,0x13,0x12,0x07,0xAB,0x7F,0x41, +0x7E,0x1D,0x12,0x07,0x66,0xEF,0x44,0x20, +0x44,0x80,0xFD,0xAC,0x06,0x7F,0x41,0x7E, +0x1D,0x12,0x07,0xAB,0x7D,0x40,0x7C,0x11, +0x7F,0x00,0x7E,0x62,0x12,0x07,0xAB,0x02, +0x02,0x2F,0x7D,0x04,0x7C,0x00,0x7F,0x01, +0x7E,0x66,0x12,0x07,0xAB,0x7D,0x80,0x7C, +0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xAB, +0x7F,0x02,0x7E,0x66,0x12,0x07,0x66,0xEF, +0x44,0x02,0x44,0x04,0xFD,0xAC,0x06,0x7F, +0x02,0x7E,0x66,0x12,0x07,0xAB,0x7D,0x04, +0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xAB,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x02,0x07,0xAB,0xC0,0xE0,0xC0,0xF0, +0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75,0xD0, +0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5,0x8C, +0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06,0x31, +0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E,0x90, +0x06,0x33,0xE4,0x75,0xF0,0x01,0x12,0x00, +0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82,0xD0, +0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2,0xAF, +0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D,0xA3, +0x75,0xA0,0x01,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xAE,0xA1, +0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7,0xD2, +0xAF,0x22,0x7D,0x20,0x7C,0x0F,0x7F,0x02, +0x7E,0x66,0x12,0x07,0xAB,0x7D,0x01,0x7C, +0x00,0x7F,0x01,0x7E,0x66,0x12,0x07,0xAB, +0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, +0x02,0x07,0xAB,0xC2,0xAF,0xAB,0x07,0xAA, +0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D, +0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA, +0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x7F, +0x0C,0x7E,0x13,0x12,0x07,0x66,0xEF,0x44, +0x50,0xFD,0xAC,0x06,0x7F,0x0C,0x7E,0x13, +0x02,0x07,0xAB,0x12,0x07,0xC7,0x12,0x07, +0xF2,0x12,0x04,0x2B,0x02,0x00,0x03,0x42, +0x06,0x33,0x00,0x00,0x42,0x06,0x31,0x00, +0x00,0x00,0xE4,0xF5,0x8E,0x22,}; + +#define FIBER2_1G_INIT_SIZE 2032 +rtk_uint8 Fiber2_1G[FIBER2_1G_INIT_SIZE] = { +0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF, +0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0, +0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, +0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, +0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, +0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, +0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, +0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, +0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, +0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, +0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, +0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, +0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, +0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, +0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, +0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, +0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, +0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, +0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, +0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, +0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, +0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, +0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, +0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, +0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, +0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, +0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, +0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, +0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, +0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, +0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, +0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, +0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, +0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, +0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, +0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C, +0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F, +0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04, +0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C, +0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F, +0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84, +0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C, +0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00, +0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4, +0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, +0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, +0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, +0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, +0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, +0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, +0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12, +0x01,0x27,0x12,0x06,0x9F,0x7D,0x41,0x7C, +0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5, +0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF, +0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2, +0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E, +0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07, +0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90, +0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA, +0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90, +0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3, +0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06, +0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0, +0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C, +0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80, +0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, +0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13, +0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0, +0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07, +0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14, +0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60, +0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38, +0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09, +0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B, +0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75, +0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75, +0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05, +0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC, +0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C, +0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09, +0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4, +0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B, +0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00, +0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B, +0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF, +0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C, +0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB, +0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08, +0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2, +0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07, +0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF, +0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D, +0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90, +0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0, +0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5, +0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E, +0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04, +0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F, +0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06, +0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54, +0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF, +0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07, +0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, +0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F, +0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, +0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, +0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, +0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, +0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, +0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, +0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60, +0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, +0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, +0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, +0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, +0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, +0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, +0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, +0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C, +0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5, +0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, +0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, +0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB, +0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07, +0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E, +0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11, +0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02, +0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11, +0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C, +0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5, +0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13, +0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12, +0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD, +0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E, +0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D, +0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12, +0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB, +0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C, +0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5, +0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, +0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, +0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, +0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07, +0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00, +0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07, +0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC, +0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0, +0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0, +0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6, +0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90, +0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00, +0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01, +0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0, +0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32, +0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2, +0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF, +0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB, +0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C, +0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00, +0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF, +0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60, +0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C, +0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1, +0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00, +0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06, +0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,}; + +#define FIBER2_100M_INIT_SIZE 2032 +rtk_uint8 Fiber2_100M[FIBER2_100M_INIT_SIZE] = { +0x02,0x05,0x89,0xE4,0xF5,0xA8,0xD2,0xAF, +0x22,0x00,0x00,0x02,0x07,0x26,0xC5,0xF0, +0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, +0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, +0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, +0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, +0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, +0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, +0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, +0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, +0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, +0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, +0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, +0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, +0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, +0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, +0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, +0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, +0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, +0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, +0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, +0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, +0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, +0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, +0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, +0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, +0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, +0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, +0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, +0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, +0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, +0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, +0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, +0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, +0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0x7D, +0xD7,0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x04,0x7F,0x01, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C, +0x00,0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x94,0x7C,0xF9,0x7F,0x02,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0x81,0x7C,0x04,0x7F, +0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0xA2,0x7C,0x31,0x7F,0x02,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0x82,0x7C,0x04, +0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x60,0x7C,0x69,0x7F,0x02, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0x83,0x7C, +0x04,0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0x28,0x7C,0x97,0x7F, +0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x84, +0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0x85,0x7C,0x9D, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x23,0x7C,0x04,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7D,0x10,0x7C, +0xD8,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x24,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D,0x00, +0x7C,0x04,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x2F,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x60,0xEF,0x44,0x40,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x03,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E, +0x66,0x12,0x07,0x60,0xEF,0x54,0xBF,0xFD, +0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x60,0xEF,0x54,0xFD,0x54,0xFE, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x01,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x80,0x7C,0x00,0x7F,0x00,0x7E, +0x66,0x12,0x07,0xA5,0x7F,0x02,0x7E,0x66, +0x12,0x07,0x60,0xEF,0x44,0x02,0x44,0x01, +0xFD,0xAC,0x06,0x7F,0x02,0x7E,0x66,0x12, +0x07,0xA5,0xE4,0xFD,0xFC,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x02,0x07,0xA5,0xE4, +0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, +0x3F,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, +0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x07, +0xA5,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, +0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, +0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, +0x13,0x12,0x07,0xA5,0x12,0x07,0xD5,0x12, +0x01,0x27,0x12,0x06,0x5A,0x7D,0x41,0x7C, +0x00,0x7F,0x36,0x7E,0x13,0x12,0x07,0xA5, +0xE4,0xFF,0xFE,0xFD,0x80,0x26,0x7F,0xFF, +0x7E,0xFF,0x7D,0x05,0x7C,0x00,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD1,0xC2,0x00,0xC2, +0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01,0x7E, +0x62,0x12,0x07,0x60,0xEF,0x30,0xE2,0x07, +0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE,0x90, +0x06,0x2C,0xE0,0x70,0x12,0x12,0x04,0xEA, +0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4,0x90, +0x06,0x33,0xF0,0xA3,0xF0,0x80,0xD6,0xC3, +0x90,0x06,0x34,0xE0,0x94,0x62,0x90,0x06, +0x33,0xE0,0x94,0x00,0x40,0xC7,0xE4,0xF0, +0xA3,0xF0,0x12,0x04,0xEA,0x90,0x06,0x2C, +0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F,0x80, +0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75,0x0C, +0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E,0x13, +0x12,0x07,0x60,0xEE,0xC4,0xF8,0x54,0xF0, +0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54,0x07, +0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB,0x14, +0x60,0x1C,0x14,0x60,0x27,0x24,0xFE,0x60, +0x31,0x14,0x60,0x3C,0x24,0x05,0x70,0x38, +0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75,0x09, +0xEB,0x75,0x08,0x0B,0x80,0x36,0x75,0x0B, +0x40,0x75,0x0A,0x59,0x75,0x09,0x73,0x75, +0x08,0x07,0x80,0x28,0x75,0x0B,0x00,0x75, +0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08,0x05, +0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A,0xAC, +0x75,0x09,0xB9,0x75,0x08,0x03,0x80,0x0C, +0x75,0x0B,0x00,0x75,0x0A,0x62,0x75,0x09, +0x3D,0x75,0x08,0x01,0x75,0x89,0x11,0xE4, +0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF,0x0B, +0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12,0x00, +0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4,0x9B, +0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6,0xAF, +0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5,0x8C, +0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B,0xFB, +0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF,0x08, +0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7,0xD2, +0xA9,0x22,0x7F,0x10,0x7E,0x13,0x12,0x07, +0x60,0x90,0x06,0x2D,0xEE,0xF0,0xA3,0xEF, +0xF0,0xEE,0x44,0x10,0xFE,0x90,0x06,0x2D, +0xF0,0xA3,0xEF,0xF0,0x54,0xEF,0xFF,0x90, +0x06,0x2D,0xEE,0xF0,0xFC,0xA3,0xEF,0xF0, +0xFD,0x7F,0x10,0x7E,0x13,0x12,0x07,0xA5, +0xE4,0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E, +0xEF,0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04, +0x7C,0x00,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0xE4, +0xFD,0xFC,0x7F,0x02,0x7E,0x66,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E, +0x66,0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x07,0xA5,0x7F, +0x10,0x7E,0x13,0x12,0x07,0x60,0x90,0x06, +0x2D,0xEE,0xF0,0xA3,0xEF,0xF0,0xEE,0x54, +0xEF,0x90,0x06,0x2D,0xF0,0xFC,0xA3,0xEF, +0xF0,0xFD,0x7F,0x10,0x7E,0x13,0x02,0x07, +0xA5,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, +0x81,0x3C,0x02,0x05,0xD0,0x02,0x03,0x2F, +0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, +0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, +0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, +0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, +0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, +0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, +0x90,0x07,0xE1,0xE4,0x7E,0x01,0x93,0x60, +0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, +0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, +0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, +0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, +0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, +0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, +0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, +0xE9,0xDE,0xE7,0x80,0xBE,0x7D,0x40,0x7C, +0x17,0x7F,0x11,0x7E,0x1D,0x12,0x07,0xA5, +0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, +0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, +0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB, +0x7C,0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07, +0xA5,0x7D,0x07,0x7C,0x00,0x7F,0xE7,0x7E, +0x13,0x12,0x07,0xA5,0x7D,0x40,0x7C,0x11, +0x7F,0x00,0x7E,0x62,0x12,0x07,0xA5,0x02, +0x02,0x2F,0x7D,0xC0,0x7C,0x16,0x7F,0x11, +0x7E,0x1D,0x12,0x07,0xA5,0x7D,0xBB,0x7C, +0x15,0x7F,0xEB,0x7E,0x13,0x12,0x07,0xA5, +0x7D,0x0D,0x7C,0x00,0x7F,0xE7,0x7E,0x13, +0x12,0x07,0xA5,0x7F,0x41,0x7E,0x1D,0x12, +0x07,0x60,0xEF,0x44,0x20,0x44,0x80,0xFD, +0xAC,0x06,0x7F,0x41,0x7E,0x1D,0x12,0x07, +0xA5,0x7D,0x00,0x7C,0x21,0x7F,0x00,0x7E, +0x62,0x12,0x07,0xA5,0x02,0x02,0x2F,0x7D, +0x40,0x7C,0x17,0x7F,0x11,0x7E,0x1D,0x12, +0x07,0xA5,0x7D,0xBB,0x7C,0x15,0x7F,0xEB, +0x7E,0x13,0x12,0x07,0xA5,0x7D,0x0C,0x7C, +0x00,0x7F,0xE7,0x7E,0x13,0x12,0x07,0xA5, +0x7F,0x41,0x7E,0x1D,0x12,0x07,0x60,0xEF, +0x44,0x20,0x44,0x80,0xFD,0xAC,0x06,0x7F, +0x41,0x7E,0x1D,0x12,0x07,0xA5,0x7D,0x40, +0x7C,0x11,0x7F,0x00,0x7E,0x62,0x12,0x07, +0xA5,0x02,0x02,0x2F,0x7D,0x04,0x7C,0x00, +0x7F,0x01,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x80,0x7C,0x00,0x7F,0x00,0x7E,0x66,0x12, +0x07,0xA5,0x7F,0x02,0x7E,0x66,0x12,0x07, +0x60,0xEF,0x44,0x02,0x44,0x04,0xFD,0xAC, +0x06,0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5, +0x7D,0x04,0x7C,0x00,0x7F,0x01,0x7E,0x66, +0x12,0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x02,0x07,0xA5,0xC0,0xE0, +0xC0,0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0, +0x75,0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6, +0xF5,0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90, +0x06,0x31,0xE4,0x75,0xF0,0x01,0x12,0x00, +0x0E,0x90,0x06,0x33,0xE4,0x75,0xF0,0x01, +0x12,0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0, +0x82,0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32, +0xC2,0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2, +0x8D,0xA3,0x75,0xA0,0x01,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0xAE,0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF, +0xA7,0xD2,0xAF,0x22,0x7D,0x20,0x7C,0x0F, +0x7F,0x02,0x7E,0x66,0x12,0x07,0xA5,0x7D, +0x01,0x7C,0x00,0x7F,0x01,0x7E,0x66,0x12, +0x07,0xA5,0x7D,0xC0,0x7C,0x00,0x7F,0x00, +0x7E,0x66,0x02,0x07,0xA5,0xC2,0xAF,0xAB, +0x07,0xAA,0x06,0x8A,0xA2,0x8B,0xA3,0x8C, +0xA4,0x8D,0xA5,0x75,0xA0,0x03,0x00,0x00, +0x00,0xAA,0xA1,0xBA,0x00,0xF8,0xD2,0xAF, +0x22,0x7F,0x0C,0x7E,0x13,0x12,0x07,0x60, +0xEF,0x44,0x50,0xFD,0xAC,0x06,0x7F,0x0C, +0x7E,0x13,0x02,0x07,0xA5,0x12,0x07,0xC1, +0x12,0x07,0xEC,0x12,0x04,0x25,0x02,0x00, +0x03,0x42,0x06,0x33,0x00,0x00,0x42,0x06, +0x31,0x00,0x00,0x00,0xE4,0xF5,0x8E,0x22,}; + + +#define SGMII_INIT_SIZE 1183 +rtk_uint8 Sgmii_Init[SGMII_INIT_SIZE] = { +0x02,0x03,0x81,0xE4,0xF5,0xA8,0xD2,0xAF, +0x22,0x00,0x00,0x02,0x04,0x0D,0xC5,0xF0, +0xF8,0xA3,0xE0,0x28,0xF0,0xC5,0xF0,0xF8, +0xE5,0x82,0x15,0x82,0x70,0x02,0x15,0x83, +0xE0,0x38,0xF0,0x22,0x75,0xF0,0x08,0x75, +0x82,0x00,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xCD,0x33,0xCD,0xCC,0x33,0xCC,0xC5,0x82, +0x33,0xC5,0x82,0x9B,0xED,0x9A,0xEC,0x99, +0xE5,0x82,0x98,0x40,0x0C,0xF5,0x82,0xEE, +0x9B,0xFE,0xED,0x9A,0xFD,0xEC,0x99,0xFC, +0x0F,0xD5,0xF0,0xD6,0xE4,0xCE,0xFB,0xE4, +0xCD,0xFA,0xE4,0xCC,0xF9,0xA8,0x82,0x22, +0xB8,0x00,0xC1,0xB9,0x00,0x59,0xBA,0x00, +0x2D,0xEC,0x8B,0xF0,0x84,0xCF,0xCE,0xCD, +0xFC,0xE5,0xF0,0xCB,0xF9,0x78,0x18,0xEF, +0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33,0xFD, +0xEC,0x33,0xFC,0xEB,0x33,0xFB,0x10,0xD7, +0x03,0x99,0x40,0x04,0xEB,0x99,0xFB,0x0F, +0xD8,0xE5,0xE4,0xF9,0xFA,0x22,0x78,0x18, +0xEF,0x2F,0xFF,0xEE,0x33,0xFE,0xED,0x33, +0xFD,0xEC,0x33,0xFC,0xC9,0x33,0xC9,0x10, +0xD7,0x05,0x9B,0xE9,0x9A,0x40,0x07,0xEC, +0x9B,0xFC,0xE9,0x9A,0xF9,0x0F,0xD8,0xE0, +0xE4,0xC9,0xFA,0xE4,0xCC,0xFB,0x22,0x75, +0xF0,0x10,0xEF,0x2F,0xFF,0xEE,0x33,0xFE, +0xED,0x33,0xFD,0xCC,0x33,0xCC,0xC8,0x33, +0xC8,0x10,0xD7,0x07,0x9B,0xEC,0x9A,0xE8, +0x99,0x40,0x0A,0xED,0x9B,0xFD,0xEC,0x9A, +0xFC,0xE8,0x99,0xF8,0x0F,0xD5,0xF0,0xDA, +0xE4,0xCD,0xFB,0xE4,0xCC,0xFA,0xE4,0xC8, +0xF9,0x22,0xEB,0x9F,0xF5,0xF0,0xEA,0x9E, +0x42,0xF0,0xE9,0x9D,0x42,0xF0,0xE8,0x9C, +0x45,0xF0,0x22,0xE0,0xFC,0xA3,0xE0,0xFD, +0xA3,0xE0,0xFE,0xA3,0xE0,0xFF,0x22,0xE0, +0xF8,0xA3,0xE0,0xF9,0xA3,0xE0,0xFA,0xA3, +0xE0,0xFB,0x22,0xEC,0xF0,0xA3,0xED,0xF0, +0xA3,0xEE,0xF0,0xA3,0xEF,0xF0,0x22,0xE4, +0x90,0x06,0x2C,0xF0,0xFD,0x7C,0x01,0x7F, +0x3F,0x7E,0x1D,0x12,0x04,0x6B,0x7D,0x40, +0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12,0x04, +0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25,0xE4, +0x7F,0xFF,0x7E,0xFF,0xFD,0xFC,0x90,0x06, +0x24,0x12,0x01,0x0F,0xC3,0x12,0x00,0xF2, +0x50,0x1B,0x90,0x06,0x24,0x12,0x01,0x03, +0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE,0xE4, +0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06,0x24, +0x12,0x01,0x1B,0x80,0xD2,0xE4,0xF5,0xA8, +0xD2,0xAF,0x7D,0x1F,0xFC,0x7F,0x49,0x7E, +0x13,0x12,0x04,0x6B,0x12,0x04,0x92,0x7D, +0x41,0x7C,0x00,0x7F,0x36,0x7E,0x13,0x12, +0x04,0x6B,0xE4,0xFF,0xFE,0xFD,0x80,0x25, +0xE4,0x7F,0x20,0x7E,0x4E,0xFD,0xFC,0x90, +0x06,0x24,0x12,0x01,0x0F,0xC3,0x12,0x00, +0xF2,0x50,0x1B,0x90,0x06,0x24,0x12,0x01, +0x03,0xEF,0x24,0x01,0xFF,0xE4,0x3E,0xFE, +0xE4,0x3D,0xFD,0xE4,0x3C,0xFC,0x90,0x06, +0x24,0x12,0x01,0x1B,0x80,0xD2,0xC2,0x00, +0xC2,0x01,0xD2,0xA9,0xD2,0x8C,0x7F,0x01, +0x7E,0x62,0x12,0x04,0x47,0xEF,0x30,0xE2, +0x07,0xE4,0x90,0x06,0x2C,0xF0,0x80,0xEE, +0x90,0x06,0x2C,0xE0,0x70,0x12,0x12,0x02, +0xDB,0x90,0x06,0x2C,0x74,0x01,0xF0,0xE4, +0x90,0x06,0x2F,0xF0,0xA3,0xF0,0x80,0xD6, +0xC3,0x90,0x06,0x30,0xE0,0x94,0x62,0x90, +0x06,0x2F,0xE0,0x94,0x00,0x40,0xC7,0xE4, +0xF0,0xA3,0xF0,0x12,0x02,0xDB,0x90,0x06, +0x2C,0x74,0x01,0xF0,0x80,0xB8,0x75,0x0F, +0x80,0x75,0x0E,0x7E,0x75,0x0D,0xAA,0x75, +0x0C,0x83,0xE4,0xF5,0x10,0x7F,0x36,0x7E, +0x13,0x12,0x04,0x47,0xEE,0xC4,0xF8,0x54, +0xF0,0xC8,0xEF,0xC4,0x54,0x0F,0x48,0x54, +0x07,0xFB,0x7A,0x00,0xEA,0x70,0x4A,0xEB, +0x14,0x60,0x1C,0x14,0x60,0x27,0x24,0xFE, +0x60,0x31,0x14,0x60,0x3C,0x24,0x05,0x70, +0x38,0x75,0x0B,0x00,0x75,0x0A,0xC2,0x75, +0x09,0xEB,0x75,0x08,0x0B,0x80,0x36,0x75, +0x0B,0x40,0x75,0x0A,0x59,0x75,0x09,0x73, +0x75,0x08,0x07,0x80,0x28,0x75,0x0B,0x00, +0x75,0x0A,0xE1,0x75,0x09,0xF5,0x75,0x08, +0x05,0x80,0x1A,0x75,0x0B,0xA0,0x75,0x0A, +0xAC,0x75,0x09,0xB9,0x75,0x08,0x03,0x80, +0x0C,0x75,0x0B,0x00,0x75,0x0A,0x62,0x75, +0x09,0x3D,0x75,0x08,0x01,0x75,0x89,0x11, +0xE4,0x7B,0x60,0x7A,0x09,0xF9,0xF8,0xAF, +0x0B,0xAE,0x0A,0xAD,0x09,0xAC,0x08,0x12, +0x00,0x60,0xAA,0x06,0xAB,0x07,0xC3,0xE4, +0x9B,0xFB,0xE4,0x9A,0xFA,0x78,0x17,0xF6, +0xAF,0x03,0xEF,0x08,0xF6,0x18,0xE6,0xF5, +0x8C,0x08,0xE6,0xF5,0x8A,0x74,0x0D,0x2B, +0xFB,0xE4,0x3A,0x18,0xF6,0xAF,0x03,0xEF, +0x08,0xF6,0x75,0x88,0x10,0x53,0x8E,0xC7, +0xD2,0xA9,0x22,0x7D,0x02,0x7C,0x00,0x7F, +0x4A,0x7E,0x13,0x12,0x04,0x6B,0x7D,0x46, +0x7C,0x71,0x7F,0x02,0x7E,0x66,0x12,0x04, +0x6B,0x7D,0x03,0x7C,0x00,0x7F,0x01,0x7E, +0x66,0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00, +0x7F,0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4, +0xFF,0xFE,0x0F,0xBF,0x00,0x01,0x0E,0xEF, +0x64,0x64,0x4E,0x70,0xF5,0x7D,0x04,0x7C, +0x00,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B, +0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD, +0xFC,0x7F,0x02,0x7E,0x66,0x12,0x04,0x6B, +0x7D,0x00,0x7C,0x04,0x7F,0x01,0x7E,0x66, +0x12,0x04,0x6B,0x7D,0xC0,0x7C,0x00,0x7F, +0x00,0x7E,0x66,0x12,0x04,0x6B,0xE4,0xFD, +0xFC,0x7F,0x4A,0x7E,0x13,0x12,0x04,0x6B, +0x7D,0x06,0x7C,0x71,0x7F,0x02,0x7E,0x66, +0x12,0x04,0x6B,0x7D,0x03,0x7C,0x00,0x7F, +0x01,0x7E,0x66,0x12,0x04,0x6B,0x7D,0xC0, +0x7C,0x00,0x7F,0x00,0x7E,0x66,0x02,0x04, +0x6B,0x78,0x7F,0xE4,0xF6,0xD8,0xFD,0x75, +0x81,0x3C,0x02,0x03,0xC8,0x02,0x01,0x27, +0xE4,0x93,0xA3,0xF8,0xE4,0x93,0xA3,0x40, +0x03,0xF6,0x80,0x01,0xF2,0x08,0xDF,0xF4, +0x80,0x29,0xE4,0x93,0xA3,0xF8,0x54,0x07, +0x24,0x0C,0xC8,0xC3,0x33,0xC4,0x54,0x0F, +0x44,0x20,0xC8,0x83,0x40,0x04,0xF4,0x56, +0x80,0x01,0x46,0xF6,0xDF,0xE4,0x80,0x0B, +0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, +0x90,0x04,0x87,0xE4,0x7E,0x01,0x93,0x60, +0xBC,0xA3,0xFF,0x54,0x3F,0x30,0xE5,0x09, +0x54,0x1F,0xFE,0xE4,0x93,0xA3,0x60,0x01, +0x0E,0xCF,0x54,0xC0,0x25,0xE0,0x60,0xA8, +0x40,0xB8,0xE4,0x93,0xA3,0xFA,0xE4,0x93, +0xA3,0xF8,0xE4,0x93,0xA3,0xC8,0xC5,0x82, +0xC8,0xCA,0xC5,0x83,0xCA,0xF0,0xA3,0xC8, +0xC5,0x82,0xC8,0xCA,0xC5,0x83,0xCA,0xDF, +0xE9,0xDE,0xE7,0x80,0xBE,0xC0,0xE0,0xC0, +0xF0,0xC0,0x83,0xC0,0x82,0xC0,0xD0,0x75, +0xD0,0x00,0xC0,0x00,0x78,0x17,0xE6,0xF5, +0x8C,0x78,0x18,0xE6,0xF5,0x8A,0x90,0x06, +0x2D,0xE4,0x75,0xF0,0x01,0x12,0x00,0x0E, +0x90,0x06,0x2F,0xE4,0x75,0xF0,0x01,0x12, +0x00,0x0E,0xD0,0x00,0xD0,0xD0,0xD0,0x82, +0xD0,0x83,0xD0,0xF0,0xD0,0xE0,0x32,0xC2, +0xAF,0xAD,0x07,0xAC,0x06,0x8C,0xA2,0x8D, +0xA3,0x75,0xA0,0x01,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAE, +0xA1,0xBE,0x00,0xF0,0xAE,0xA6,0xAF,0xA7, +0xD2,0xAF,0x22,0xC2,0xAF,0xAB,0x07,0xAA, +0x06,0x8A,0xA2,0x8B,0xA3,0x8C,0xA4,0x8D, +0xA5,0x75,0xA0,0x03,0x00,0x00,0x00,0xAA, +0xA1,0xBA,0x00,0xF8,0xD2,0xAF,0x22,0x42, +0x06,0x2F,0x00,0x00,0x42,0x06,0x2D,0x00, +0x00,0x00,0x12,0x04,0x9B,0x12,0x02,0x16, +0x02,0x00,0x03,0xE4,0xF5,0x8E,0x22,}; + + +/* Function Name: + * rtl8367c_setAsicPortUnknownDaBehavior + * Description: + * Set UNDA behavior + * Input: + * port - port ID + * behavior - 0: flooding to unknown DA portmask; 1: drop; 2:trap; 3: flooding + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid behavior + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 behavior) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(behavior >= L2_UNDA_BEHAVE_END) + return RT_ERR_NOT_ALLOWED; + + if(port < 8) + return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), behavior); + else + return rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), behavior); +} +/* Function Name: + * rtl8367c_getAsicPortUnknownDaBehavior + * Description: + * Get UNDA behavior + * Input: + * port - port ID + * Output: + * pBehavior - 0: flooding to unknown DA portmask; 1: drop; 2:trap; 3: flooding + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnknownDaBehavior(rtk_uint32 port, rtk_uint32 *pBehavior) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE, RTL8367C_Port0_ACTION_MASK << (port * 2), pBehavior); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_UNICAST_DA_PORT_BEHAVE_EXT, RTL8367C_PORT8_ACTION_MASK << ((port-8) * 2), pBehavior); +} +/* Function Name: + * rtl8367c_setAsicPortUnknownSaBehavior + * Description: + * Set UNSA behavior + * Input: + * behavior - 0: flooding; 1: drop; 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid behavior + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnknownSaBehavior(rtk_uint32 behavior) +{ + if(behavior >= L2_BEHAVE_SA_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, behavior); +} +/* Function Name: + * rtl8367c_getAsicPortUnknownSaBehavior + * Description: + * Get UNSA behavior + * Input: + * pBehavior - 0: flooding; 1: drop; 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnknownSaBehavior(rtk_uint32 *pBehavior) +{ + return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNKNOWN_SA_BEHAVE_MASK, pBehavior); +} +/* Function Name: + * rtl8367c_setAsicPortUnmatchedSaBehavior + * Description: + * Set Unmatched SA behavior + * Input: + * behavior - 0: flooding; 1: drop; 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid behavior + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnmatchedSaBehavior(rtk_uint32 behavior) +{ + if(behavior >= L2_BEHAVE_SA_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, behavior); +} +/* Function Name: + * rtl8367c_getAsicPortUnmatchedSaBehavior + * Description: + * Get Unmatched SA behavior + * Input: + * pBehavior - 0: flooding; 1: drop; 2:trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnmatchedSaBehavior(rtk_uint32 *pBehavior) +{ + return rtl8367c_getAsicRegBits(RTL8367C_PORT_SECURIT_CTRL_REG, RTL8367C_UNMATCHED_SA_BEHAVE_MASK, pBehavior); +} + +/* Function Name: + * rtl8367c_setAsicPortUnmatchedSaMoving + * Description: + * Set Unmatched SA moving state + * Input: + * port - Port ID + * enabled - 0: can't move to new port; 1: can move to new port + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Error Port ID + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, (enabled == 1) ? 0 : 1); +} + +/* Function Name: + * rtl8367c_getAsicPortUnmatchedSaMoving + * Description: + * Get Unmatched SA moving state + * Input: + * port - Port ID + * Output: + * pEnabled - 0: can't move to new port; 1: can move to new port + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Error Port ID + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnmatchedSaMoving(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + rtk_uint32 data; + ret_t retVal; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_L2_SA_MOVING_FORBID, port, &data)) != RT_ERR_OK) + return retVal; + + *pEnabled = (data == 1) ? 0 : 1; + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicPortUnknownDaFloodingPortmask + * Description: + * Set UNDA flooding portmask + * Input: + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnknownDaFloodingPortmask(rtk_uint32 portmask) +{ + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, portmask); +} +/* Function Name: + * rtl8367c_getAsicPortUnknownDaFloodingPortmask + * Description: + * Get UNDA flooding portmask + * Input: + * pPortmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnknownDaFloodingPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_UNUCAST_FLOADING_PMSK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicPortUnknownMulticastFloodingPortmask + * Description: + * Set UNMC flooding portmask + * Input: + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 portmask) +{ + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, portmask); +} +/* Function Name: + * rtl8367c_getAsicPortUnknownMulticastFloodingPortmask + * Description: + * Get UNMC flooding portmask + * Input: + * pPortmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortUnknownMulticastFloodingPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_UNMCAST_FLOADING_PMSK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicPortBcastFloodingPortmask + * Description: + * Set Bcast flooding portmask + * Input: + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicPortBcastFloodingPortmask(rtk_uint32 portmask) +{ + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, portmask); +} +/* Function Name: + * rtl8367c_getAsicPortBcastFloodingPortmask + * Description: + * Get Bcast flooding portmask + * Input: + * pPortmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortBcastFloodingPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_BCAST_FLOADING_PMSK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicPortBlockSpa + * Description: + * Set disabling blocking frame if source port and destination port are the same + * Input: + * port - Physical port number (0~7) + * permit - 0: block; 1: permit + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortBlockSpa(rtk_uint32 port, rtk_uint32 permit) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, permit); +} +/* Function Name: + * rtl8367c_getAsicPortBlockSpa + * Description: + * Get disabling blocking frame if source port and destination port are the same + * Input: + * port - Physical port number (0~7) + * pPermit - 0: block; 1: permit + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortBlockSpa(rtk_uint32 port, rtk_uint32* pPermit) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_SOURCE_PORT_BLOCK_REG, port, pPermit); +} +/* Function Name: + * rtl8367c_setAsicPortDos + * Description: + * Set DOS function + * Input: + * type - DOS type + * drop - 0: permit; 1: drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid payload index + * Note: + * None + */ +ret_t rtl8367c_setAsicPortDos(rtk_uint32 type, rtk_uint32 drop) +{ + if(type >= DOS_END) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type, drop); +} +/* Function Name: + * rtl8367c_getAsicPortDos + * Description: + * Get DOS function + * Input: + * type - DOS type + * pDrop - 0: permit; 1: drop + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid payload index + * Note: + * None + */ +ret_t rtl8367c_getAsicPortDos(rtk_uint32 type, rtk_uint32* pDrop) +{ + if(type >= DOS_END) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_DOS_CFG, RTL8367C_DROP_DAEQSA_OFFSET + type,pDrop); +} +/* Function Name: + * rtl8367c_setAsicPortForceLink + * Description: + * Set port force linking configuration + * Input: + * port - Physical port number (0~7) + * pPortAbility - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility) +{ + rtk_uint32 regData = 0; + + /* Invalid input parameter */ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + regData |= pPortAbility->forcemode << 12; + regData |= pPortAbility->mstfault << 9; + regData |= pPortAbility->mstmode << 8; + regData |= pPortAbility->nway << 7; + regData |= pPortAbility->txpause << 6; + regData |= pPortAbility->rxpause << 5; + regData |= pPortAbility->link << 4; + regData |= pPortAbility->duplex << 2; + regData |= pPortAbility->speed; + + return rtl8367c_setAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT+port, regData); +} +/* Function Name: + * rtl8367c_getAsicPortForceLink + * Description: + * Get port force linking configuration + * Input: + * port - Physical port number (0~7) + * pPortAbility - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortForceLink(rtk_uint32 port, rtl8367c_port_ability_t *pPortAbility) +{ + ret_t retVal; + rtk_uint32 regData; + + /* Invalid input parameter */ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_MAC0_FORCE_SELECT + port, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (regData >> 12) & 0x0001; + pPortAbility->mstfault = (regData >> 9) & 0x0001; + pPortAbility->mstmode = (regData >> 8) & 0x0001; + pPortAbility->nway = (regData >> 7) & 0x0001; + pPortAbility->txpause = (regData >> 6) & 0x0001; + pPortAbility->rxpause = (regData >> 5) & 0x0001; + pPortAbility->link = (regData >> 4) & 0x0001; + pPortAbility->duplex = (regData >> 2) & 0x0001; + pPortAbility->speed = regData & 0x0003; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicPortStatus + * Description: + * Get port link status + * Input: + * port - Physical port number (0~7) + * pPortAbility - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortStatus(rtk_uint32 port, rtl8367c_port_status_t *pPortStatus) +{ + ret_t retVal; + rtk_uint32 regData; + + /* Invalid input parameter */ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_PORT0_STATUS+port,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pPortStatus->lpi1000 = (regData >> 11) & 0x0001; + pPortStatus->lpi100 = (regData >> 10) & 0x0001; + pPortStatus->mstfault = (regData >> 9) & 0x0001; + pPortStatus->mstmode = (regData >> 8) & 0x0001; + pPortStatus->nway = (regData >> 7) & 0x0001; + pPortStatus->txpause = (regData >> 6) & 0x0001; + pPortStatus->rxpause = (regData >> 5) & 0x0001; + pPortStatus->link = (regData >> 4) & 0x0001; + pPortStatus->duplex = (regData >> 2) & 0x0001; + pPortStatus->speed = regData & 0x0003; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPortForceLinkExt + * Description: + * Set external interface force linking configuration + * Input: + * id - external interface id (0~2) + * portAbility - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility) +{ + rtk_uint32 retVal, regValue, regValue2, type, sgmiibit, hisgmiibit; + rtk_uint32 reg_data = 0; + rtk_uint32 i = 0; + + /* Invalid input parameter */ + if(id >= RTL8367C_EXTNO) + return RT_ERR_OUT_OF_RANGE; + + reg_data |= pPortAbility->forcemode << 12; + reg_data |= pPortAbility->mstfault << 9; + reg_data |= pPortAbility->mstmode << 8; + reg_data |= pPortAbility->nway << 7; + reg_data |= pPortAbility->txpause << 6; + reg_data |= pPortAbility->rxpause << 5; + reg_data |= pPortAbility->link << 4; + reg_data |= pPortAbility->duplex << 2; + reg_data |= pPortAbility->speed; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + /*get chip ID */ + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + type = 0; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 1; + break; + case 0x0652: + case 0x6368: + type = 2; + break; + case 0x0801: + case 0x6511: + type = 3; + break; + default: + return RT_ERR_FAILED; + } + + if (1 == type) + { + if(1 == id) + { + if ((retVal = rtl8367c_getAsicReg(RTL8367C_REG_REG_TO_ECO4, ®Value)) != RT_ERR_OK) + return retVal; + + if((regValue & (0x0001 << 5)) && (regValue & (0x0001 << 7))) + { + return RT_ERR_OK; + } + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + } + + if(0 == id || 1 == id) + return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE + id, reg_data); + else + return rtl8367c_setAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, reg_data); + } + else if (2 == type) + { + if (1 == id) + { + if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->link == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) + return retVal; + } + + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + } + else if (2 == id) + { + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->link == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK) + return retVal; + } + + if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1dc1, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1dc1, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + } + + } + else if(3 == type) + { + if(1 == id) + { + if((retVal = rtl8367c_getAsicRegBit(0x1d11, 6, &sgmiibit)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, &hisgmiibit)) != RT_ERR_OK) + return retVal; + + if ((sgmiibit == 1) || (hisgmiibit == 1)) + { + /*for 1000x/100fx/1000x_100fx, param has to be set to serdes registers*/ + if((retVal = rtl8367c_getAsicReg(0x1d41, ®Value)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib =1, bit7: cfg_mac6_fib2=1*/ + if((regValue & 0xa0) == 0xa0) + { + /* new_cfg_sds_mode */ + if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) + return retVal; + + /*1000X*/ + if(regValue2 == 0x4) + { +#if 0 + /* new_cfg_sds_mode:reset mode */ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + /* Enable new sds mode config */ + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0x9000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFDFFF; + reg_data |= 0x40; + if(pPortAbility->forcemode) + reg_data &= 0xffffefff; + else + reg_data |= 0x1000; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= (~0x80); + + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= (~0x100); + + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /*new_cfg_sds_mode=1000x*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) + return retVal; + + } + else if(regValue2 == 0x5) + { +#if 0 + /*100FX*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + /*cfg_sds_mode_sel_new=1 */ + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0xB000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFFBF; + reg_data |= 0x2000; + reg_data &= 0xffffefff; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= (~0x80); + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= (~0x100); + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + /* new_cfg_sds_mode=1000x */ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) + return retVal; + + } + else if(regValue2 == 0x7) + { +#if 0 + /*100FX*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0x9000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFDFFF; + reg_data |= 0x40; + if(pPortAbility->forcemode) + reg_data &= 0xffffefff; + else + reg_data |= 0x1000; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= (~0x80); + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &=(~0x100); + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0xB000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFFBF; + reg_data |= 0x2000; + reg_data &= 0xffffefff; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= 0xffffff7f; + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= 0xfffffeff; + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + /*sds_mode:*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) + return retVal; + + } + + /*disable force ability --- */ + if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + + } + + /* new_cfg_sds_mode */ + if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) + return retVal; + if(regValue2 == 0x2) + { +#if 0 + /*SGMII*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + /* 0 2 0 bit 8-9 nway*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xfffffcff; + if (pPortAbility->nway) + reg_data &= 0xfffffcff; + else + reg_data |= 0x100; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + /*disable force ability --- */ + if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + else if(regValue2 == 0x12) + { +#if 0 + /*HiSGMII*/ + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + /* 0 2 0 bit 8-9 nway*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xfffffcff; + if (pPortAbility->nway) + reg_data &= 0xfffffcff; + else + reg_data |= 0x100; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + if((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0x1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + /*disable force ability --- */ + if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + + } + } + else + { + if((retVal = rtl8367c_getAsicRegBits(0x1d3d, 10, ®Value2)) != RT_ERR_OK) + return retVal; + if (regValue2 == 0) + { + /*ext1_force_ablty*/ + if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + /*force mode for ext1*/ + if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->link == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) + return retVal; + } + + /*disable force ability --- */ + if((retVal = rtl8367c_setAsicRegBit(0x137c, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + } + + + } + else if (2 == id) + { + + if((retVal = rtl8367c_getAsicRegBit(0x1d95, 0, &sgmiibit)) != RT_ERR_OK) + return retVal; + if (sgmiibit == 1) + { + /*for 1000x/100fx/1000x_100fx, param has to bet set to serdes registers*/ + if((retVal = rtl8367c_getAsicReg(0x1d95, ®Value)) != RT_ERR_OK) + return retVal; + /*cfg_mac7_sel_sgmii=1 & cfg_mac7_fib =1*/ + if((regValue & 0x3) == 0x3) + { + if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) + return retVal; + + if(regValue2 == 0x4) + { + /*1000X*/ +#if 0 + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0x9000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFDFFF; + reg_data |= 0x40; + if(pPortAbility->forcemode) + reg_data &= 0xffffefff; + else + reg_data |= 0x1000; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= 0xffffff7f; + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= 0xfffffeff; + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) + return retVal; + + } + else if(regValue2 == 0x5) + { + /*100FX*/ +#if 0 + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0xB000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFFBF; + reg_data |= 0x2000; + reg_data &= 0xffffefff; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= 0xffffff7f; + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= 0xfffffeff; + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) + return retVal; + + } + else if(regValue2 == 0x7) + { + /*100FX*/ +#if 0 + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 4*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0x9000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 1, bit13 set to 0, bit12 nway_en*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFDFFF; + reg_data |= 0x40; + if(pPortAbility->forcemode) + reg_data &= 0xffffefff; + else + reg_data |= 0x1000; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= 0xffffff7f; + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= 0xfffffeff; + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 1, bit15~13 = 5*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFF0FFF; + reg_data |= 0xB000; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 0 2 bit 6 set 0, bit13 set to 1, bit12 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFFBF; + reg_data |= 0x2000; + reg_data &= 0xffffefff; + + if((retVal = rtl8367c_setAsicSdsReg(0,0,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 2 bit 8 rx pause, bit7 tx pause*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 2, ®_data)) != RT_ERR_OK) + return retVal; + if (pPortAbility->txpause) + reg_data |= 0x80; + else + reg_data &= 0xffffff7f; + if (pPortAbility->rxpause) + reg_data |= 0x100; + else + reg_data &= 0xfffffeff; + if((retVal = rtl8367c_setAsicSdsReg(0,4,2, reg_data)) != RT_ERR_OK) + return retVal; + + /* 0 4 0 bit 12 set 0*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFEFFF; + if((retVal = rtl8367c_setAsicSdsReg(0,4,0, reg_data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) + return retVal; + + } + + if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + + } + /* new_cfg_sds_mode */ + if((retVal = rtl8367c_getAsicRegBits(0x1d95, 0x1f00, ®Value2)) != RT_ERR_OK) + return retVal; + if(regValue2 == 0x2) + { + /*SGMII*/ +#if 0 + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; +#endif + if((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + /* 0 2 0 bit 8-9 nway*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xfffffcff; + if (pPortAbility->nway) + reg_data &= 0xfffffcff; + else + reg_data |= 0x100; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) + return retVal; + + for(i=0;i<0xfff; i++); + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + } + else + { + + /*ext2_force_ablty*/ + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 2, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 6, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 5, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + /*force mode for ext2*/ + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 12, pPortAbility->forcemode)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->link == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x13c4, 4, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(0x13c4, 0x3, 2)) != RT_ERR_OK) + return retVal; + } + + + if((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x1311, 2, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, pPortAbility->link)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 6, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 5, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + /*force mode for ext1*/ + if((retVal = rtl8367c_setAsicRegBit(0x1311, 12, pPortAbility->forcemode)) != RT_ERR_OK) + return retVal; + + if (pPortAbility->link == 1) + { + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(0x1311, 4, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(0x1311, 0x3, 2)) != RT_ERR_OK) + return retVal; + } + } + + + } + + /*disable force ability --- */ + if((retVal = rtl8367c_setAsicRegBit(0x137d, 12, 0)) != RT_ERR_OK) + return retVal; + } +#if 0 + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, pPortAbility->duplex)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, pPortAbility->speed)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, pPortAbility->txpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, pPortAbility->rxpause)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, pPortAbility->link)) != RT_ERR_OK) + return retVal; +#endif + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicPortForceLinkExt + * Description: + * Get external interface force linking configuration + * Input: + * id - external interface id (0~1) + * pPortAbility - port ability configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicPortForceLinkExt(rtk_uint32 id, rtl8367c_port_ability_t *pPortAbility) +{ + rtk_uint32 reg_data, regValue, type; + rtk_uint32 sgmiiSel; + rtk_uint32 hsgmiiSel; + ret_t retVal; + + /* Invalid input parameter */ + if(id >= RTL8367C_EXTNO) + return RT_ERR_OUT_OF_RANGE; + /*cfg_magic_id & get chip_id*/ + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + type = 0; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 1; + break; + case 0x0652: + case 0x6368: + type = 2; + break; + case 0x0801: + case 0x6511: + type = 3; + break; + default: + return RT_ERR_FAILED; + } + + if (1 == type) + { + if(1 == id) + { + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, &sgmiiSel)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, &hsgmiiSel)) != RT_ERR_OK) + return retVal; + + if( (sgmiiSel == 1) || (hsgmiiSel == 1) ) + { + memset(pPortAbility, 0x00, sizeof(rtl8367c_port_ability_t)); + pPortAbility->forcemode = 1; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_FDUP_OFFSET, ®_data)) != RT_ERR_OK) + return retVal; + + pPortAbility->duplex = reg_data; + + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_SPD_MASK, ®_data)) != RT_ERR_OK) + return retVal; + + pPortAbility->speed = reg_data; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_LINK_OFFSET, ®_data)) != RT_ERR_OK) + return retVal; + + pPortAbility->link = reg_data; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_TXFC_OFFSET, ®_data)) != RT_ERR_OK) + return retVal; + + pPortAbility->txpause = reg_data; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_SGMII_RXFC_OFFSET, ®_data)) != RT_ERR_OK) + return retVal; + + pPortAbility->rxpause = reg_data; + + return RT_ERR_OK; + } + } + + if(0 == id || 1 == id) + retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE0_FORCE+id, ®_data); + else + retVal = rtl8367c_getAsicReg(RTL8367C_REG_DIGITAL_INTERFACE2_FORCE, ®_data); + + if(retVal != RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (reg_data >> 12) & 0x0001; + pPortAbility->mstfault = (reg_data >> 9) & 0x0001; + pPortAbility->mstmode = (reg_data >> 8) & 0x0001; + pPortAbility->nway = (reg_data >> 7) & 0x0001; + pPortAbility->txpause = (reg_data >> 6) & 0x0001; + pPortAbility->rxpause = (reg_data >> 5) & 0x0001; + pPortAbility->link = (reg_data >> 4) & 0x0001; + pPortAbility->duplex = (reg_data >> 2) & 0x0001; + pPortAbility->speed = reg_data & 0x0003; + } + else if (2 == type) + { + if (id == 1) + { + if ((retVal = rtl8367c_getAsicReg(0x1311, ®_data))!=RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (reg_data >> 12) & 1; + pPortAbility->duplex = (reg_data >> 2) & 1; + pPortAbility->link = (reg_data >> 4) & 1; + pPortAbility->speed = reg_data & 3; + pPortAbility->rxpause = (reg_data >> 5) & 1; + pPortAbility->txpause = (reg_data >> 6) & 1; + } + else if (2 == id) + { + if ((retVal = rtl8367c_getAsicReg(0x13c4, ®_data))!=RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (reg_data >> 12) & 1; + pPortAbility->duplex = (reg_data >> 2) & 1; + pPortAbility->link = (reg_data >> 4) & 1; + pPortAbility->speed = reg_data & 3; + pPortAbility->rxpause = (reg_data >> 5) & 1; + pPortAbility->txpause = (reg_data >> 6) & 1; + } + } + else if (3 == type) + { + if (id == 1) + { + if ((retVal = rtl8367c_getAsicReg(0x1311, ®_data))!=RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (reg_data >> 12) & 1; + pPortAbility->duplex = (reg_data >> 2) & 1; + pPortAbility->link = (reg_data >> 4) & 1; + pPortAbility->speed = reg_data & 3; + pPortAbility->rxpause = (reg_data >> 5) & 1; + pPortAbility->txpause = (reg_data >> 6) & 1; + } + else if (2 == id) + { + if ((retVal = rtl8367c_getAsicReg(0x13c4, ®_data))!=RT_ERR_OK) + return retVal; + + pPortAbility->forcemode = (reg_data >> 12) & 1; + pPortAbility->duplex = (reg_data >> 2) & 1; + pPortAbility->link = (reg_data >> 4) & 1; + pPortAbility->speed = reg_data & 3; + pPortAbility->rxpause = (reg_data >> 5) & 1; + pPortAbility->txpause = (reg_data >> 6) & 1; + } + } + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPortExtMode + * Description: + * Set external interface mode configuration + * Input: + * id - external interface id (0~2) + * mode - external interface mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicPortExtMode(rtk_uint32 id, rtk_uint32 mode) +{ + ret_t retVal; + rtk_uint32 i, regValue, type, option,reg_data; + rtk_uint32 idx; + rtk_uint32 redData[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x21A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} }; + rtk_uint32 redDataSB[][2] = { {0x04D7, 0x0480}, {0xF994, 0x0481}, {0x31A2, 0x0482}, {0x6960, 0x0483}, {0x9728, 0x0484}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x83F2, 0x002E} }; + rtk_uint32 redData1[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + rtk_uint32 redData5[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + rtk_uint32 redData6[][2] = { {0x82F1, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + rtk_uint32 redData8[][2] = { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + rtk_uint32 redData9[][2] = { {0x82F1, 0x0500}, {0xF995, 0x0501}, {0x31A2, 0x0502}, {0x796C, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + rtk_uint32 redDataHB[][2] = { {0x82F0, 0x0500}, {0xF195, 0x0501}, {0x31A2, 0x0502}, {0x7960, 0x0503}, {0x9728, 0x0504}, {0x9D85, 0x0423}, {0xD810, 0x0424}, {0x0F80, 0x0001}, {0x83F2, 0x002E} }; + + if(id >= RTL8367C_EXTNO) + return RT_ERR_OUT_OF_RANGE; + + if(mode >= EXT_END) + return RT_ERR_OUT_OF_RANGE; + + /* magic number*/ + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + /* Chip num */ + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + type = 0; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 1; + break; + case 0x0652: + case 0x6368: + type = 2; + break; + case 0x0801: + case 0x6511: + type = 3; + break; + default: + return RT_ERR_FAILED; + } + + + if (1==type) + { + if((mode == EXT_1000X_100FX) || (mode == EXT_1000X) || (mode == EXT_100FX)) + { + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 5, 1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_REG_TO_ECO4, 7, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if(mode == EXT_1000X_100FX) + { + for(idx = 0; idx < FIBER2_AUTO_INIT_SIZE; idx++) + { + if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_Auto[idx])) != RT_ERR_OK) + return retVal; + } + } + + if(mode == EXT_1000X) + { + for(idx = 0; idx < FIBER2_1G_INIT_SIZE; idx++) + { + if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_1G[idx])) != RT_ERR_OK) + return retVal; + } + } + + if(mode == EXT_100FX) + { + for(idx = 0; idx < FIBER2_100M_INIT_SIZE; idx++) + { + if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Fiber2_100M[idx])) != RT_ERR_OK) + return retVal; + } + } + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + + if(mode == EXT_GMII) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT0_RGMXF, RTL8367C_EXT0_RGTX_INV_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_EXT1_RGMXF, RTL8367C_EXT1_RGTX_INV_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT1_GMII_TX_DELAY_MASK, 5)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_EXT_TXC_DLY, RTL8367C_EXT0_GMII_TX_DELAY_MASK, 6)) != RT_ERR_OK) + return retVal; + } + + /* Serdes reset */ + if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) ) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id, 0)) != RT_ERR_OK) + return retVal; + } + + if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) + { + if(id != 1) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x13C1, &option)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C0, 0x0000)) != RT_ERR_OK) + return retVal; + } + + if(mode == EXT_SGMII) + { + if(option == 0) + { + for(i = 0; i <= 7; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + else + { + for(i = 0; i <= 7; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataSB[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataSB[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + } + + if(mode == EXT_HSGMII) + { + if(option == 0) + { + if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0249)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicReg(0x1301, ®Value)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(0x13c2, 0x0000)) != RT_ERR_OK) + return retVal; + + if ( ((regValue & 0x00F0) >> 4) == 0x0001) + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData1[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData1[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + else if ( ((regValue & 0x00F0) >> 4) == 0x0005) + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData5[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData5[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + else if ( ((regValue & 0x00F0) >> 4) == 0x0006) + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData6[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData6[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + else if ( ((regValue & 0x00F0) >> 4) == 0x0008) + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData8[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData8[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + else if ( ((regValue & 0x00F0) >> 4) == 0x0009) + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redData9[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redData9[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + } + else + { + for(i = 0; i <= 8; i++) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, redDataHB[i][0])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, redDataHB[i][1])) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + } + } + + /* Only one ext port should care SGMII setting */ + if(id == 1) + { + + if(mode == EXT_SGMII) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + else if(mode == EXT_HSGMII) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 1)) != RT_ERR_OK) + return retVal; + } + else + { + + if((mode != EXT_1000X_100FX) && (mode != EXT_1000X) && (mode != EXT_100FX)) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + } + } + + if(0 == id || 1 == id) + { + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), mode)) != RT_ERR_OK) + return retVal; + } + else + { + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, mode)) != RT_ERR_OK) + return retVal; + } + + /* Serdes not reset */ + if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) + { + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x7106)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, 0x0003)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + } + + if( (mode == EXT_SGMII) || (mode == EXT_HSGMII) ) + { + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_MISCELLANEOUS_CONFIGURE0, RTL8367C_DW8051_EN_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + for(idx = 0; idx < SGMII_INIT_SIZE; idx++) + { + if ((retVal = rtl8367c_setAsicReg(0xE000 + idx, (rtk_uint32)Sgmii_Init[idx])) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_IROM_MSB_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_DW8051_RDY, RTL8367C_ACS_IROM_ENABLE_OFFSET, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_CHIP_RESET, RTL8367C_DW8051_RST_OFFSET, 0)) != RT_ERR_OK) + return retVal; + } + } + else if (2 == type) + { + /* Serdes reset */ + if( (mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY) ) + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 1)) != RT_ERR_OK) + return retVal; + } + else + { + if( (retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_BYPASS_LINE_RATE, id+2, 0)) != RT_ERR_OK) + return retVal; + } + + /*set MAC mode*/ + if (id == 1) + { + if(mode == EXT_HSGMII) + return RT_ERR_PORT_ID; + + if (mode == EXT_SGMII) + { + /*cfg port8 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + + /*enable port8 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 1)) != RT_ERR_OK) + return retVal; + } + else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX) + { + /*cfg port8 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + + /*disable port8 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK) + return retVal; + + /*set fiber link up*/ + if((retVal = rtl8367c_setAsicRegBit(0x6210, 11, 0)) != RT_ERR_OK) + return retVal; + } + else + { + /*cfg port8 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK) + return retVal; + + /*disable port8 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 14, 0)) != RT_ERR_OK) + return retVal; + } + /*disable SDS 1*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + } + else if(id == 2) + { + if (mode == EXT_HSGMII) + { + if ((retVal = rtl8367c_setAsicReg(0x130, 7)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x39f, 7)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicReg(0x130, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x39f, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x3fa, 4)) != RT_ERR_OK) + return retVal; + + } + + + if (mode == EXT_SGMII) + { + /*cfg port9 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*enable port9 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 1)) != RT_ERR_OK) + return retVal; + + /*disable port9 HSGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) + return retVal; + } + else if (mode == EXT_HSGMII) + { + /*cfg port9 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*disable port9 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) + return retVal; + + /*enable port9 HSGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 1)) != RT_ERR_OK) + return retVal; + } + else if (mode == EXT_1000X || mode == EXT_100FX || mode == EXT_1000X_100FX) + { + /*cfg port9 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*disable port9 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) + return retVal; + + /*disable port9 HSGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) + return retVal; + + /*set fiber link up*/ + if((retVal = rtl8367c_setAsicRegBit(0x6200, 11, 0)) != RT_ERR_OK) + return retVal; + } + else + { + /*cfg port9 with MII mac mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK) + return retVal; + + /*disable port9 SGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 6, 0)) != RT_ERR_OK) + return retVal; + + /*disable port9 HSGMII*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d92, 7, 0)) != RT_ERR_OK) + return retVal; + } + /*disable SDS 0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) + return retVal; + } + + /*SET TO RGMII MODE*/ + if (mode == EXT_RGMII) + { + /*disable paral led pad*/ + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN3, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN1, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(RTL8367C_REG_PARA_LED_IO_EN2, 0)) != RT_ERR_OK) + return retVal; + + /*set MAC8 mode*/ + if (id == 1) + { + /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 9, 1)) != RT_ERR_OK) + return retVal; + + /*drving 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 6, 1)) != RT_ERR_OK) + return retVal; + + /*drving 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 4, 1)) != RT_ERR_OK) + return retVal; + + /*show rate = 0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 1, 0)) != RT_ERR_OK) + return retVal; + + /*EXT1 RGMII TXC delay 2ns*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1307, 3, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_Ext1_rgtxc_dly = 0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x38, 0)) != RT_ERR_OK) + return retVal; + + /*RXDLY = 0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1307, 0x7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_rg1_dn = 4*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1304, 0x7000, 4)) != RT_ERR_OK) + return retVal; + + /*cfg_rg1_dp = 4*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x700, 4)) != RT_ERR_OK) + return retVal; + } + else if (id == 2) + { + /*1: RGMII1 bias work at 3.3V, 0: RGMII1 bias work at 2.5V*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1303, 10, 1)) != RT_ERR_OK) + return retVal; + + /*drving 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 2, 1)) != RT_ERR_OK) + return retVal; + + /*drving 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 1, 1)) != RT_ERR_OK) + return retVal; + + /*show rate = 0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x13e2, 0, 0)) != RT_ERR_OK) + return retVal; + + /*EXT1 RGMII TXC delay 2ns*/ + if ((retVal = rtl8367c_setAsicRegBit(0x13c5, 3, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_Ext1_rgtxc_dly = 0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13f9, 0x1c0, 0)) != RT_ERR_OK) + return retVal; + + /*RXDLY = 0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c5, 0x7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_rg1_dn = 4*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x1c0, 4)) != RT_ERR_OK) + return retVal; + + /*cfg_rg1_dp = 4*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13e2, 0x38, 4)) != RT_ERR_OK) + return retVal; + } + } + else if (mode == EXT_SGMII) + { + if (id == 1) + { + /*sds 1 reg 1 page 0x21 write value 0xec91*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0xec91)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 1)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK) + return retVal; + + /*sds 1 reg 5 page 0x24 write value 0x5825*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x5825)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 5)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 2)) != RT_ERR_OK) + return retVal; + + /*?????????????????*/ + + } + else if (id == 2) + { + /*sds 0 reg 0 page 0x28 write value 0x942c*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + /*sds 0 reg 0 page 0x24 write value 0x942c*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + /*sds 0 reg 5 page 0x21 write value 0x8dc3*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 2)) != RT_ERR_OK) + return retVal; + + /*?????????????????*/ + } + } + else if (mode == EXT_HSGMII) + { + if (id == 2) + { + /*sds 0 reg 0 page 0x28 write value 0x942c*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x28<<5) | 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + /*sds 0 reg 0 page 0x24 write value 0x942c*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x942c)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x24<<5) | 0)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + /*sds 0 reg 5 page 0x21 write value 0x8dc3*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x8dc3)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5) | 5)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + + /* optimizing HISGMII performance while RGMII used & */ + /*sds 0 reg 9 page 0x21 write value 0x3931*/ + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_DATA, 0x3931)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_ADR, (0x21<<5)|9) ) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_setAsicReg(RTL8367C_REG_SDS_INDACS_CMD, 0x00C0)) != RT_ERR_OK) + return retVal; + + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x12)) != RT_ERR_OK) + return retVal; + + /*?????????????????*/ + } + } + else if (mode == EXT_1000X) + { + if (id == 1) + { + + if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*patch speed change sds1 1000M*/ + if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFF0FFF; + regValue |= 0x9000; + if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFdFFF; + regValue |= 0x40; + if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK) + return retVal; + + + if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFEFFF; + if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 4)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK) + return retVal; + + } + else if (id == 2) + { + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK) + return retVal; + + /*patch speed change sds0 1000M*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFF0FFF; + regValue |= 0x9000; + if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFDFFF; + regValue |= 0x40; + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFEFFF; + if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 4)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK) + return retVal; + + } + } + else if (mode == EXT_100FX) + { + if (id == 1) + { + if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK) + return retVal; + + /*patch speed change sds1 100M*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFF0FFF; + regValue |= 0xb000; + if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(1, 0, 2, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFFFBF; + regValue |= 0x2000; + if( (retVal = rtl8367c_setAsicSdsReg(1, 0, 2, regValue)) != RT_ERR_OK) + return retVal; +#if 0 + if( (retVal = rtl8367c_setAsicReg(0x6214, 0x1a0)) != RT_ERR_OK) + return retVal; +#endif + if( (retVal = rtl8367c_getAsicSdsReg(1, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFEFFF; + if( (retVal = rtl8367c_setAsicSdsReg(1, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 5)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x6000, 0)) != RT_ERR_OK) + return retVal; + } + else if (id == 2) + { + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK) + return retVal; + + /*patch speed change sds0 100M*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 0x1f)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFF0FFF; + regValue |= 0xb000; + if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 0, 2, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFFFBF; + regValue |= 0x2000; + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 2, regValue)) != RT_ERR_OK) + return retVal; + + if( (retVal = rtl8367c_getAsicSdsReg(0, 4, 0, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFEFFF; + if( (retVal = rtl8367c_setAsicSdsReg(0, 4, 0, regValue)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 5)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0xe0, 0)) != RT_ERR_OK) + return retVal; + } + } + else if (mode == EXT_1000X_100FX) + { + if (id == 1) + { + if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0x21, 0xec91)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(1, 5, 0x24, 0x5825)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(1, 13, 0, 0x4616)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(1, 1, 0, 0xf20)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f00, 7)) != RT_ERR_OK) + return retVal; + } + else if (id == 2) + { + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x28, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 0, 0x24, 0x942c)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 5, 0x21, 0x8dc3)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 13, 0, 0x4616)) != RT_ERR_OK) + return retVal; + if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 0, 0xf20)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d92, 0x1f, 7)) != RT_ERR_OK) + return retVal; + } + } + + } + else if (3 == type) + { + + /*restore patch, by designer. patch Tx FIFO issue, when not HSGMII 2.5G mode + #sds0, page 1, reg 1, bit4=0*/ + if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, ®Value)) != RT_ERR_OK) + return retVal; + regValue &= 0xFFFFFFEF; + if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK) + return retVal; + + /*set for mac 6*/ + if (1 == id) + { + /*force port6 linkdown*/ + if ((retVal = rtl8367c_setAsicReg(0x137c, 0x1000)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, ®_data)) != RT_ERR_OK) + return retVal; + while(reg_data == 0) + { + if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 6, ®_data)) != RT_ERR_OK) + return retVal; + } + + if (mode == EXT_SGMII) + { + /* disable mac6 mode_ext1 mode*/ + if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + } + /*cfg_bypass_line_rate[1]=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_fib=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 0: MAC7 is not SGMII mode*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK) + return retVal; + + /*#cfg_sgmii_link=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + + + /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x1F (reset mode) */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x12 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) + return retVal; + + /* MAC link source*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) + return retVal; + + + } + else if (mode == EXT_HSGMII) + { + + /*restore patch, by designer. patch Tx FIFO issue, when HSGMII 2.5G mode + #sds0, page 1, reg 1, bit4=1*/ + if( (retVal = rtl8367c_getAsicSdsReg(0, 1, 1, ®Value)) != RT_ERR_OK) + return retVal; + regValue |= 0x10; + if( (retVal = rtl8367c_setAsicSdsReg(0, 1, 1, regValue)) != RT_ERR_OK) + return retVal; + + /* mode_ext1 = disable*/ + /* disable mac6 mode_ext1 mode*/ + if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_fib=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 1, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 9, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0xd0,7)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x399, 7)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x3fa, 7)) != RT_ERR_OK) + return retVal; + + /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x12 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x12)) != RT_ERR_OK) + return retVal; + /* + 1: MAC link = SGMII SerDes link + 0: MAC link = SGMII config link (cfg_sgmii_link) + */ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) + return retVal; + + } + else if(mode == EXT_1000X) + { + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* disable mac6 mode_ext1 mode*/ + if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method + bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 + */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable + bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ + if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) + return retVal; + + /*bit3: Serdes force mode:cfg_sds_frc_mode=1 + bit[2:0]: Serdes chip mode, cfg_sds_mode=3b'100 (force sds FIB1G mode) */ + if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) + return retVal; + + + /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x4 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) + return retVal; + } + else if(mode == EXT_100FX) + { + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* disable mac6 mode_ext1 mode*/ + if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method + bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 + */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable + bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ + if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) + return retVal; + + /*!!!!! cfg_sds_frc_mode=1 & cfg_sds_mode=3b'101 (force sds fib100M mode)*/ + if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) + return retVal; + + + /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x5 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) + return retVal; + } + else if(mode == EXT_1000X_100FX) + { + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /* disable mac6 mode_ext1 mode*/ + if ((retVal = rtl8367c_getAsicRegBit(0x1d3d, 10, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 0)) != RT_ERR_OK) + return retVal; + } + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*bit13: cfg_sds_mode_sel_new=1 :Enable new sds mode config method + bit[1:0]:cfg_mac7_fib= 0 & cfg_mac7_sel_sgmii=0 + */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + /* bit0 :UTP/Fiber auto detect function enable or not, cfg_dis_det=1:disable + bit3:Force UTP/Fiber auto detect function enable or not, cfg_force_auto-detect=1 */ + if ((retVal = rtl8367c_setAsicReg(0x13eb, 0x15bb)) != RT_ERR_OK) + return retVal; + + /*!!!!!! cfg_sds_frc_mode=1 & cfg_sds_mode=3'b111: Fib1G/Fib100M auto detect */ + if ((retVal = rtl8367c_setAsicReg(0x13e7, 0xc)) != RT_ERR_OK) + return retVal; + + + /*bit5: cfg_mac6_fib=1 & bit7: cfg_mac6_fib2=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 1)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 1)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x7 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) + return retVal; + } + else if(mode < EXT_SGMII) + { + if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 0)) != RT_ERR_OK) + return retVal; + + /* keep default setting, disable mac6 sel SerDes mode,*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + if (mode < EXT_GMII) + { + /* set mac6 mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, mode)) != RT_ERR_OK) + return retVal; + } + else if(mode == EXT_RMII_MAC) + { + /*!!!!!!*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 7)) != RT_ERR_OK) + return retVal; + } + else if(mode == EXT_RMII_PHY) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, 8)) != RT_ERR_OK) + return retVal; + } + + if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY)) + { + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 1, 1)) != RT_ERR_OK) + return retVal; + } + } + + } + else if (2 == id) + { + + /*force port7 linkdown*/ + if ((retVal = rtl8367c_setAsicReg(0x137d, 0x1000)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, ®_data)) != RT_ERR_OK) + return retVal; + while(reg_data == 0) + { + if ((retVal = rtl8367c_getAsicRegBit(0x1d9d, 7, ®_data)) != RT_ERR_OK) + return retVal; + } + + if (mode == EXT_SGMII) + { + /*disable mac7 sel ext2 xMII mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf,0)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) + return retVal; + /* disable mac7 mode_ext2 */ + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /* + bit0:cfg_mac7_sel_sgmii=0,MAC7 is not SGMII mode + bit1:cfg_mac7_fib= 0 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_hsgmii=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 11, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac6_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 0)) != RT_ERR_OK) + return retVal; + + /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x1F (reset mode) */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 0, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x2 (SGMII mode)*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x2)) != RT_ERR_OK) + return retVal; + + /*select MAC link source when port6/7 be set sgmii mode (cfg_sgmii_link)*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 2, 0)) != RT_ERR_OK) + return retVal; + } + else if (mode == EXT_1000X) + { + /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) + return retVal; + + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /* keep default setting, disable mac6 sel serdes*/ + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x1F (reset mode) */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) + return retVal; + + /*new_cfg_sds_mode=0x4 (FIB1000 mode)*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x4)) != RT_ERR_OK) + return retVal; + + } + else if (mode == EXT_100FX) + { + /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) + return retVal; + + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /* keep default setting, disable mac6 sel serdes*/ + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x1F (reset mode) */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x5 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x5)) != RT_ERR_OK) + return retVal; + } + else if (mode == EXT_1000X_100FX) + { + /* disable mac7 MII/TMM/RMII/GMII/RGMII mode, mode_ext2 = disable */ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicReg(0x13c4, 0)) != RT_ERR_OK) + return retVal; + + /* 0 2 0 bit 8~9 set 0, force n-way*/ + if((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®_data)) != RT_ERR_OK) + return retVal; + reg_data &= 0xFFFFFCFF; + if((retVal = rtl8367c_setAsicSdsReg(0,2,0, reg_data)) != RT_ERR_OK) + return retVal; + + /*restore ext2 ability*/ + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /* keep default setting, disable mac6 sel serdes*/ + if ((retVal = rtl8367c_setAsicReg(0x1d11, 0x1500)) != RT_ERR_OK) + return retVal; + + /*Enable new sds mode config method, cfg_sds_mode_sel_new=1*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d95, 13, 1)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x1F (reset mode) */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x1f)) != RT_ERR_OK) + return retVal; + + /*bit5: cfg_mac6_fib=0 & bit7: cfg_mac6_fib2=0*/ + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 5, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicRegBit(0x1d41, 7, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 1 & cfg_mac7_fib=1*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 3)) != RT_ERR_OK) + return retVal; + + /* bit[12:8]: Only valid when cfg_sds_mode_sel_new=1 + new_cfg_sds_mode=0x7 */ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 0x1f00, 0x7)) != RT_ERR_OK) + return retVal; + } + else if (mode < EXT_SGMII) + { + if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /* keep default setting, disable mac7 sel SerDes mode*/ + if ((retVal = rtl8367c_setAsicReg(0x1d95, 0x1f00)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + /* set port7 mode*/ + if ((retVal = rtl8367c_setAsicRegBits(0x13c3, 0xf, mode)) != RT_ERR_OK) + return retVal; + + if ((mode == EXT_TMII_MAC) || (mode == EXT_TMII_PHY)) + { + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK) + return retVal; + } + + } + else if ((mode < EXT_END) && (mode > EXT_100FX)) + { + if ((retVal = rtl8367c_setAsicRegBits(0x13C3, 0xf, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 0)) != RT_ERR_OK) + return retVal; + + /*cfg_mac7_sel_sgmii= 0 & cfg_mac7_fib=0*/ + if ((retVal = rtl8367c_setAsicRegBits(0x1d95, 3, 0)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRegBit(0x1d3d, 10, 1)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicRegBit(0x1d11, 11, ®_data)) != RT_ERR_OK) + return retVal; + if(reg_data == 0) + { + if ((retVal = rtl8367c_setAsicRegBit(0x1d11, 6, 1)) != RT_ERR_OK) + return retVal; + } + + /* set port7 mode*/ + if (mode < EXT_RMII_MAC_2) + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-13))) != RT_ERR_OK) + return retVal; + } + else + { + if ((retVal = rtl8367c_setAsicRegBits(0x1305, 0xf0, (mode-12))) != RT_ERR_OK) + return retVal; + } + + if ((mode == EXT_TMII_MAC_2) || (mode == EXT_TMII_PHY_2)) + { + if ((retVal = rtl8367c_setAsicRegBit(0x3f7, 2, 1)) != RT_ERR_OK) + return retVal; + } + } + + } + + } + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicPortExtMode + * Description: + * Get external interface mode configuration + * Input: + * id - external interface id (0~1) + * pMode - external interface mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicPortExtMode(rtk_uint32 id, rtk_uint32 *pMode) +{ + ret_t retVal; + rtk_uint32 regData, regValue, type; + + if(id >= RTL8367C_EXTNO) + return RT_ERR_OUT_OF_RANGE; + /*cfg_magic_id & get chip_id*/ + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + type = 0; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 1; + break; + case 0x0652: + case 0x6368: + type = 2; + break; + case 0x0801: + case 0x6511: + type = 3; + break; + default: + return RT_ERR_FAILED; + } + + + if (1 == type) + { + + if (1 == id) + { + if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_SGMII_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + + if(1 == regData) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + + if( (retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SDS_MISC, RTL8367C_CFG_MAC8_SEL_HSGMII_OFFSET, ®Data)) != RT_ERR_OK) + return retVal; + + if(1 == regData) + { + *pMode = EXT_HSGMII; + return RT_ERR_OK; + } + } + + if(0 == id || 1 == id) + return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT, RTL8367C_SELECT_GMII_0_MASK << (id * RTL8367C_SELECT_GMII_1_OFFSET), pMode); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_DIGITAL_INTERFACE_SELECT_1, RTL8367C_SELECT_GMII_2_MASK, pMode); + + } + else if (2 == type) + { + if (1 == id) + { + if ((retVal = rtl8367c_getAsicReg(0x1d92, ®Data))!=RT_ERR_OK) + return retVal; + + if (regData & 0x4000) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + + else if (((regData >> 8) & 0x1f) == 4) + { + *pMode = EXT_1000X; + return RT_ERR_OK; + } + else if (((regData >> 8) & 0x1f) == 5) + { + *pMode = EXT_100FX; + return RT_ERR_OK; + } + else if (((regData >> 8) & 0x1f) == 7) + { + *pMode = EXT_1000X_100FX; + return RT_ERR_OK; + } + + return rtl8367c_getAsicRegBits(0x1305, 0xf0, pMode); + } + else if (2 == id) + { +#if 0 + if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 6, ®Data))!=RT_ERR_OK) + return retVal; + + if (regData == 1) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + + if ((retVal = rtl8367c_getAsicRegBit(0x1d92, 7, ®Data))!=RT_ERR_OK) + return retVal; + + if (regData == 1) + { + *pMode = EXT_HSGMII; + return RT_ERR_OK; + } +#endif + if ((retVal = rtl8367c_getAsicReg(0x1d92, ®Data))!=RT_ERR_OK) + return retVal; + + if (regData & 0x40) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + else if (regData & 0x80) + { + *pMode = EXT_HSGMII; + return RT_ERR_OK; + } + else if ((regData & 0x1f) == 4) + { + *pMode = EXT_1000X; + return RT_ERR_OK; + } + else if ((regData & 0x1f) == 5) + { + *pMode = EXT_100FX; + return RT_ERR_OK; + } + else if ((regData & 0x1f) == 7) + { + *pMode = EXT_1000X_100FX; + return RT_ERR_OK; + } + + return rtl8367c_getAsicRegBits(0x1305, 0xf, pMode); + } + } + else if(3 == type) + { + if (1 == id) + { + /* SDS_CFG_NEW */ + if ((retVal = rtl8367c_getAsicReg(0x1d95, ®Data))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicReg(0x1d41, ®Value))!=RT_ERR_OK) + return retVal; + + /* bit5: cfg_mac6_fib=1 && bit7: cfg_mac6_fib2 =1 */ + if((regValue & 0xa0) == 0xa0 ) + { + /* new_cfg_sds_mode */ + regData = regData >> 8; + if((regData & 0x1f) == 4) + { + *pMode = EXT_1000X; + return RT_ERR_OK; + } + else if((regData & 0x1f) == 5) + { + *pMode = EXT_100FX; + return RT_ERR_OK; + } + else if((regData & 0x1f) == 7) + { + *pMode = EXT_1000X_100FX; + return RT_ERR_OK; + } + + } + + + if ((retVal = rtl8367c_getAsicReg(0x1d11, ®Data))!=RT_ERR_OK) + return retVal; + + /* check cfg_mac6_sel_sgmii */ + if((regData >> 6) & 1) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + else if((regData >> 11) & 1) + { + *pMode = EXT_HSGMII; + return RT_ERR_OK; + } + else + { + /* check port6 MAC mode */ + if ((retVal = rtl8367c_getAsicRegBits(0x1305, 0xf0, ®Data))!=RT_ERR_OK) + return retVal; + + if(regData < 6) + *pMode = regData; + else if(regData == 6) + *pMode = EXT_RMII_MAC; + else if(regData == 7) + *pMode = EXT_RMII_PHY; + + return RT_ERR_OK; + } + } + else if (2 == id) + { + if ((retVal = rtl8367c_getAsicReg(0x1d95, ®Data))!=RT_ERR_OK) + return retVal; + + /* bit0: cfg_mac7_sel_sgmii + bit1: cfg_mac7_fib + bit[12:8]: new_cfg_sds_mode*/ + if(((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x4)) + { + *pMode = EXT_1000X; + return RT_ERR_OK; + } + else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x5)) + { + *pMode = EXT_100FX; + return RT_ERR_OK; + } + else if (((regData & 0x3) == 3) && (((regData >> 8) & 0x1f) == 0x7)) + { + *pMode = EXT_1000X_100FX; + return RT_ERR_OK; + } + else if(regData & 1) + { + *pMode = EXT_SGMII; + return RT_ERR_OK; + } + else + { + /* check port7 MAC mode */ + if ((retVal = rtl8367c_getAsicRegBits(0x13c3, 0xf, ®Data))!=RT_ERR_OK) + return retVal; + + *pMode = regData; + + return RT_ERR_OK; + } + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8370_setAsicPortEnableAll + * Description: + * Set ALL ports enable. + * Input: + * enable - enable all ports. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortEnableAll(rtk_uint32 enable) +{ + if(enable >= 2) + return RT_ERR_INPUT; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, !enable); +} + +/* Function Name: + * rtl8367c_getAsicPortEnableAll + * Description: + * Set ALL ports enable. + * Input: + * enable - enable all ports. + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortEnableAll(rtk_uint32 *pEnable) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_PHY_AD, RTL8367C_PDNPHY_OFFSET, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if (regData==0) + *pEnable = 1; + else + *pEnable = 0; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPortSmallIpg + * Description: + * Set small ipg egress mode + * Input: + * port - Physical port number (0~7) + * enable - 0: normal, 1: small + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortSmallIpg(rtk_uint32 port, rtk_uint32 enable) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, enable); +} + +/* Function Name: + * rtl8367c_getAsicPortSmallIpg + * Description: + * Get small ipg egress mode + * Input: + * port - Physical port number (0~7) + * pEnable - 0: normal, 1: small + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortSmallIpg(rtk_uint32 port, rtk_uint32* pEnable) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_PORT_SMALL_IPG_REG(port), RTL8367C_PORT0_MISC_CFG_SMALL_TAG_IPG_OFFSET, pEnable); +} + +/* Function Name: + * rtl8367c_setAsicPortLoopback + * Description: + * Set MAC loopback + * Input: + * port - Physical port number (0~7) + * enable - 0: Disable, 1: enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortLoopback(rtk_uint32 port, rtk_uint32 enable) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, enable); +} + +/* Function Name: + * rtl8367c_getAsicPortLoopback + * Description: + * Set MAC loopback + * Input: + * port - Physical port number (0~7) + * Output: + * pEnable - 0: Disable, 1: enable + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortLoopback(rtk_uint32 port, rtk_uint32 *pEnable) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_PORT0_MISC_CFG_MAC_LOOPBACK_OFFSET, pEnable); +} + +/* Function Name: + * rtl8367c_setAsicPortRTCTEnable + * Description: + * Set RTCT Enable echo response mode + * Input: + * portmask - Port mask of RTCT enabled (0-4) + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * Note: + * RTCT test takes 4.8 seconds at most. + */ +ret_t rtl8367c_setAsicPortRTCTEnable(rtk_uint32 portmask) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 port; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if( (regData == 0x0276) || (regData == 0x0597) ) + return RT_ERR_CHIP_NOT_SUPPORTED; + + for(port = 0; port <= 10 ; port++) + { + if(portmask & (0x0001 << port)) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= 0x7FFF; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + + regData |= 0x00F2;/*RTCT set to echo response mode*/ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + + regData |= 0x0001; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicPortRTCTDisable + * Description: + * Set RTCT Disable + * Input: + * portmask - Port mask of RTCT enabled (0-4) + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * Note: + * RTCT test takes 4.8 seconds at most. + */ +ret_t rtl8367c_setAsicPortRTCTDisable(rtk_uint32 portmask) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 port; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if( (regData == 0x0276) || (regData == 0x0597) ) + return RT_ERR_CHIP_NOT_SUPPORTED; + + for(port = 0; port <= 10 ; port++) + { + if(portmask & (0x0001 << port)) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) + return retVal; + + regData &= 0x7FFF; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + + regData |= 0x00F0; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + + regData &= ~0x0001; + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa422, regData)) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + + +/* Function Name: + * rtl8367c_getAsicPortRTCTResult + * Description: + * Get RTCT result + * Input: + * port - Port ID of RTCT result + * Output: + * pResult - The result of port ID + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid port mask + * RT_ERR_PHY_RTCT_NOT_FINISH - RTCT test doesn't finish. + * Note: + * RTCT test takes 4.8 seconds at most. + * If this API returns RT_ERR_PHY_RTCT_NOT_FINISH, + * users should wait a whole then read it again. + */ +ret_t rtl8367c_getAsicPortRTCTResult(rtk_uint32 port, rtl8367c_port_rtct_result_t *pResult) +{ + ret_t retVal; + rtk_uint32 regData, finish = 1; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Data)) != RT_ERR_OK) + return retVal; + + if( (regData == 0x6367) ) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) + return retVal; + + if((regData & 0x8000) == 0x8000) + { + /* Channel A */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelAShort = (regData == 0x0050) ? 1 : 0; + pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel B */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelBShort = (regData == 0x0050) ? 1 : 0; + pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel C */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelCShort = (regData == 0x0050) ? 1 : 0; + pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel D */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelDShort = (regData == 0x0050) ? 1 : 0; + pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel A Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelALen = (regData / 2); + + /* Channel B Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBLen = (regData / 2); + + /* Channel C Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCLen = (regData / 2); + + /* Channel D Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDLen = (regData / 2); + } + else + finish = 0; + } + else if(regData == 0x6368) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) + return retVal; + + if((regData & 0x8000) == 0x8000) + { + /* Channel A */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802b)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelAShort = (regData == 0x0050) ? 1 : 0; + pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel B */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802f)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelBShort = (regData == 0x0050) ? 1 : 0; + pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel C */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8033)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelCShort = (regData == 0x0050) ? 1 : 0; + pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel D */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8037)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelDShort = (regData == 0x0050) ? 1 : 0; + pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel A Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802d)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelALen = (regData / 2); + + /* Channel B Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8031)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBLen = (regData / 2); + + /* Channel C Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8035)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCLen = (regData / 2); + + /* Channel D Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8039)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDLen = (regData / 2); + } + else + finish = 0; + + } + else if((regData == 0x6511) || (regData == 0x0801)) + { + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa422, ®Data)) != RT_ERR_OK) + return retVal; + + if((regData & 0x8000) == 0x8000) + { + /* Channel A */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802a)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelAOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelAShort = (regData == 0x0050) ? 1 : 0; + pResult->channelAMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelALinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel B */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802e)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelBShort = (regData == 0x0050) ? 1 : 0; + pResult->channelBMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelBLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel C */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8032)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelCShort = (regData == 0x0050) ? 1 : 0; + pResult->channelCMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelCLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel D */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8036)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDOpen = (regData == 0x0048) ? 1 : 0; + pResult->channelDShort = (regData == 0x0050) ? 1 : 0; + pResult->channelDMismatch = ((regData == 0x0042) || (regData == 0x0044)) ? 1 : 0; + pResult->channelDLinedriver = (regData == 0x0041) ? 1 : 0; + + /* Channel A Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x802c)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelALen = (regData / 2); + + /* Channel B Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8030)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelBLen = (regData / 2); + + /* Channel C Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8034)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelCLen = (regData / 2); + + /* Channel D Length */ + if((retVal = rtl8367c_setAsicPHYOCPReg(port, 0xa436, 0x8038)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicPHYOCPReg(port, 0xa438, ®Data)) != RT_ERR_OK) + return retVal; + + pResult->channelDLen = (regData / 2); + } + else + finish = 0; + + } + else + return RT_ERR_CHIP_NOT_SUPPORTED; + + if(finish == 0) + return RT_ERR_PHY_RTCT_NOT_FINISH; + else + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_sdsReset + * Description: + * Reset Serdes + * Input: + * id - EXT ID + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +ret_t rtl8367c_sdsReset(rtk_uint32 id) +{ + rtk_uint32 retVal, regValue, state, i, option, running = 0, retVal2; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + option = 0; + break; + case 0x0652: + case 0x6368: + option = 1; + break; + case 0x0801: + case 0x6511: + option = 2; + break; + default: + return RT_ERR_FAILED; + } + + if(option == 0) + { + if (1 == id) + { + if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) + return retVal; + + if(running == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) + return retVal; + } + + retVal = rtl8367c_setAsicReg(0x6601, 0x0000); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6602, 0x1401); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6601, 0x0000); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6602, 0x1403); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); + + if(running == 1) + { + if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) + return retVal2; + } + + if(retVal != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_PORT_ID; + } + else if(option == 1) + { + if (1 == id) + { + if((retVal = rtl8367c_getAsicReg(0x1311, &state)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1311, 0x66)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x1311, 0x1066)) != RT_ERR_OK) + return retVal; + + while(1) + { + if((retVal = rtl8367c_getAsicReg(0x1d9d, ®Value)) != RT_ERR_OK) + return retVal; + if((regValue >> 8) & 1) + break; + } + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK) + return retVal; + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6600, 0xc1)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK) + return retVal; + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x1311, state)) != RT_ERR_OK) + return retVal; + + + } + else if (2== id) + { + if((retVal = rtl8367c_getAsicReg(0x13c4, &state)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13c4, 0x66)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13c4, 0x1066)) != RT_ERR_OK) + return retVal; + + while(1) + { + if((retVal = rtl8367c_getAsicReg(0x1d9d, ®Value)) != RT_ERR_OK) + return retVal; + if((regValue >> 9) & 1) + break; + } + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x133d, 0x2)) != RT_ERR_OK) + return retVal; + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6602, 0x1401)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6601, 0x0)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6602, 0x1403)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_setAsicReg(0x6600, 0xc0)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x133d, 0x0)) != RT_ERR_OK) + return retVal; + + for (i=0; i<0xffff; i++); + + if((retVal = rtl8367c_setAsicReg(0x13c4, state)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_PORT_ID; + } + else if(option == 2) + { + if ((retVal = rtl8367c_getAsicSdsReg(0, 3, 0, ®Value))!=RT_ERR_OK) + return retVal; + regValue |= 0x40; + if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK) + return retVal; + + for (i=0; i<0xffff; i++); + + regValue &= ~(0x40); + if ((retVal = rtl8367c_setAsicSdsReg(0, 3, 0, regValue))!=RT_ERR_OK) + return retVal; + + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getSdsLinkStatus + * Description: + * Get SGMII status + * Input: + * id - EXT ID + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +ret_t rtl8367c_getSdsLinkStatus(rtk_uint32 ext_id, rtk_uint32 *pSignalDetect, rtk_uint32 *pSync, rtk_uint32 *pLink) +{ + rtk_uint32 retVal, regValue, type, running = 0, retVal2; + + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 0; + break; + case 0x0652: + case 0x6368: + type = 1; + break; + case 0x0801: + case 0x6511: + type = 2; + break; + default: + return RT_ERR_FAILED; + } + + if(type == 0) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) + return retVal; + + if(running == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) + return retVal; + } + + retVal = rtl8367c_setAsicReg(0x6601, 0x003D); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x0080); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_getAsicReg(0x6602, ®Value); + + if(running == 1) + { + if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) + return retVal2; + } + + if(retVal != RT_ERR_OK) + return retVal; + + *pSignalDetect = (regValue & 0x0100) ? 1 : 0; + *pSync = (regValue & 0x0001) ? 1 : 0; + *pLink = (regValue & 0x0010) ? 1 : 0; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 1) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + *pSignalDetect = (regValue & 0x0100) ? 1 : 0; + *pSync = (regValue & 0x0001) ? 1 : 0; + *pLink = (regValue & 0x0010) ? 1 : 0; + } + else if (2 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x003D))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + *pSignalDetect = (regValue & 0x0100) ? 1 : 0; + *pSync = (regValue & 0x0001) ? 1 : 0; + *pLink = (regValue & 0x0010) ? 1 : 0; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 2) + { + if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, ®Value)) != RT_ERR_OK) + return retVal; + if((retVal = rtl8367c_getAsicSdsReg(0, 30, 1, ®Value)) != RT_ERR_OK) + return retVal; + + *pSignalDetect = (regValue & 0x0100) ? 1 : 0; + *pSync = (regValue & 0x0001) ? 1 : 0; + *pLink = (regValue & 0x0010) ? 1 : 0; + + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setSgmiiNway + * Description: + * Set SGMII Nway + * Input: + * ext_id - EXT ID + * state - SGMII Nway state + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +ret_t rtl8367c_setSgmiiNway(rtk_uint32 ext_id, rtk_uint32 state) +{ + rtk_uint32 retVal, regValue, type, running = 0, retVal2; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 0; + break; + case 0x0652: + case 0x6368: + type = 1; + break; + case 0x0801: + case 0x6511: + type = 2; + break; + default: + return RT_ERR_FAILED; + } + + if(type == 0) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) + return retVal; + + if(running == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) + return retVal; + } + + retVal = rtl8367c_setAsicReg(0x6601, 0x0002); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x0080); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_getAsicReg(0x6602, ®Value); + + if(retVal == RT_ERR_OK) + { + if(state) + regValue |= 0x0200; + else + regValue &= ~0x0200; + + regValue |= 0x0100; + } + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6602, regValue); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6601, 0x0002); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x00C0); + + if(running == 1) + { + if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) + return retVal2; + } + + if(retVal != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 1) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + if(state) + regValue |= 0x0200; + else + regValue &= ~0x0200; + + regValue |= 0x0100; + + if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C1))!=RT_ERR_OK) + return retVal; + } + else if (2 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + if(state) + regValue |= 0x0200; + else + regValue &= ~0x0200; + + regValue |= 0x0100; + + if ((retVal = rtl8367c_setAsicReg(0x6602, regValue))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x00C0))!=RT_ERR_OK) + return retVal; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 2) + { + if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®Value))!=RT_ERR_OK) + return retVal; + + if(state & 1) + regValue &= ~0x100; + else + regValue |= 0x100; + + if ((retVal = rtl8367c_setAsicSdsReg(0, 2, 0, regValue))!=RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getSgmiiNway + * Description: + * Get SGMII Nway + * Input: + * ext_id - EXT ID + * state - SGMII Nway state + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None. + */ +ret_t rtl8367c_getSgmiiNway(rtk_uint32 ext_id, rtk_uint32 *pState) +{ + rtk_uint32 retVal, regValue, type, running = 0, retVal2; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 0; + break; + case 0x0652: + case 0x6368: + type = 1; + break; + case 0x0801: + case 0x6511: + type = 2; + break; + default: + return RT_ERR_FAILED; + } + + if(type == 0) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_getAsicRegBit(0x130c, 5, &running))!=RT_ERR_OK) + return retVal; + + if(running == 1) + { + if ((retVal = rtl8367c_setAsicRegBit(0x130c, 5, 0))!=RT_ERR_OK) + return retVal; + } + + retVal = rtl8367c_setAsicReg(0x6601, 0x0002); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_setAsicReg(0x6600, 0x0080); + + if(retVal == RT_ERR_OK) + retVal = rtl8367c_getAsicReg(0x6602, ®Value); + + if(running == 1) + { + if ((retVal2 = rtl8367c_setAsicRegBit(0x130c, 5, 1))!=RT_ERR_OK) + return retVal2; + } + + if(retVal != RT_ERR_OK) + return retVal; + + if(regValue & 0x0200) + *pState = 1; + else + *pState = 0; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 1) + { + if (1 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0081))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + if(regValue & 0x0200) + *pState = 1; + else + *pState = 0; + } + else if (2 == ext_id) + { + if ((retVal = rtl8367c_setAsicReg(0x6601, 0x0002))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicReg(0x6600, 0x0080))!=RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_getAsicReg(0x6602, ®Value))!=RT_ERR_OK) + return retVal; + + if(regValue & 0x0200) + *pState = 1; + else + *pState = 0; + } + else + return RT_ERR_PORT_ID; + } + else if(type == 2) + { + if ((retVal = rtl8367c_getAsicSdsReg(0, 2, 0, ®Value))!=RT_ERR_OK) + return retVal; + + if(regValue & 0x100) + *pState = 0; + else + *pState = 1; + } + + return RT_ERR_OK; +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c new file mode 100644 index 000000000000..e0b9db4bfbeb --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_portIsolation.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port isolation related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicPortIsolationPermittedPortmask + * Description: + * Set permitted port isolation portmask + * Input: + * port - Physical port number (0~10) + * permitPortmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 permitPortmask) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if( permitPortmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), permitPortmask); +} +/* Function Name: + * rtl8367c_getAsicPortIsolationPermittedPortmask + * Description: + * Get permitted port isolation portmask + * Input: + * port - Physical port number (0~10) + * pPermitPortmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortIsolationPermittedPortmask(rtk_uint32 port, rtk_uint32 *pPermitPortmask) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicReg(RTL8367C_PORT_ISOLATION_PORT_MASK_REG(port), pPermitPortmask); +} +/* Function Name: + * rtl8367c_setAsicPortIsolationEfid + * Description: + * Set port isolation EFID + * Input: + * port - Physical port number (0~10) + * efid - EFID (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - Input parameter out of range + * Note: + * EFID is used in individual learning in filtering database + */ +ret_t rtl8367c_setAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 efid) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if( efid > RTL8367C_EFIDMAX) + return RT_ERR_OUT_OF_RANGE; + + return rtl8367c_setAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), efid); +} +/* Function Name: + * rtl8367c_getAsicPortIsolationEfid + * Description: + * Get port isolation EFID + * Input: + * port - Physical port number (0~10) + * pEfid - EFID (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortIsolationEfid(rtk_uint32 port, rtk_uint32 *pEfid) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_PORT_EFID_REG(port), RTL8367C_PORT_EFID_MASK(port), pEfid); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c new file mode 100644 index 000000000000..69081049e336 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_qos.c @@ -0,0 +1,778 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : QoS related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicPriorityDot1qRemapping + * Description: + * Set 802.1Q absolutely priority + * Input: + * srcpriority - Priority value + * priority - Absolute priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 priority ) +{ + if((srcpriority > RTL8367C_PRIMAX) || (priority > RTL8367C_PRIMAX)) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority),priority); +} +/* Function Name: + * rtl8367c_getAsicPriorityDot1qRemapping + * Description: + * Get 802.1Q absolutely priority + * Input: + * srcpriority - Priority value + * pPriority - Absolute priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPriorityDot1qRemapping(rtk_uint32 srcpriority, rtk_uint32 *pPriority ) +{ + if(srcpriority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_REMAPPING_REG(srcpriority), RTL8367C_QOS_1Q_PRIORITY_REMAPPING_MASK(srcpriority), pPriority); +} +/* Function Name: + * rtl8367c_setAsicPriorityPortBased + * Description: + * Set port based priority + * Input: + * port - Physical port number (0~7) + * priority - Priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 priority ) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(priority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), priority); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), priority); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicPriorityPortBased + * Description: + * Get port based priority + * Input: + * port - Physical port number (0~7) + * pPriority - Priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPriorityPortBased(rtk_uint32 port, rtk_uint32 *pPriority ) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_PORTBASED_PRIORITY_REG(port), RTL8367C_QOS_PORTBASED_PRIORITY_MASK(port), pPriority); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_PORTBASED_PRIORITY_CTRL2, 0x7 << ((port - 8) << 2), pPriority); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPriorityDscpBased + * Description: + * Set DSCP-based priority + * Input: + * dscp - DSCP value + * priority - Priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 priority ) +{ + if(priority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if(dscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), priority); +} +/* Function Name: + * rtl8367c_getAsicPriorityDscpBased + * Description: + * Get DSCP-based priority + * Input: + * dscp - DSCP value + * pPriority - Priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicPriorityDscpBased(rtk_uint32 dscp, rtk_uint32 *pPriority ) +{ + if(dscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_PRIORITY_REG(dscp), RTL8367C_QOS_DSCP_TO_PRIORITY_MASK(dscp), pPriority); +} +/* Function Name: + * rtl8367c_setAsicPriorityDecision + * Description: + * Set priority decision table + * Input: + * prisrc - Priority decision source + * decisionPri - Decision priority assignment + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32 decisionPri) +{ + ret_t retVal; + + if(index >= PRIDEC_IDX_END ) + return RT_ERR_ENTRY_INDEX; + + if(prisrc >= PRIDEC_END ) + return RT_ERR_QOS_SEL_PRI_SOURCE; + + if(decisionPri > RTL8367C_DECISIONPRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + switch(index) + { + case PRIDEC_IDX0: + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), decisionPri))!= RT_ERR_OK) + return retVal; + break; + case PRIDEC_IDX1: + if((retVal = rtl8367c_setAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), decisionPri))!= RT_ERR_OK) + return retVal; + break; + default: + break; + }; + + return RT_ERR_OK; + + +} + +/* Function Name: + * rtl8367c_getAsicPriorityDecision + * Description: + * Get priority decision table + * Input: + * prisrc - Priority decision source + * pDecisionPri - Decision priority assignment + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_SEL_PRI_SOURCE - Invalid priority decision source parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicPriorityDecision(rtk_uint32 index, rtk_uint32 prisrc, rtk_uint32* pDecisionPri) +{ + ret_t retVal; + + if(index >= PRIDEC_IDX_END ) + return RT_ERR_ENTRY_INDEX; + + if(prisrc >= PRIDEC_END ) + return RT_ERR_QOS_SEL_PRI_SOURCE; + + switch(index) + { + case PRIDEC_IDX0: + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_MASK(prisrc), pDecisionPri))!= RT_ERR_OK) + return retVal; + break; + case PRIDEC_IDX1: + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_REG(prisrc), RTL8367C_QOS_INTERNAL_PRIORITY_DECISION2_MASK(prisrc), pDecisionPri))!= RT_ERR_OK) + return retVal; + break; + default: + break; + }; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtl8367c_setAsicPortPriorityDecisionIndex + * Description: + * Set priority decision index for each port + * Input: + * port - Physical port number (0~7) + * index - Table index + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_NUM - Invalid queue number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 index ) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index >= PRIDEC_IDX_END) + return RT_ERR_ENTRY_INDEX; + + return rtl8367c_setAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, index); +} +/* Function Name: + * rtl8367c_getAsicPortPriorityDecisionIndex + * Description: + * Get priority decision index for each port + * Input: + * port - Physical port number (0~7) + * pIndex - Table index + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortPriorityDecisionIndex(rtk_uint32 port, rtk_uint32 *pIndex ) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_QOS_INTERNAL_PRIORITY_DECISION_IDX_CTRL, port, pIndex); +} + +/* Function Name: + * rtl8367c_setAsicOutputQueueMappingIndex + * Description: + * Set output queue number for each port + * Input: + * port - Physical port number (0~7) + * index - Mapping table index + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_NUM - Invalid queue number + * Note: + * None + */ +ret_t rtl8367c_setAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 index ) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index >= RTL8367C_QUEUENO) + return RT_ERR_QUEUE_NUM; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), index); +} +/* Function Name: + * rtl8367c_getAsicOutputQueueMappingIndex + * Description: + * Get output queue number for each port + * Input: + * port - Physical port number (0~7) + * pIndex - Mapping table index + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicOutputQueueMappingIndex(rtk_uint32 port, rtk_uint32 *pIndex ) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_PORT_QUEUE_NUMBER_REG(port), RTL8367C_QOS_PORT_QUEUE_NUMBER_MASK(port), pIndex); +} +/* Function Name: + * rtl8367c_setAsicPriorityToQIDMappingTable + * Description: + * Set priority to QID mapping table parameters + * Input: + * index - Mapping table index + * priority - The priority value + * qid - Queue id + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QUEUE_ID - Invalid queue id + * RT_ERR_QUEUE_NUM - Invalid queue number + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32 qid ) +{ + if(index >= RTL8367C_QUEUENO) + return RT_ERR_QUEUE_NUM; + + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), qid); +} +/* Function Name: + * rtl8367c_getAsicPriorityToQIDMappingTable + * Description: + * Get priority to QID mapping table parameters + * Input: + * index - Mapping table index + * priority - The priority value + * pQid - Queue id + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QUEUE_NUM - Invalid queue number + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicPriorityToQIDMappingTable(rtk_uint32 index, rtk_uint32 priority, rtk_uint32* pQid) +{ + if(index >= RTL8367C_QUEUENO) + return RT_ERR_QUEUE_NUM; + + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_PRIORITY_TO_QID_REG(index, priority), RTL8367C_QOS_1Q_PRIORITY_TO_QID_MASK(priority), pQid); +} +/* Function Name: + * rtl8367c_setAsicRemarkingDot1pAbility + * Description: + * Set 802.1p remarking ability + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRemarkingDot1pAbility + * Description: + * Get 802.1p remarking ability + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDot1pAbility(rtk_uint32 port, rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_1QREMARK_ENABLE_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRemarkingDot1pParameter + * Description: + * Set 802.1p remarking parameter + * Input: + * priority - Priority value + * newPriority - New priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 newPriority ) +{ + if(priority > RTL8367C_PRIMAX || newPriority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), newPriority); +} +/* Function Name: + * rtl8367c_getAsicRemarkingDot1pParameter + * Description: + * Get 802.1p remarking parameter + * Input: + * priority - Priority value + * pNewPriority - New priority value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDot1pParameter(rtk_uint32 priority, rtk_uint32 *pNewPriority ) +{ + if(priority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_1Q_REMARK_REG(priority), RTL8367C_QOS_1Q_REMARK_MASK(priority), pNewPriority); +} + +/* Function Name: + * rtl8367c_setAsicRemarkingDot1pSrc + * Description: + * Set remarking source of 802.1p remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure 802.1p remark functionality to map original DSCP value or internal + * priority to TX DSCP value. + */ +ret_t rtl8367c_setAsicRemarkingDot1pSrc(rtk_uint32 type) +{ + + if(type >= DOT1P_PRISEL_END ) + return RT_ERR_QOS_SEL_PRI_SOURCE; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, type); +} + + +/* Function Name: + * rtl8367c_getAsicRemarkingDot1pSrc + * Description: + * Get remarking source of 802.1p remarking. + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDot1pSrc(rtk_uint32 *pType) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_1Q_CFG_SEL_OFFSET, pType); +} + + + + + +/* Function Name: + * rtl8367c_setAsicRemarkingDscpAbility + * Description: + * Set DSCP remarking ability + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRemarkingDscpAbility(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRemarkingDscpAbility + * Description: + * Get DSCP remarking ability + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDscpAbility(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REMARKING_CTRL_REG, RTL8367C_REMARKING_DSCP_ENABLE_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRemarkingDscpParameter + * Description: + * Set DSCP remarking parameter + * Input: + * priority - Priority value + * newDscp - New DSCP value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_DSCP_VALUE - Invalid DSCP value + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32 newDscp ) +{ + if(priority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + if(newDscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), newDscp); +} +/* Function Name: + * rtl8367c_getAsicRemarkingDscpParameter + * Description: + * Get DSCP remarking parameter + * Input: + * priority - Priority value + * pNewDscp - New DSCP value + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDscpParameter(rtk_uint32 priority, rtk_uint32* pNewDscp ) +{ + if(priority > RTL8367C_PRIMAX ) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_REMARK_REG(priority), RTL8367C_QOS_DSCP_REMARK_MASK(priority), pNewDscp); +} + +/* Function Name: + * rtl8367c_setAsicRemarkingDscpSrc + * Description: + * Set remarking source of DSCP remarking. + * Input: + * type - remarking source + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + + * Note: + * The API can configure DSCP remark functionality to map original DSCP value or internal + * priority to TX DSCP value. + */ +ret_t rtl8367c_setAsicRemarkingDscpSrc(rtk_uint32 type) +{ + + if(type >= DSCP_PRISEL_END ) + return RT_ERR_QOS_SEL_PRI_SOURCE; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, type); +} + + +/* Function Name: + * rtl8367c_getAsicRemarkingDscpSrc + * Description: + * Get remarking source of DSCP remarking. + * Output: + * pType - remarking source + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * RT_ERR_NULL_POINTER - input parameter may be null pointer + + * Note: + * None + */ +ret_t rtl8367c_getAsicRemarkingDscpSrc(rtk_uint32 *pType) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_RMK_CFG_SEL_CTRL, RTL8367C_RMK_DSCP_CFG_SEL_MASK, pType); +} + +/* Function Name: + * rtl8367c_setAsicRemarkingDscp2Dscp + * Description: + * Set DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * rmkDscp - remarked DSCP value + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - Invalid unit id + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * Note: + * dscp parameter can be DSCP value or internal priority according to configuration of API + * dal_apollomp_qos_dscpRemarkSrcSel_set(), because DSCP remark functionality can map original DSCP + * value or internal priority to TX DSCP value. + */ +ret_t rtl8367c_setAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 rmkDscp) +{ + if((dscp > RTL8367C_DSCPMAX ) || (rmkDscp > RTL8367C_DSCPMAX)) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), rmkDscp); +} + +/* Function Name: + * rtl8367c_getAsicRemarkingDscp2Dscp + * Description: + * Get DSCP to remarked DSCP mapping. + * Input: + * dscp - DSCP value + * Output: + * pRmkDscp - remarked DSCP value + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_DSCP_VALUE - Invalid dscp value + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * None. + */ +ret_t rtl8367c_getAsicRemarkingDscp2Dscp(rtk_uint32 dscp, rtk_uint32 *pRmkDscp) +{ + if(dscp > RTL8367C_DSCPMAX) + return RT_ERR_QOS_DSCP_VALUE; + + return rtl8367c_getAsicRegBits(RTL8367C_QOS_DSCP_TO_DSCP_REG(dscp), RTL8367C_QOS_DSCP_TO_DSCP_MASK(dscp), pRmkDscp); + +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c new file mode 100644 index 000000000000..0309689d39b9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rldp.c @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 42321 $ + * $Date: 2013-08-26 13:51:29 +0800 (週一, 26 八月 2013) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : RLDP related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicRldp + * Description: + * Set RLDP function enable/disable + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldp(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRldp + * Description: + * Get RLDP function enable/disable + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldp(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_ENABLE_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRldpEnable8051 + * Description: + * Set RLDP function handled by ASIC or 8051 + * Input: + * enabled - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpEnable8051(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_setAsicRldrtl8367c_getAsicRldpEnable8051pEnable8051 + * Description: + * Get RLDP function handled by ASIC or 8051 + * Input: + * pEnabled - 1: enabled 8051, 0: disabled 8051 (RLDP is handled by ASIC) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpEnable8051(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_8051_ENABLE_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRldpCompareRandomNumber + * Description: + * Set enable compare the random number field and seed field of RLDP frame + * Input: + * enabled - 1: enabled comparing random number, 0: disabled comparing random number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpCompareRandomNumber(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRldpCompareRandomNumber + * Description: + * Get enable compare the random number field and seed field of RLDP frame + * Input: + * pEnabled - 1: enabled comparing random number, 0: disabled comparing random number + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpCompareRandomNumber(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_COMP_ID_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRldpIndicatorSource + * Description: + * Set buzzer and LED source when detecting a loop + * Input: + * src - 0: ASIC, 1: 8051 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpIndicatorSource(rtk_uint32 src) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, src); +} +/* Function Name: + * rtl8367c_getAsicRldpIndicatorSource + * Description: + * Get buzzer and LED source when detecting a loop + * Input: + * pSrc - 0: ASIC, 1: 8051 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpIndicatorSource(rtk_uint32 *pSrc) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_INDICATOR_SOURCE_OFFSET, pSrc); +} +/* Function Name: + * rtl8367c_setAsicRldpCheckingStatePara + * Description: + * Set retry count and retry period of checking state + * Input: + * retryCount - 0~0xFF (times) + * retryPeriod - 0~0xFFFF (ms) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpCheckingStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod) +{ + ret_t retVal; + + if(retryCount > 0xFF) + return RT_ERR_OUT_OF_RANGE; + if(retryPeriod > RTL8367C_REGDATAMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, retryCount); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, retryPeriod); +} +/* Function Name: + * rtl8367c_getAsicRldpCheckingStatePara + * Description: + * Get retry count and retry period of checking state + * Input: + * pRetryCount - 0~0xFF (times) + * pRetryPeriod - 0~0xFFFF (ms) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpCheckingStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_CHKSTATE_MASK, pRetryCount); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_CHKSTATE_REG, pRetryPeriod); +} +/* Function Name: + * rtl8367c_setAsicRldpLoopStatePara + * Description: + * Set retry count and retry period of loop state + * Input: + * retryCount - 0~0xFF (times) + * retryPeriod - 0~0xFFFF (ms) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpLoopStatePara(rtk_uint32 retryCount, rtk_uint32 retryPeriod) +{ + ret_t retVal; + + if(retryCount > 0xFF) + return RT_ERR_OUT_OF_RANGE; + + if(retryPeriod > RTL8367C_REGDATAMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, retryCount); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, retryPeriod); +} +/* Function Name: + * rtl8367c_getAsicRldpLoopStatePara + * Description: + * Get retry count and retry period of loop state + * Input: + * pRetryCount - 0~0xFF (times) + * pRetryPeriod - 0~0xFFFF (ms) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - input parameter out of range + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpLoopStatePara(rtk_uint32 *pRetryCount, rtk_uint32 *pRetryPeriod) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_RETRY_COUNT_REG, RTL8367C_RLDP_RETRY_COUNT_LOOPSTATE_MASK, pRetryCount); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_getAsicReg(RTL8367C_RLDP_RETRY_PERIOD_LOOPSTATE_REG, pRetryPeriod); +} +/* Function Name: + * rtl8367c_setAsicRldpTxPortmask + * Description: + * Set portmask that send/forward RLDP frame + * Input: + * portmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpTxPortmask(rtk_uint32 portmask) +{ + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicReg(RTL8367C_RLDP_TX_PMSK_REG, portmask); +} +/* Function Name: + * rtl8367c_getAsicRldpTxPortmask + * Description: + * Get portmask that send/forward RLDP frame + * Input: + * pPortmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpTxPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_RLDP_TX_PMSK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicRldpMagicNum + * Description: + * Set Random seed of RLDP + * Input: + * seed - MAC + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpMagicNum(ether_addr_t seed) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + + accessPtr = (rtk_uint16*)&seed; + + for (i = 0; i < 3; i++) + { + regData = *accessPtr; + retVal = rtl8367c_setAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr++; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicRldpMagicNum + * Description: + * Get Random seed of RLDP + * Input: + * pSeed - MAC + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpMagicNum(ether_addr_t *pSeed) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + + accessPtr = (rtk_uint16*)pSeed; + + for(i = 0; i < 3; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_MAGIC_NUM_REG_BASE + i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + accessPtr++; + } + + return retVal; +} + +/* Function Name: + * rtl8367c_getAsicRldpLoopedPortmask + * Description: + * Get looped portmask + * Input: + * pPortmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpLoopedPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_RLDP_LOOP_PMSK_REG, pPortmask); +} +/* Function Name: + * rtl8367c_getAsicRldpRandomNumber + * Description: + * Get Random number of RLDP + * Input: + * pRandNumber - MAC + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpRandomNumber(ether_addr_t *pRandNumber) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_int16 accessPtr[3]; + rtk_uint32 i; + + for(i = 0; i < 3; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_RLDP_RAND_NUM_REG_BASE+ i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr[i] = regData; + } + + memcpy(pRandNumber, accessPtr, 6); + return retVal; +} +/* Function Name: + * rtl8367c_getAsicRldpLoopedPortmask + * Description: + * Get port number of looped pair + * Input: + * port - Physical port number (0~7) + * pLoopedPair - port (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpLoopedPortPair(rtk_uint32 port, rtk_uint32 *pLoopedPair) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_RLDP_LOOP_PORT_REG(port), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_LOOP_PORT_REG4 + ((port - 8) >> 1), RTL8367C_RLDP_LOOP_PORT_MASK(port), pLoopedPair); +} +/* Function Name: + * rtl8367c_setAsicRlppTrap8051 + * Description: + * Set trap RLPP packet to 8051 + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRlppTrap8051(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRlppTrap8051 + * Description: + * Get trap RLPP packet to 8051 + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRlppTrap8051(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLPP_8051_TRAP_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicRldpLeaveLoopedPortmask + * Description: + * Clear leaved looped portmask + * Input: + * portmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpLeaveLoopedPortmask(rtk_uint32 portmask) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, portmask); +} +/* Function Name: + * rtl8367c_getAsicRldpLeaveLoopedPortmask + * Description: + * Get leaved looped portmask + * Input: + * pPortmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpLeaveLoopedPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_RELEASED_INDICATOR, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicRldpEnterLoopedPortmask + * Description: + * Clear enter loop portmask + * Input: + * portmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpEnterLoopedPortmask(rtk_uint32 portmask) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, portmask); +} +/* Function Name: + * rtl8367c_getAsicRldpEnterLoopedPortmask + * Description: + * Get enter loop portmask + * Input: + * pPortmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpEnterLoopedPortmask(rtk_uint32 *pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_RLDP_LOOPED_INDICATOR, pPortmask); +} + +/* Function Name: + * rtl8367c_setAsicRldpTriggerMode + * Description: + * Set trigger RLDP mode + * Input: + * mode - 1: Periodically, 0: SA moving + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicRldpTriggerMode(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicRldpTriggerMode + * Description: + * Get trigger RLDP mode + * Input: + * pMode - - 1: Periodically, 0: SA moving + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldpTriggerMode(rtk_uint32 *pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_RLDP_CTRL0, RTL8367C_RLDP_TRIGGER_MODE_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicRldp8051Portmask + * Description: + * Set 8051/CPU configured looped portmask + * Input: + * portmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * Note: + * None + */ +ret_t rtl8367c_setAsicRldp8051Portmask(rtk_uint32 portmask) +{ + ret_t retVal; + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,(portmask >> 8) & 7); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicRldp8051Portmask + * Description: + * Get 8051/CPU configured looped portmask + * Input: + * pPortmask - 0~0xFF + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicRldp8051Portmask(rtk_uint32 *pPortmask) +{ + rtk_uint32 tmpPmsk; + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_RLDP_CTRL0_REG,RTL8367C_RLDP_8051_LOOP_PORTMSK_MASK,&tmpPmsk); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask = tmpPmsk & 0xff; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RLDP_CTRL5,RTL8367C_RLDP_CTRL5_MASK,&tmpPmsk); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask |= (tmpPmsk & 7) <<8; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c new file mode 100644 index 000000000000..f297defa78ac --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_rma.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 64716 $ + * $Date: 2015-12-31 16:31:55 +0800 (週四, 31 十二月 2015) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : RMA related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicRma + * Description: + * Set reserved multicast address for CPU trapping + * Input: + * index - reserved multicast LSB byte, 0x00~0x2F is available value + * pRmacfg - type of RMA for trapping frame type setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_setAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg) +{ + rtk_uint32 regData = 0; + ret_t retVal; + + if(index > RTL8367C_RMAMAX) + return RT_ERR_RMA_ADDR; + + regData |= (pRmacfg->portiso_leaky & 0x0001); + regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); + regData |= ((pRmacfg->keep_format & 0x0001) << 2); + regData |= ((pRmacfg->trap_priority & 0x0007) << 3); + regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); + regData |= ((pRmacfg->operation & 0x0003) << 7); + + if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index)) + index = 0x04; + else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f)) + index = 0x13; + else if(index >= 0x22 && index <= 0x2F) + index = 0x22; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL00+index, regData); +} +/* Function Name: + * rtl8367c_getAsicRma + * Description: + * Get reserved multicast address for CPU trapping + * Input: + * index - reserved multicast LSB byte, 0x00~0x2F is available value + * rmacfg - type of RMA for trapping frame type setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_getAsicRma(rtk_uint32 index, rtl8367c_rma_t* pRmacfg) +{ + ret_t retVal; + rtk_uint32 regData; + + if(index > RTL8367C_RMAMAX) + return RT_ERR_RMA_ADDR; + + if( (index >= 0x4 && index <= 0x7) || (index >= 0x9 && index <= 0x0C) || (0x0F == index)) + index = 0x04; + else if((index >= 0x13 && index <= 0x17) || (0x19 == index) || (index >= 0x1B && index <= 0x1f)) + index = 0x13; + else if(index >= 0x22 && index <= 0x2F) + index = 0x22; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL00+index, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->operation = ((regData >> 7) & 0x0003); + pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); + pRmacfg->trap_priority = ((regData >> 3) & 0x0007); + pRmacfg->keep_format = ((regData >> 2) & 0x0001); + pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); + pRmacfg->portiso_leaky = (regData & 0x0001); + + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->trap_priority = regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicRmaCdp + * Description: + * Set CDP(Cisco Discovery Protocol) for CPU trapping + * Input: + * pRmacfg - type of RMA for trapping frame type setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_setAsicRmaCdp(rtl8367c_rma_t* pRmacfg) +{ + rtk_uint32 regData = 0; + ret_t retVal; + + if(pRmacfg->operation >= RMAOP_END) + return RT_ERR_RMA_ACTION; + + if(pRmacfg->trap_priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + regData |= (pRmacfg->portiso_leaky & 0x0001); + regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); + regData |= ((pRmacfg->keep_format & 0x0001) << 2); + regData |= ((pRmacfg->trap_priority & 0x0007) << 3); + regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); + regData |= ((pRmacfg->operation & 0x0003) << 7); + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CDP, regData); +} +/* Function Name: + * rtl8367c_getAsicRmaCdp + * Description: + * Get CDP(Cisco Discovery Protocol) for CPU trapping + * Input: + * None + * Output: + * pRmacfg - type of RMA for trapping frame type setting + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_getAsicRmaCdp(rtl8367c_rma_t* pRmacfg) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CDP, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->operation = ((regData >> 7) & 0x0003); + pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); + pRmacfg->trap_priority = ((regData >> 3) & 0x0007); + pRmacfg->keep_format = ((regData >> 2) & 0x0001); + pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); + pRmacfg->portiso_leaky = (regData & 0x0001); + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->trap_priority = regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicRmaCsstp + * Description: + * Set CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping + * Input: + * pRmacfg - type of RMA for trapping frame type setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_setAsicRmaCsstp(rtl8367c_rma_t* pRmacfg) +{ + rtk_uint32 regData = 0; + ret_t retVal; + + if(pRmacfg->operation >= RMAOP_END) + return RT_ERR_RMA_ACTION; + + if(pRmacfg->trap_priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + regData |= (pRmacfg->portiso_leaky & 0x0001); + regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); + regData |= ((pRmacfg->keep_format & 0x0001) << 2); + regData |= ((pRmacfg->trap_priority & 0x0007) << 3); + regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); + regData |= ((pRmacfg->operation & 0x0003) << 7); + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, regData); +} +/* Function Name: + * rtl8367c_getAsicRmaCsstp + * Description: + * Get CSSTP(Cisco Shared Spanning Tree Protocol) for CPU trapping + * Input: + * None + * Output: + * pRmacfg - type of RMA for trapping frame type setting + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_getAsicRmaCsstp(rtl8367c_rma_t* pRmacfg) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_CSSTP, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->operation = ((regData >> 7) & 0x0003); + pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); + pRmacfg->trap_priority = ((regData >> 3) & 0x0007); + pRmacfg->keep_format = ((regData >> 2) & 0x0001); + pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); + pRmacfg->portiso_leaky = (regData & 0x0001); + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->trap_priority = regData; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicRmaLldp + * Description: + * Set LLDP for CPU trapping + * Input: + * pRmacfg - type of RMA for trapping frame type setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_setAsicRmaLldp(rtk_uint32 enabled, rtl8367c_rma_t* pRmacfg) +{ + rtk_uint32 regData = 0; + ret_t retVal; + + if(enabled > 1) + return RT_ERR_ENABLE; + + if(pRmacfg->operation >= RMAOP_END) + return RT_ERR_RMA_ACTION; + + if(pRmacfg->trap_priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,enabled); + if(retVal != RT_ERR_OK) + return retVal; + + regData |= (pRmacfg->portiso_leaky & 0x0001); + regData |= ((pRmacfg->vlan_leaky & 0x0001) << 1); + regData |= ((pRmacfg->keep_format & 0x0001) << 2); + regData |= ((pRmacfg->trap_priority & 0x0007) << 3); + regData |= ((pRmacfg->discard_storm_filter & 0x0001) << 6); + regData |= ((pRmacfg->operation & 0x0003) << 7); + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, pRmacfg->trap_priority); + if(retVal != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, regData); +} +/* Function Name: + * rtl8367c_getAsicRmaLldp + * Description: + * Get LLDP for CPU trapping + * Input: + * None + * Output: + * pRmacfg - type of RMA for trapping frame type setting + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_RMA_ADDR - Invalid RMA address index + * Note: + * None + */ +ret_t rtl8367c_getAsicRmaLldp(rtk_uint32 *pEnabled, rtl8367c_rma_t* pRmacfg) +{ + ret_t retVal; + rtk_uint32 regData; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_RMA_LLDP_EN, RTL8367C_RMA_LLDP_EN_OFFSET,pEnabled); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_REG_RMA_CTRL_LLDP, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->operation = ((regData >> 7) & 0x0003); + pRmacfg->discard_storm_filter = ((regData >> 6) & 0x0001); + pRmacfg->trap_priority = ((regData >> 3) & 0x0007); + pRmacfg->keep_format = ((regData >> 2) & 0x0001); + pRmacfg->vlan_leaky = ((regData >> 1) & 0x0001); + pRmacfg->portiso_leaky = (regData & 0x0001); + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_RMA_CTRL00, RTL8367C_TRAP_PRIORITY_MASK, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + pRmacfg->trap_priority = regData; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c new file mode 100644 index 000000000000..32d9b208408d --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_scheduling.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Packet Scheduling related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicLeakyBucketParameter + * Description: + * Set Leaky Bucket Parameters + * Input: + * tick - Tick is used for time slot size unit + * token - Token is used for adding budget in each time slot + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_TICK - Invalid TICK + * RT_ERR_TOKEN - Invalid TOKEN + * Note: + * None + */ +ret_t rtl8367c_setAsicLeakyBucketParameter(rtk_uint32 tick, rtk_uint32 token) +{ + ret_t retVal; + + if(tick > 0xFF) + return RT_ERR_TICK; + + if(token > 0xFF) + return RT_ERR_TOKEN; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicLeakyBucketParameter + * Description: + * Get Leaky Bucket Parameters + * Input: + * tick - Tick is used for time slot size unit + * token - Token is used for adding budget in each time slot + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicLeakyBucketParameter(rtk_uint32 *tick, rtk_uint32 *token) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TICK_REG, RTL8367C_LEAKY_BUCKET_TICK_MASK, tick); + + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_LEAKY_BUCKET_TOKEN_REG, RTL8367C_LEAKY_BUCKET_TOKEN_MASK, token); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicAprMeter + * Description: + * Set per-port per-queue APR shared meter index + * Input: + * port - Physical port number (0~10) + * qid - Queue id + * apridx - dedicated shared meter index for APR (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * None + */ +ret_t rtl8367c_setAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 apridx) +{ + ret_t retVal; + rtk_uint32 regAddr; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + if(apridx > RTL8367C_PORT_QUEUE_METER_INDEX_MAX) + return RT_ERR_FILTER_METER_ID; + + if(port < 8) + retVal = rtl8367c_setAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); + else { + regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5); + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicAprMeter + * Description: + * Get per-port per-queue APR shared meter index + * Input: + * port - Physical port number (0~10) + * qid - Queue id + * apridx - dedicated shared meter index for APR (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_getAsicAprMeter(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *apridx) +{ + ret_t retVal; + rtk_uint32 regAddr; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + if(port < 8) + retVal = rtl8367c_getAsicRegBits(RTL8367C_SCHEDULE_PORT_APR_METER_REG(port, qid), RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); + else { + regAddr = RTL8367C_REG_SCHEDULE_PORT8_APR_METER_CTRL0 + ((port-8) << 1) + (qid / 5); + retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_SCHEDULE_PORT_APR_METER_MASK(qid), apridx); + } + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicAprEnable + * Description: + * Set per-port APR enable + * Input: + * port - Physical port number (0~7) + * aprEnable - APR enable setting 1:enable 0:disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicAprEnable(rtk_uint32 port, rtk_uint32 aprEnable) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicAprEnable + * Description: + * Get per-port APR enable + * Input: + * port - Physical port number (0~7) + * aprEnable - APR enable setting 1:enable 0:disable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicAprEnable(rtk_uint32 port, rtk_uint32 *aprEnable) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_APR_CTRL_REG, RTL8367C_SCHEDULE_APR_CTRL_OFFSET(port), aprEnable); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicWFQWeight + * Description: + * Set weight of a queue + * Input: + * port - Physical port number (0~10) + * qid - The queue ID wanted to set + * qWeight - The weight value wanted to set (valid:0~127) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * RT_ERR_QOS_QUEUE_WEIGHT - Invalid queue weight + * Note: + * None + */ +ret_t rtl8367c_setAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 qWeight) +{ + ret_t retVal; + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + if(qWeight > RTL8367C_QWEIGHTMAX && qid > 0) + return RT_ERR_QOS_QUEUE_WEIGHT; + + retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicWFQWeight + * Description: + * Get weight of a queue + * Input: + * port - Physical port number (0~10) + * qid - The queue ID wanted to set + * qWeight - The weight value wanted to set (valid:0~127) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_getAsicWFQWeight(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *qWeight) +{ + ret_t retVal; + + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + + retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_PORT_QUEUE_WFQ_WEIGHT_REG(port, qid), qWeight); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicWFQBurstSize + * Description: + * Set WFQ leaky bucket burst size + * Input: + * burstsize - Leaky bucket burst size, unit byte + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicWFQBurstSize(rtk_uint32 burstsize) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicWFQBurstSize + * Description: + * Get WFQ leaky bucket burst size + * Input: + * burstsize - Leaky bucket burst size, unit byte + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicWFQBurstSize(rtk_uint32 *burstsize) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_SCHEDULE_WFQ_BURST_SIZE_REG, burstsize); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicQueueType + * Description: + * Set type of a queue + * Input: + * port - Physical port number (0~10) + * qid - The queue ID wanted to set + * queueType - The specified queue type. 0b0: Strict priority, 0b1: WFQ + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_setAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 queueType) +{ + ret_t retVal; + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + /* Set Related Registers */ + retVal = rtl8367c_setAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicQueueType + * Description: + * Get type of a queue + * Input: + * port - Physical port number (0~7) + * qid - The queue ID wanted to set + * queueType - The specified queue type. 0b0: Strict priority, 0b1: WFQ + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QUEUE_ID - Invalid queue id + * Note: + * None + */ +ret_t rtl8367c_getAsicQueueType(rtk_uint32 port, rtk_uint32 qid, rtk_uint32 *queueType) +{ + ret_t retVal; + + /* Invalid input parameter */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(qid > RTL8367C_QIDMAX) + return RT_ERR_QUEUE_ID; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_SCHEDULE_QUEUE_TYPE_REG(port), RTL8367C_SCHEDULE_QUEUE_TYPE_OFFSET(port, qid),queueType); + + return retVal; +} +/* Function Name: + * rtl8367c_setAsicPortEgressRate + * Description: + * Set per-port egress rate + * Input: + * port - Physical port number (0~10) + * rate - Egress rate + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QOS_EBW_RATE - Invalid bandwidth/rate + * Note: + * None + */ +ret_t rtl8367c_setAsicPortEgressRate(rtk_uint32 port, rtk_uint32 rate) +{ + ret_t retVal; + rtk_uint32 regAddr, regData; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(rate > RTL8367C_QOS_GRANULARTY_MAX) + return RT_ERR_QOS_EBW_RATE; + + regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port); + regData = RTL8367C_QOS_GRANULARTY_LSB_MASK & rate; + + retVal = rtl8367c_setAsicReg(regAddr, regData); + + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port); + regData = (RTL8367C_QOS_GRANULARTY_MSB_MASK & rate) >> RTL8367C_QOS_GRANULARTY_MSB_OFFSET; + + retVal = rtl8367c_setAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, regData); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicPortEgressRate + * Description: + * Get per-port egress rate + * Input: + * port - Physical port number (0~10) + * rate - Egress rate + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortEgressRate(rtk_uint32 port, rtk_uint32 *rate) +{ + ret_t retVal; + rtk_uint32 regAddr, regData,regData2; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + regAddr = RTL8367C_PORT_EGRESSBW_LSB_REG(port); + + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_PORT_EGRESSBW_MSB_REG(port); + retVal = rtl8367c_getAsicRegBits(regAddr, RTL8367C_PORT6_EGRESSBW_CTRL1_MASK, ®Data2); + if(retVal != RT_ERR_OK) + return retVal; + + *rate = regData | (regData2 << RTL8367C_QOS_GRANULARTY_MSB_OFFSET); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicPortEgressRateIfg + * Description: + * Set per-port egress rate calculate include/exclude IFG + * Input: + * ifg - 1:include IFG 0:exclude IFG + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicPortEgressRateIfg(rtk_uint32 ifg) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg); + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicPortEgressRateIfg + * Description: + * Get per-port egress rate calculate include/exclude IFG + * Input: + * ifg - 1:include IFG 0:exclude IFG + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicPortEgressRateIfg(rtk_uint32 *ifg) +{ + ret_t retVal; + + retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_SCHEDULE_WFQ_CTRL, RTL8367C_SCHEDULE_WFQ_CTRL_OFFSET, ifg); + + return retVal; +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c new file mode 100644 index 000000000000..a29f64769d65 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_storm.c @@ -0,0 +1,851 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Storm control filtering related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicStormFilterBroadcastEnable + * Description: + * Set per-port broadcast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_STORM_BCAST_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicStormFilterBroadcastEnable + * Description: + * Get per-port broadcast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterBroadcastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_STORM_BCAST_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicStormFilterBroadcastMeter + * Description: + * Set per-port broadcast storm filter meter + * Input: + * port - Physical port number (0~7) + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 meter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), meter); +} +/* Function Name: + * rtl8367c_getAsicStormFilterBroadcastMeter + * Description: + * Get per-port broadcast storm filter meter + * Input: + * port - Physical port number (0~7) + * pMeter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterBroadcastMeter(rtk_uint32 port, rtk_uint32 *pMeter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_STORM_BCAST_METER_CTRL_REG(port), RTL8367C_STORM_BCAST_METER_CTRL_MASK(port), pMeter); +} +/* Function Name: + * rtl8367c_setAsicStormFilterMulticastEnable + * Description: + * Set per-port multicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_STORM_MCAST_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicStormFilterMulticastEnable + * Description: + * Get per-port multicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_STORM_MCAST_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicStormFilterMulticastMeter + * Description: + * Set per-port multicast storm filter meter + * Input: + * port - Physical port number (0~7) + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 meter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), meter); +} +/* Function Name: + * rtl8367c_getAsicStormFilterMulticastMeter + * Description: + * Get per-port multicast storm filter meter + * Input: + * port - Physical port number (0~7) + * pMeter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_STORM_MCAST_METER_CTRL_REG(port), RTL8367C_STORM_MCAST_METER_CTRL_MASK(port), pMeter); +} +/* Function Name: + * rtl8367c_setAsicStormFilterUnknownMulticastEnable + * Description: + * Set per-port unknown multicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicStormFilterUnknownMulticastEnable + * Description: + * Get per-port unknown multicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_MCAST_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicStormFilterUnknownMulticastMeter + * Description: + * Set per-port unknown multicast storm filter meter + * Input: + * port - Physical port number (0~7) + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 meter) +{ + ret_t retVal; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), meter); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicStormFilterUnknownMulticastMeter + * Description: + * Get per-port unknown multicast storm filter meter + * Input: + * port - Physical port number (0~7) + * pMeter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_uint32 port, rtk_uint32 *pMeter) +{ + ret_t retVal; + + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_STORM_UNMC_METER_CTRL_REG(port), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_UNMC_METER_CTRL4 + ((port - 8) >> 1), RTL8367C_STORM_UNMC_METER_CTRL_MASK(port), pMeter); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicStormFilterUnknownUnicastEnable + * Description: + * Set per-port unknown unicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicStormFilterUnknownUnicastEnable + * Description: + * get per-port unknown unicast storm filter enable/disable + * Input: + * port - Physical port number (0~7) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_uint32 port, rtk_uint32 *pEnabled) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_STORM_UNKNOWN_UCAST_REG, port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicStormFilterUnknownUnicastMeter + * Description: + * Set per-port unknown unicast storm filter meter + * Input: + * port - Physical port number (0~7) + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 meter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), meter); +} +/* Function Name: + * rtl8367c_getAsicStormFilterUnknownUnicastMeter + * Description: + * Get per-port unknown unicast storm filter meter + * Input: + * port - Physical port number (0~7) + * pMeter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_uint32 port, rtk_uint32 *pMeter) +{ + if(port >= RTL8367C_PORTNO) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_STORM_UNDA_METER_CTRL_REG(port), RTL8367C_STORM_UNDA_METER_CTRL_MASK(port), pMeter); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtBroadcastMeter + * Description: + * Set extension broadcast storm filter meter + * Input: + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtBroadcastMeter(rtk_uint32 meter) +{ + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, meter); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtBroadcastMeter + * Description: + * get extension broadcast storm filter meter + * Input: + * None + * Output: + * pMeter - meter index (0~31) + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtBroadcastMeter(rtk_uint32 *pMeter) +{ + if(NULL == pMeter) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_BC_STORM_EXT_METERIDX_MASK, pMeter); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtMulticastMeter + * Description: + * Set extension multicast storm filter meter + * Input: + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtMulticastMeter(rtk_uint32 meter) +{ + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, meter); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtMulticastMeter + * Description: + * get extension multicast storm filter meter + * Input: + * None + * Output: + * pMeter - meter index (0~31) + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtMulticastMeter(rtk_uint32 *pMeter) +{ + if(NULL == pMeter) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG0, RTL8367C_MC_STORM_EXT_METERIDX_MASK, pMeter); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtUnknownMulticastMeter + * Description: + * Set extension unknown multicast storm filter meter + * Input: + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 meter) +{ + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, meter); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtUnknownMulticastMeter + * Description: + * get extension unknown multicast storm filter meter + * Input: + * None + * Output: + * pMeter - meter index (0~31) + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(rtk_uint32 *pMeter) +{ + if(NULL == pMeter) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNMC_STORM_EXT_METERIDX_MASK, pMeter); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtUnknownUnicastMeter + * Description: + * Set extension unknown unicast storm filter meter + * Input: + * meter - meter index (0~31) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_FILTER_METER_ID - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 meter) +{ + if(meter > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, meter); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtUnknownUnicastMeter + * Description: + * get extension unknown unicast storm filter meter + * Input: + * None + * Output: + * pMeter - meter index (0~31) + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Invalid meter index + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(rtk_uint32 *pMeter) +{ + if(NULL == pMeter) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_MTRIDX_CFG1, RTL8367C_UNUC_STORM_EXT_METERIDX_MASK, pMeter); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtBroadcastEnable + * Description: + * Set extension broadcast storm filter state + * Input: + * enabled - state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtBroadcastEnable(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, enabled); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtBroadcastEnable + * Description: + * Get extension broadcast storm filter state + * Input: + * None + * Output: + * pEnabled - state + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtBroadcastEnable(rtk_uint32 *pEnabled) +{ + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_BCAST_EXT_EN_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtMulticastEnable + * Description: + * Set extension multicast storm filter state + * Input: + * enabled - state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtMulticastEnable(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, enabled); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtMulticastEnable + * Description: + * Get extension multicast storm filter state + * Input: + * None + * Output: + * pEnabled - state + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtMulticastEnable(rtk_uint32 *pEnabled) +{ + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_MCAST_EXT_EN_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtUnknownMulticastEnable + * Description: + * Set extension unknown multicast storm filter state + * Input: + * enabled - state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, enabled); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtUnknownMulticastEnable + * Description: + * Get extension unknown multicast storm filter state + * Input: + * None + * Output: + * pEnabled - state + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtUnknownMulticastEnable(rtk_uint32 *pEnabled) +{ + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_MCAST_EXT_EN_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtUnknownUnicastEnable + * Description: + * Set extension unknown unicast storm filter state + * Input: + * enabled - state + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, enabled); +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtUnknownUnicastEnable + * Description: + * Get extension unknown unicast storm filter state + * Input: + * None + * Output: + * pEnabled - state + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtUnknownUnicastEnable(rtk_uint32 *pEnabled) +{ + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_UNKNOWN_UCAST_EXT_EN_OFFSET, pEnabled); +} + +/* Function Name: + * rtl8367c_setAsicStormFilterExtEnablePortMask + * Description: + * Set extension storm filter port mask + * Input: + * portmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicStormFilterExtEnablePortMask(rtk_uint32 portmask) +{ + ret_t retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, portmask & 0x3FF); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, (portmask >> 10)&1); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicStormFilterExtEnablePortMask + * Description: + * Get extension storm filter port mask + * Input: + * portmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getAsicStormFilterExtEnablePortMask(rtk_uint32 *pPortmask) +{ + rtk_uint32 tmpPmsk; + ret_t retVal; + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_MASK, &tmpPmsk); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask = tmpPmsk & 0x3ff; + + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_STORM_EXT_CFG, RTL8367C_STORM_EXT_EN_PORTMASK_EXT_MASK, &tmpPmsk); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask |= (tmpPmsk & 1) << 10; + + return RT_ERR_OK; +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c new file mode 100644 index 000000000000..e199664b5e73 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_svlan.c @@ -0,0 +1,1003 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : SVLAN related functions + * + */ +#include + +#include + +static void _rtl8367c_svlanConfStUser2Smi( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt) +{ + pSmiSt[0] |= (pUserSt->vs_member & 0x00FF); + pSmiSt[0] |= (pUserSt->vs_untag & 0x00FF) << 8; + + pSmiSt[1] |= (pUserSt->vs_fid_msti & 0x000F); + pSmiSt[1] |= (pUserSt->vs_priority & 0x0007) << 4; + pSmiSt[1] |= (pUserSt->vs_force_fid & 0x0001) << 7; + + pSmiSt[2] |= (pUserSt->vs_svid & 0x0FFF); + pSmiSt[2] |= (pUserSt->vs_efiden & 0x0001) << 12; + pSmiSt[2] |= (pUserSt->vs_efid & 0x0007) << 13; + + pSmiSt[3] |= ((pUserSt->vs_member & 0x0700) >> 8); + pSmiSt[3] |= ((pUserSt->vs_untag & 0x0700) >> 8) << 3; +} + +static void _rtl8367c_svlanConfStSmi2User( rtl8367c_svlan_memconf_t *pUserSt, rtk_uint16 *pSmiSt) +{ + + pUserSt->vs_member = (pSmiSt[0] & 0x00FF) | ((pSmiSt[3] & 0x0007) << 8); + pUserSt->vs_untag = ((pSmiSt[0] & 0xFF00) >> 8) | (((pSmiSt[3] & 0x0038) >> 3) << 8); + + pUserSt->vs_fid_msti = (pSmiSt[1] & 0x000F); + pUserSt->vs_priority = (pSmiSt[1] & 0x0070) >> 4; + pUserSt->vs_force_fid = (pSmiSt[1] & 0x0080) >> 7; + + pUserSt->vs_svid = (pSmiSt[2] & 0x0FFF); + pUserSt->vs_efiden = (pSmiSt[2] & 0x1000) >> 12; + pUserSt->vs_efid = (pSmiSt[2] & 0xE000) >> 13; +} + +static void _rtl8367c_svlanMc2sStUser2Smi(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt) +{ + pSmiSt[0] |= (pUserSt->svidx & 0x003F); + pSmiSt[0] |= (pUserSt->format & 0x0001) << 6; + pSmiSt[0] |= (pUserSt->valid & 0x0001) << 7; + + pSmiSt[1] = (rtk_uint16)(pUserSt->smask & 0x0000FFFF); + pSmiSt[2] = (rtk_uint16)((pUserSt->smask & 0xFFFF0000) >> 16); + + pSmiSt[3] = (rtk_uint16)(pUserSt->sdata & 0x0000FFFF); + pSmiSt[4] = (rtk_uint16)((pUserSt->sdata & 0xFFFF0000) >> 16); +} + +static void _rtl8367c_svlanMc2sStSmi2User(rtl8367c_svlan_mc2s_t *pUserSt, rtk_uint16 *pSmiSt) +{ + pUserSt->svidx = (pSmiSt[0] & 0x003F); + pUserSt->format = (pSmiSt[0] & 0x0040) >> 6; + pUserSt->valid = (pSmiSt[0] & 0x0080) >> 7; + + pUserSt->smask = pSmiSt[1] | (pSmiSt[2] << 16); + pUserSt->sdata = pSmiSt[3] | (pSmiSt[4] << 16); +} + +static void _rtl8367c_svlanSp2cStUser2Smi(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt) +{ + pSmiSt[0] |= (pUserSt->dstport & 0x0007); + pSmiSt[0] |= (pUserSt->svidx & 0x003F) << 3; + pSmiSt[0] |= ((pUserSt->dstport & 0x0008) >> 3) << 9; + + pSmiSt[1] |= (pUserSt->vid & 0x0FFF); + pSmiSt[1] |= (pUserSt->valid & 0x0001) << 12; +} + +static void _rtl8367c_svlanSp2cStSmi2User(rtl8367c_svlan_s2c_t *pUserSt, rtk_uint16 *pSmiSt) +{ + pUserSt->dstport = (((pSmiSt[0] & 0x0200) >> 9) << 3) | (pSmiSt[0] & 0x0007); + pUserSt->svidx = (pSmiSt[0] & 0x01F8) >> 3; + pUserSt->vid = (pSmiSt[1] & 0x0FFF); + pUserSt->valid = (pSmiSt[1] & 0x1000) >> 12; +} + +/* Function Name: + * rtl8367c_setAsicSvlanUplinkPortMask + * Description: + * Set uplink ports mask + * Input: + * portMask - Uplink port mask setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanUplinkPortMask(rtk_uint32 portMask) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, portMask); +} +/* Function Name: + * rtl8367c_getAsicSvlanUplinkPortMask + * Description: + * Get uplink ports mask + * Input: + * pPortmask - Uplink port mask setting + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanUplinkPortMask(rtk_uint32* pPortmask) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_SVLAN_UPLINK_PORTMASK, pPortmask); +} +/* Function Name: + * rtl8367c_setAsicSvlanTpid + * Description: + * Set accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8 + * Input: + * protocolType - Ether type of S-tag frame parsing in uplink ports + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 + * for Q-in-Q SLAN design. User can set matched ether type as service provider supported protocol + */ +ret_t rtl8367c_setAsicSvlanTpid(rtk_uint32 protocolType) +{ + return rtl8367c_setAsicReg(RTL8367C_REG_VS_TPID, protocolType); +} +/* Function Name: + * rtl8367c_getAsicReg + * Description: + * Get accepted S-VLAN ether type. The default ether type of S-VLAN is 0x88a8 + * Input: + * pProtocolType - Ether type of S-tag frame parsing in uplink ports + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanTpid(rtk_uint32* pProtocolType) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_VS_TPID, pProtocolType); +} +/* Function Name: + * rtl8367c_setAsicSvlanPrioritySel + * Description: + * Set SVLAN priority field setting + * Input: + * priSel - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanPrioritySel(rtk_uint32 priSel) +{ + if(priSel >= SPRISEL_END) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, priSel); +} +/* Function Name: + * rtl8367c_getAsicSvlanPrioritySel + * Description: + * Get SVLAN priority field setting + * Input: + * pPriSel - S-priority assignment method, 0:internal priority 1:C-tag priority 2:using Svlan member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanPrioritySel(rtk_uint32* pPriSel) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_SPRISEL_MASK, pPriSel); +} +/* Function Name: + * rtl8367c_setAsicSvlanTrapPriority + * Description: + * Set trap to CPU priority assignment + * Input: + * priority - Priority assignment + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanTrapPriority(rtk_uint32 priority) +{ + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, priority); +} +/* Function Name: + * rtl8367c_getAsicSvlanTrapPriority + * Description: + * Get trap to CPU priority assignment + * Input: + * pPriority - Priority assignment + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanTrapPriority(rtk_uint32* pPriority) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_QOS_TRAP_PRIORITY0, RTL8367C_SVLAN_PRIOIRTY_MASK, pPriority); +} +/* Function Name: + * rtl8367c_setAsicSvlanDefaultVlan + * Description: + * Set default egress SVLAN + * Input: + * port - Physical port number (0~10) + * index - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32 index) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + if(port < 8){ + if(port & 1) + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,index); + else + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,index); + }else{ + switch(port){ + case 8: + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,index); + break; + + case 9: + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,index); + break; + + case 10: + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,index); + break; + } + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicSvlanDefaultVlan + * Description: + * Get default egress SVLAN + * Input: + * port - Physical port number (0~7) + * pIndex - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanDefaultVlan(rtk_uint32 port, rtk_uint32* pIndex) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8){ + if(port & 1) + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT1_SVIDX_MASK,pIndex); + else + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL0 + (port >> 1), RTL8367C_VS_PORT0_SVIDX_MASK,pIndex); + }else{ + switch(port){ + case 8: + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT8_SVIDX_MASK,pIndex); + break; + + case 9: + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL4, RTL8367C_VS_PORT9_SVIDX_MASK,pIndex); + break; + + case 10: + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_PORTBASED_SVIDX_CTRL5, RTL8367C_SVLAN_PORTBASED_SVIDX_CTRL5_MASK,pIndex); + break; + } + } + + return retVal; + +} +/* Function Name: + * rtl8367c_setAsicSvlanIngressUntag + * Description: + * Set action received un-Stag frame from uplink port + * Input: + * mode - 0:Drop 1:Trap 2:Assign SVLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanIngressUntag(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, mode); +} +/* Function Name: + * rtl8367c_getAsicSvlanIngressUntag + * Description: + * Get action received un-Stag frame from uplink port + * Input: + * pMode - 0:Drop 1:Trap 2:Assign SVLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanIngressUntag(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNTAG_MASK, pMode); +} +/* Function Name: + * rtl8367c_setAsicSvlanIngressUnmatch + * Description: + * Set action received unmatched Stag frame from uplink port + * Input: + * mode - 0:Drop 1:Trap 2:Assign SVLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanIngressUnmatch(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, mode); +} +/* Function Name: + * rtl8367c_getAsicSvlanIngressUnmatch + * Description: + * Get action received unmatched Stag frame from uplink port + * Input: + * pMode - 0:Drop 1:Trap 2:Assign SVLAN + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanIngressUnmatch(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UNMAT_MASK, pMode); + +} +/* Function Name: + * rtl8367c_setAsicSvlanEgressUnassign + * Description: + * Set uplink stream without egress SVID action + * Input: + * enabled - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanEgressUnassign(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicSvlanEgressUnassign + * Description: + * Get uplink stream without egress SVID action + * Input: + * pEnabled - 1:Trap egress unassigned frames to CPU, 0: Use SVLAN setup in VS_CPSVIDX as egress SVID + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanEgressUnassign(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_UIFSEG_OFFSET, pEnabled); +} + + +/* Function Name: + * rtl8367c_setAsicSvlanMemberConfiguration + * Description: + * Set system 64 S-tag content + * Input: + * index - index of 64 s-tag configuration + * pSvlanMemCfg - SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanMemberConfiguration(rtk_uint32 index, rtl8367c_svlan_memconf_t* pSvlanMemCfg) +{ + ret_t retVal; + rtk_uint32 regAddr, regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN]; + + if(index > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN); + _rtl8367c_svlanConfStUser2Smi(pSvlanMemCfg, smiSvlanMemConf); + + accessPtr = smiSvlanMemConf; + + regData = *accessPtr; + for(i = 0; i < 3; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr ++; + regData = *accessPtr; + } + + if(index < 63) + regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index; + else if(index == 63) + regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4; + + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} +/* Function Name: + * rtl8367c_getAsicSvlanMemberConfiguration + * Description: + * Get system 64 S-tag content + * Input: + * index - index of 64 s-tag configuration + * pSvlanMemCfg - SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanMemberConfiguration(rtk_uint32 index,rtl8367c_svlan_memconf_t* pSvlanMemCfg) +{ + ret_t retVal; + rtk_uint32 regAddr,regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanMemConf[RTL8367C_SVLAN_MEMCONF_LEN]; + + if(index > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + memset(smiSvlanMemConf, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MEMCONF_LEN); + + accessPtr = smiSvlanMemConf; + + for(i = 0; i < 3; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MEMBERCFG_BASE_REG(index) + i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + + accessPtr ++; + } + + if(index < 63) + regAddr = RTL8367C_REG_SVLAN_MEMBERCFG0_CTRL4+index; + else if(index == 63) + regAddr = RTL8367C_REG_SVLAN_MEMBERCFG63_CTRL4; + + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + + _rtl8367c_svlanConfStSmi2User(pSvlanMemCfg, smiSvlanMemConf); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicSvlanC2SConf + * Description: + * Set SVLAN C2S table + * Input: + * index - index of 128 Svlan C2S configuration + * evid - Enhanced VID + * portmask - available c2s port mask + * svidx - index of 64 Svlan member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * ASIC will check upstream's VID and assign related SVID to matched packet + */ +ret_t rtl8367c_setAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32 evid, rtk_uint32 portmask, rtk_uint32 svidx) +{ + ret_t retVal; + + if(index > RTL8367C_C2SIDXMAX) + return RT_ERR_ENTRY_INDEX; + + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), svidx); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, portmask); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, evid); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicSvlanC2SConf + * Description: + * Get SVLAN C2S table + * Input: + * index - index of 128 Svlan C2S configuration + * pEvid - Enhanced VID + * pPortmask - available c2s port mask + * pSvidx - index of 64 Svlan member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanC2SConf(rtk_uint32 index, rtk_uint32* pEvid, rtk_uint32* pPortmask, rtk_uint32* pSvidx) +{ + ret_t retVal; + + if(index > RTL8367C_C2SIDXMAX) + return RT_ERR_ENTRY_INDEX; + + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index), pSvidx); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 1, pPortmask); + if(retVal != RT_ERR_OK) + return retVal; + + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_C2SCFG_BASE_REG(index) + 2, pEvid); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicSvlanMC2SConf + * Description: + * Set system MC2S content + * Input: + * index - index of 32 SVLAN 32 MC2S configuration + * pSvlanMc2sCfg - SVLAN Multicast to SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * If upstream packet is L2 multicast or IPv4 multicast packet and DMAC/DIP is matched MC2S + * configuration, ASIC will assign egress SVID to the packet + */ +ret_t rtl8367c_setAsicSvlanMC2SConf(rtk_uint32 index,rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN]; + + if(index > RTL8367C_MC2SIDXMAX) + return RT_ERR_ENTRY_INDEX; + + memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN); + _rtl8367c_svlanMc2sStUser2Smi(pSvlanMc2sCfg, smiSvlanMC2S); + + accessPtr = smiSvlanMC2S; + + regData = *accessPtr; + for(i = 0; i < 5; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr ++; + regData = *accessPtr; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicSvlanMC2SConf + * Description: + * Get system MC2S content + * Input: + * index - index of 32 SVLAN 32 MC2S configuration + * pSvlanMc2sCfg - SVLAN Multicast to SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanMC2SConf(rtk_uint32 index, rtl8367c_svlan_mc2s_t* pSvlanMc2sCfg) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanMC2S[RTL8367C_SVLAN_MC2S_LEN]; + + if(index > RTL8367C_MC2SIDXMAX) + return RT_ERR_ENTRY_INDEX; + + memset(smiSvlanMC2S, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_MC2S_LEN); + + accessPtr = smiSvlanMC2S; + + for(i = 0; i < 5; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_MCAST2S_ENTRY_BASE_REG(index) + i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + accessPtr ++; + } + + + _rtl8367c_svlanMc2sStSmi2User(pSvlanMc2sCfg, smiSvlanMC2S); + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setAsicSvlanSP2CConf + * Description: + * Set system 128 SP2C content + * Input: + * index - index of 128 SVLAN & Port to CVLAN configuration + * pSvlanSp2cCfg - SVLAN & Port to CVLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanSP2CConf(rtk_uint32 index, rtl8367c_svlan_s2c_t* pSvlanSp2cCfg) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN]; + + if(index > RTL8367C_SP2CMAX) + return RT_ERR_ENTRY_INDEX; + + memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN); + _rtl8367c_svlanSp2cStUser2Smi(pSvlanSp2cCfg,smiSvlanSP2C); + + accessPtr = smiSvlanSP2C; + + regData = *accessPtr; + for(i = 0; i < 2; i++) + { + retVal = rtl8367c_setAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, regData); + if(retVal != RT_ERR_OK) + return retVal; + + accessPtr ++; + regData = *accessPtr; + } + + return retVal; +} +/* Function Name: + * rtl8367c_getAsicSvlanSP2CConf + * Description: + * Get system 128 SP2C content + * Input: + * index - index of 128 SVLAN & Port to CVLAN configuration + * pSvlanSp2cCfg - SVLAN & Port to CVLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_ENTRY_INDEX - Invalid entry index + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanSP2CConf(rtk_uint32 index,rtl8367c_svlan_s2c_t* pSvlanSp2cCfg) +{ + ret_t retVal; + rtk_uint32 regData; + rtk_uint16 *accessPtr; + rtk_uint32 i; + rtk_uint16 smiSvlanSP2C[RTL8367C_SVLAN_SP2C_LEN]; + + if(index > RTL8367C_SP2CMAX) + return RT_ERR_ENTRY_INDEX; + + memset(smiSvlanSP2C, 0x00, sizeof(rtk_uint16) * RTL8367C_SVLAN_SP2C_LEN); + + accessPtr = smiSvlanSP2C; + + for(i = 0; i < 2; i++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_SVLAN_S2C_ENTRY_BASE_REG(index) + i, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *accessPtr = regData; + + accessPtr ++; + } + + _rtl8367c_svlanSp2cStSmi2User(pSvlanSp2cCfg, smiSvlanSP2C); + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicSvlanDmacCvidSel + * Description: + * Set downstream CVID decision by DMAC + * Input: + * port - Physical port number (0~7) + * enabled - 0:disabled, 1:enabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, enabled); + else + return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), enabled); +} +/* Function Name: + * rtl8367c_getAsicSvlanDmacCvidSel + * Description: + * Get downstream CVID decision by DMAC + * Input: + * port - Physical port number (0~7) + * pEnabled - 0:disabled, 1:enabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanDmacCvidSel(rtk_uint32 port, rtk_uint32* pEnabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG, RTL8367C_VS_PORT0_DMACVIDSEL_OFFSET + port, pEnabled); + else + return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_CFG_EXT, RTL8367C_VS_PORT8_DMACVIDSEL_OFFSET + (port-8), pEnabled); +} +/* Function Name: + * rtl8367c_setAsicSvlanUntagVlan + * Description: + * Set default ingress untag SVLAN + * Input: + * index - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanUntagVlan(rtk_uint32 index) +{ + if(index > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, index); +} +/* Function Name: + * rtl8367c_getAsicSvlanUntagVlan + * Description: + * Get default ingress untag SVLAN + * Input: + * pIndex - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanUntagVlan(rtk_uint32* pIndex) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNTAG_SVIDX_MASK, pIndex); +} + +/* Function Name: + * rtl8367c_setAsicSvlanUnmatchVlan + * Description: + * Set default ingress unmatch SVLAN + * Input: + * index - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_INDEX - Invalid SVLAN index parameter + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanUnmatchVlan(rtk_uint32 index) +{ + if(index > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, index); +} +/* Function Name: + * rtl8367c_getAsicSvlanUnmatchVlan + * Description: + * Get default ingress unmatch SVLAN + * Input: + * pIndex - index SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanUnmatchVlan(rtk_uint32* pIndex) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_SVLAN_UNTAG_UNMAT_CFG, RTL8367C_VS_UNMAT_SVIDX_MASK, pIndex); +} + + +/* Function Name: + * rtl8367c_setAsicSvlanLookupType + * Description: + * Set svlan lookup table selection + * Input: + * type - lookup type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicSvlanLookupType(rtk_uint32 type) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, type); +} + +/* Function Name: + * rtl8367c_getAsicSvlanLookupType + * Description: + * Get svlan lookup table selection + * Input: + * pType - lookup type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicSvlanLookupType(rtk_uint32* pType) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_SVLAN_LOOKUP_TYPE, RTL8367C_SVLAN_LOOKUP_TYPE_OFFSET, pType); +} + + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c new file mode 100644 index 000000000000..26d4c29b83b9 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_trunking.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Port trunking related functions + * + */ + +#include +/* Function Name: + * rtl8367c_setAsicTrunkingMode + * Description: + * Set port trunking mode + * Input: + * mode - 1:dumb 0:user defined + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingMode(rtk_uint32 mode) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, mode); +} +/* Function Name: + * rtl8367c_getAsicTrunkingMode + * Description: + * Get port trunking mode + * Input: + * pMode - 1:dumb 0:user defined + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingMode(rtk_uint32* pMode) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_DUMB_OFFSET, pMode); +} +/* Function Name: + * rtl8367c_setAsicTrunkingFc + * Description: + * Set port trunking flow control + * Input: + * group - Trunk Group ID + * enabled - 0:disable, 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingFc(rtk_uint32 group, rtk_uint32 enabled) +{ + ret_t retVal; + + if(group > RTL8367C_MAX_TRUNK_GID) + return RT_ERR_LA_TRUNK_ID; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_DROP_CTRL, RTL8367C_PORT_TRUNK_DROP_CTRL_OFFSET, ENABLED)) != RT_ERR_OK) + return retVal; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), enabled); +} +/* Function Name: + * rtl8367c_getAsicTrunkingFc + * Description: + * Get port trunking flow control + * Input: + * group - Trunk Group ID + * pEnabled - 0:disable, 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingFc(rtk_uint32 group, rtk_uint32* pEnabled) +{ + if(group > RTL8367C_MAX_TRUNK_GID) + return RT_ERR_LA_TRUNK_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_FLOWCTRL, (RTL8367C_EN_FLOWCTRL_TG0_OFFSET + group), pEnabled); +} +/* Function Name: + * rtl8367c_setAsicTrunkingGroup + * Description: + * Set trunking group available port mask + * Input: + * group - Trunk Group ID + * portmask - Logic trunking enable port mask, max 4 ports + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingGroup(rtk_uint32 group, rtk_uint32 portmask) +{ + if(group > RTL8367C_MAX_TRUNK_GID) + return RT_ERR_LA_TRUNK_ID; + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), portmask); +} +/* Function Name: + * rtl8367c_getAsicTrunkingGroup + * Description: + * Get trunking group available port mask + * Input: + * group - Trunk Group ID + * Output: + * pPortmask - Logic trunking enable port mask, max 4 ports + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingGroup(rtk_uint32 group, rtk_uint32* pPortmask) +{ + if(group > RTL8367C_MAX_TRUNK_GID) + return RT_ERR_LA_TRUNK_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_GROUP_MASK, RTL8367C_PORT_TRUNK_GROUP0_MASK_MASK << (group * 4), pPortmask); +} +/* Function Name: + * rtl8367c_setAsicTrunkingFlood + * Description: + * Set port trunking flood function + * Input: + * enabled - Port trunking flooding function 0:disable 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingFlood(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicTrunkingFlood + * Description: + * Get port trunking flood function + * Input: + * pEnabled - Port trunking flooding function 0:disable 1:enable + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingFlood(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_FLOOD_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicTrunkingHashSelect + * Description: + * Set port trunking hash select sources + * Input: + * hashsel - hash sources mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} + * 0b0000001: SPA + * 0b0000010: SMAC + * 0b0000100: DMAC + * 0b0001000: SIP + * 0b0010000: DIP + * 0b0100000: TCP/UDP Source Port + * 0b1000000: TCP/UDP Destination Port + */ +ret_t rtl8367c_setAsicTrunkingHashSelect(rtk_uint32 hashsel) +{ + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, hashsel); +} +/* Function Name: + * rtl8367c_getAsicTrunkingHashSelect + * Description: + * Get port trunking hash select sources + * Input: + * pHashsel - hash sources mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingHashSelect(rtk_uint32* pHashsel) +{ + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_CTRL, RTL8367C_PORT_TRUNK_HASH_MASK, pHashsel); +} +/* Function Name: + * rtl8367c_getAsicQeueuEmptyStatus + * Description: + * Get current output queue if empty status + * Input: + * portmask - queue empty port mask + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicQeueuEmptyStatus(rtk_uint32* portmask) +{ + return rtl8367c_getAsicReg(RTL8367C_REG_PORT_QEMPTY, portmask); +} +/* Function Name: + * rtl8367c_setAsicTrunkingHashTable + * Description: + * Set port trunking hash value mapping table + * Input: + * hashval - hashing value 0-15 + * portId - trunking port id 0-3 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32 portId) +{ + if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) + return RT_ERR_OUT_OF_RANGE; + + if(portId >= RTL8367C_TRUNKING_PORTNO) + return RT_ERR_PORT_ID; + + if(hashval >= 8) + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), portId); + else + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), portId); +} +/* Function Name: + * rtl8367c_getAsicTrunkingHashTable + * Description: + * Get port trunking hash value mapping table + * Input: + * hashval - hashing value 0-15 + * pPortId - trunking port id 0-3 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingHashTable(rtk_uint32 hashval, rtk_uint32* pPortId) +{ + if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) + return RT_ERR_OUT_OF_RANGE; + + if(hashval >= 8) + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL1, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL1_HASH8_MASK<<((hashval-8)*2), pPortId); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL0, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL0_HASH0_MASK<<(hashval*2), pPortId); +} + +/* Function Name: + * rtl8367c_setAsicTrunkingHashTable1 + * Description: + * Set port trunking hash value mapping table + * Input: + * hashval - hashing value 0-15 + * portId - trunking port id 0-3 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) + * Note: + * None + */ +ret_t rtl8367c_setAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32 portId) +{ + if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) + return RT_ERR_OUT_OF_RANGE; + + if(portId >= RTL8367C_TRUNKING1_PORTN0) + return RT_ERR_PORT_ID; + + if(hashval >= 8) + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), portId); + else + return rtl8367c_setAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), portId); +} +/* Function Name: + * rtl8367c_getAsicTrunkingHashTable1 + * Description: + * Get port trunking hash value mapping table + * Input: + * hashval - hashing value 0-15 + * pPortId - trunking port id 0-3 + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_OUT_OF_RANGE - Invalid hashing value (0-15) + * Note: + * None + */ +ret_t rtl8367c_getAsicTrunkingHashTable1(rtk_uint32 hashval, rtk_uint32* pPortId) +{ + if(hashval > RTL8367C_TRUNKING_HASHVALUE_MAX) + return RT_ERR_OUT_OF_RANGE; + + if(hashval >= 8) + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL3, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL3_HASH8_MASK<<((hashval-8)*2), pPortId); + else + return rtl8367c_getAsicRegBits(RTL8367C_REG_PORT_TRUNK_HASH_MAPPING_CTRL2, RTL8367C_PORT_TRUNK_HASH_MAPPING_CTRL2_HASH0_MASK<<(hashval*2), pPortId); +} + diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c new file mode 100644 index 000000000000..a3455bbebdc6 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_unknownMulticast.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : Unknown multicast related functions + * + */ + +#include + +/* Function Name: + * rtl8367c_setAsicUnknownL2MulticastBehavior + * Description: + * Set behavior of L2 multicast + * Input: + * port - Physical port number (0~7) + * behave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_NOT_ALLOWED - Invalid operation + * Note: + * None + */ +ret_t rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(behave >= L2_UNKOWN_MULTICAST_END) + return RT_ERR_NOT_ALLOWED; + if(port < 8) + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), behave); + if(retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), behave); + if(retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicUnknownL2MulticastBehavior + * Description: + * Get behavior of L2 multicast + * Input: + * port - Physical port number (0~7) + * pBehave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) +{ + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_L2_MULTICAST_REG(port), RTL8367C_UNKNOWN_L2_MULTICAST_MASK(port), pBehave); + if (retVal != RT_ERR_OK) + return retVal; + } + else + { + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_UNKNOWN_L2_MULTICAST_CTRL1, 3 << ((port - 8) << 1), pBehave); + if (retVal != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicUnknownIPv4MulticastBehavior + * Description: + * Set behavior of IPv4 multicast + * Input: + * port - Physical port number (0~7) + * behave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_NOT_ALLOWED - Invalid operation + * Note: + * None + */ +ret_t rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(behave >= L3_UNKOWN_MULTICAST_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), behave); +} +/* Function Name: + * rtl8367c_getAsicUnknownIPv4MulticastBehavior + * Description: + * Get behavior of IPv4 multicast + * Input: + * port - Physical port number (0~7) + * pBehave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV4_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV4_MULTICAST_MASK(port), pBehave); +} +/* Function Name: + * rtl8367c_setAsicUnknownIPv6MulticastBehavior + * Description: + * Set behavior of IPv6 multicast + * Input: + * port - Physical port number (0~7) + * behave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_NOT_ALLOWED - Invalid operation + * Note: + * None + */ +ret_t rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 behave) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(behave >= L3_UNKOWN_MULTICAST_END) + return RT_ERR_NOT_ALLOWED; + + return rtl8367c_setAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), behave); +} +/* Function Name: + * rtl8367c_getAsicUnknownIPv6MulticastBehavior + * Description: + * Get behavior of IPv6 multicast + * Input: + * port - Physical port number (0~7) + * pBehave - 0: flooding, 1: drop, 2: trap + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_uint32 port, rtk_uint32 *pBehave) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_UNKNOWN_IPV6_MULTICAST_REG(port), RTL8367C_UNKNOWN_IPV6_MULTICAST_MASK(port), pBehave); +} +/* Function Name: + * rtl8367c_setAsicUnknownMulticastTrapPriority + * Description: + * Set trap priority of unknown multicast frame + * Input: + * priority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicUnknownMulticastTrapPriority(rtk_uint32 priority) +{ + if(priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + return rtl8367c_setAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, priority); +} +/* Function Name: + * rtl8367c_getAsicUnknownMulticastTrapPriority + * Description: + * Get trap priority of unknown multicast frame + * Input: + * pPriority - priority (0~7) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicUnknownMulticastTrapPriority(rtk_uint32 *pPriority) +{ + return rtl8367c_getAsicRegBits(RTL8367C_QOS_TRAP_PRIORITY_CTRL0_REG, RTL8367C_UNKNOWN_MC_PRIORTY_MASK, pPriority); +} diff --git a/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c new file mode 100644 index 000000000000..1e283e7432c0 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/rtl8367c_asicdrv_vlan.c @@ -0,0 +1,1505 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTL8367C switch high-level API for RTL8367C + * Feature : VLAN related functions + * + */ +#include + +#include + +#if defined(CONFIG_RTL8367C_ASICDRV_TEST) +rtl8367c_user_vlan4kentry Rtl8370sVirtualVlanTable[RTL8367C_VIDMAX + 1]; +#endif + +static void _rtl8367c_VlanMCStUser2Smi(rtl8367c_vlanconfiguser *pVlanCg, rtk_uint16 *pSmiVlanCfg) +{ + pSmiVlanCfg[0] |= pVlanCg->mbr & 0x07FF; + + pSmiVlanCfg[1] |= pVlanCg->fid_msti & 0x000F; + + pSmiVlanCfg[2] |= pVlanCg->vbpen & 0x0001; + pSmiVlanCfg[2] |= (pVlanCg->vbpri & 0x0007) << 1; + pSmiVlanCfg[2] |= (pVlanCg->envlanpol & 0x0001) << 4; + pSmiVlanCfg[2] |= (pVlanCg->meteridx & 0x003F) << 5; + + pSmiVlanCfg[3] |= pVlanCg->evid & 0x1FFF; +} + +static void _rtl8367c_VlanMCStSmi2User(rtk_uint16 *pSmiVlanCfg, rtl8367c_vlanconfiguser *pVlanCg) +{ + pVlanCg->mbr = pSmiVlanCfg[0] & 0x07FF; + pVlanCg->fid_msti = pSmiVlanCfg[1] & 0x000F; + pVlanCg->meteridx = (pSmiVlanCfg[2] >> 5) & 0x003F; + pVlanCg->envlanpol = (pSmiVlanCfg[2] >> 4) & 0x0001; + pVlanCg->vbpri = (pSmiVlanCfg[2] >> 1) & 0x0007; + pVlanCg->vbpen = pSmiVlanCfg[2] & 0x0001; + pVlanCg->evid = pSmiVlanCfg[3] & 0x1FFF; +} + +static void _rtl8367c_Vlan4kStUser2Smi(rtl8367c_user_vlan4kentry *pUserVlan4kEntry, rtk_uint16 *pSmiVlan4kEntry) +{ + pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->mbr & 0x00FF); + pSmiVlan4kEntry[0] |= (pUserVlan4kEntry->untag & 0x00FF) << 8; + + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->fid_msti & 0x000F); + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpen & 0x0001) << 4; + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->vbpri & 0x0007) << 5; + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->envlanpol & 0x0001) << 8; + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->meteridx & 0x001F) << 9; + pSmiVlan4kEntry[1] |= (pUserVlan4kEntry->ivl_svl & 0x0001) << 14; + + pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->mbr & 0x0700) >> 8); + pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->untag & 0x0700) >> 8) << 3; + pSmiVlan4kEntry[2] |= ((pUserVlan4kEntry->meteridx & 0x0020) >> 5) << 6; +} + + +static void _rtl8367c_Vlan4kStSmi2User(rtk_uint16 *pSmiVlan4kEntry, rtl8367c_user_vlan4kentry *pUserVlan4kEntry) +{ + pUserVlan4kEntry->mbr = (pSmiVlan4kEntry[0] & 0x00FF) | ((pSmiVlan4kEntry[2] & 0x0007) << 8); + pUserVlan4kEntry->untag = ((pSmiVlan4kEntry[0] & 0xFF00) >> 8) | (((pSmiVlan4kEntry[2] & 0x0038) >> 3) << 8); + pUserVlan4kEntry->fid_msti = pSmiVlan4kEntry[1] & 0x000F; + pUserVlan4kEntry->vbpen = (pSmiVlan4kEntry[1] & 0x0010) >> 4; + pUserVlan4kEntry->vbpri = (pSmiVlan4kEntry[1] & 0x00E0) >> 5; + pUserVlan4kEntry->envlanpol = (pSmiVlan4kEntry[1] & 0x0100) >> 8; + pUserVlan4kEntry->meteridx = ((pSmiVlan4kEntry[1] & 0x3E00) >> 9) | (((pSmiVlan4kEntry[2] & 0x0040) >> 6) << 5); + pUserVlan4kEntry->ivl_svl = (pSmiVlan4kEntry[1] & 0x4000) >> 14; +} + +/* Function Name: + * rtl8367c_setAsicVlanMemberConfig + * Description: + * Set 32 VLAN member configurations + * Input: + * index - VLAN member configuration index (0~31) + * pVlanCg - VLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_L2_FID - Invalid FID + * RT_ERR_PORT_MASK - Invalid portmask + * RT_ERR_FILTER_METER_ID - Invalid meter + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg) +{ + ret_t retVal; + rtk_uint32 regAddr; + rtk_uint32 regData; + rtk_uint16 *tableAddr; + rtk_uint32 page_idx; + rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN]; + + /* Error Checking */ + if(index > RTL8367C_CVIDXMAX) + return RT_ERR_VLAN_ENTRY_NOT_FOUND; + + if(pVlanCg->evid > RTL8367C_EVIDMAX) + return RT_ERR_INPUT; + + + if(pVlanCg->mbr > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + if(pVlanCg->fid_msti > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if(pVlanCg->meteridx > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(pVlanCg->vbpri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN); + _rtl8367c_VlanMCStUser2Smi(pVlanCg, smi_vlancfg); + tableAddr = smi_vlancfg; + + for(page_idx = 0; page_idx < 4; page_idx++) /* 4 pages per VLAN Member Config */ + { + regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx; + regData = *tableAddr; + + retVal = rtl8367c_setAsicReg(regAddr, regData); + if(retVal != RT_ERR_OK) + return retVal; + + tableAddr++; + } + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicVlanMemberConfig + * Description: + * Get 32 VLAN member configurations + * Input: + * index - VLAN member configuration index (0~31) + * pVlanCg - VLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanMemberConfig(rtk_uint32 index, rtl8367c_vlanconfiguser *pVlanCg) +{ + ret_t retVal; + rtk_uint32 page_idx; + rtk_uint32 regAddr; + rtk_uint32 regData; + rtk_uint16 *tableAddr; + rtk_uint16 smi_vlancfg[RTL8367C_VLAN_MBRCFG_LEN]; + + if(index > RTL8367C_CVIDXMAX) + return RT_ERR_VLAN_ENTRY_NOT_FOUND; + + memset(smi_vlancfg, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_MBRCFG_LEN); + tableAddr = smi_vlancfg; + + for(page_idx = 0; page_idx < 4; page_idx++) /* 4 pages per VLAN Member Config */ + { + regAddr = RTL8367C_VLAN_MEMBER_CONFIGURATION_BASE + (index * 4) + page_idx; + + retVal = rtl8367c_getAsicReg(regAddr, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *tableAddr = (rtk_uint16)regData; + tableAddr++; + } + + _rtl8367c_VlanMCStSmi2User(smi_vlancfg, pVlanCg); + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlan4kEntry + * Description: + * Set VID mapped entry to 4K VLAN table + * Input: + * pVlan4kEntry - 4K VLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_L2_FID - Invalid FID + * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) + * RT_ERR_PORT_MASK - Invalid portmask + * RT_ERR_FILTER_METER_ID - Invalid meter + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * Note: + * None + */ +ret_t rtl8367c_setAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ) +{ + rtk_uint16 vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN]; + rtk_uint32 page_idx; + rtk_uint16 *tableAddr; + ret_t retVal; + rtk_uint32 regData; + + if(pVlan4kEntry->vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if(pVlan4kEntry->mbr > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + if(pVlan4kEntry->untag > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + if(pVlan4kEntry->fid_msti > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if(pVlan4kEntry->meteridx > RTL8367C_METERMAX) + return RT_ERR_FILTER_METER_ID; + + if(pVlan4kEntry->vbpri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + memset(vlan_4k_entry, 0x00, sizeof(rtk_uint16) * RTL8367C_VLAN_4KTABLE_LEN); + _rtl8367c_Vlan4kStUser2Smi(pVlan4kEntry, vlan_4k_entry); + + /* Prepare Data */ + tableAddr = vlan_4k_entry; + for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++) + { + regData = *tableAddr; + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_WRDATA_BASE + page_idx, regData); + if(retVal != RT_ERR_OK) + return retVal; + + tableAddr++; + } + + /* Write Address (VLAN_ID) */ + regData = pVlan4kEntry->vid; + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Write Command */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK,RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_WRITE,TB_TARGET_CVLAN)); + if(retVal != RT_ERR_OK) + return retVal; + +#if defined(CONFIG_RTL8367C_ASICDRV_TEST) + memcpy(&Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], pVlan4kEntry, sizeof(rtl8367c_user_vlan4kentry)); +#endif + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicVlan4kEntry + * Description: + * Get VID mapped entry to 4K VLAN table + * Input: + * pVlan4kEntry - 4K VLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VID parameter (0~4095) + * RT_ERR_BUSYWAIT_TIMEOUT - LUT is busy at retrieving + * Note: + * None + */ +ret_t rtl8367c_getAsicVlan4kEntry(rtl8367c_user_vlan4kentry *pVlan4kEntry ) +{ + rtk_uint16 vlan_4k_entry[RTL8367C_VLAN_4KTABLE_LEN]; + rtk_uint32 page_idx; + rtk_uint16 *tableAddr; + ret_t retVal; + rtk_uint32 regData; + rtk_uint32 busyCounter; + + if(pVlan4kEntry->vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + /* Polling status */ + busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO; + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if(regData == 0) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + /* Write Address (VLAN_ID) */ + regData = pVlan4kEntry->vid; + retVal = rtl8367c_setAsicReg(RTL8367C_TABLE_ACCESS_ADDR_REG, regData); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Command */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_TABLE_ACCESS_CTRL_REG, RTL8367C_TABLE_TYPE_MASK | RTL8367C_COMMAND_TYPE_MASK, RTL8367C_TABLE_ACCESS_REG_DATA(TB_OP_READ,TB_TARGET_CVLAN)); + if(retVal != RT_ERR_OK) + return retVal; + + /* Polling status */ + busyCounter = RTL8367C_VLAN_BUSY_CHECK_NO; + while(busyCounter) + { + retVal = rtl8367c_getAsicRegBit(RTL8367C_TABLE_ACCESS_STATUS_REG, RTL8367C_TABLE_LUT_ADDR_BUSY_FLAG_OFFSET,®Data); + if(retVal != RT_ERR_OK) + return retVal; + + if(regData == 0) + break; + + busyCounter --; + if(busyCounter == 0) + return RT_ERR_BUSYWAIT_TIMEOUT; + } + + /* Read VLAN data from register */ + tableAddr = vlan_4k_entry; + for(page_idx = 0; page_idx < RTL8367C_VLAN_4KTABLE_LEN; page_idx++) + { + retVal = rtl8367c_getAsicReg(RTL8367C_TABLE_ACCESS_RDDATA_BASE + page_idx, ®Data); + if(retVal != RT_ERR_OK) + return retVal; + + *tableAddr = regData; + tableAddr++; + } + + _rtl8367c_Vlan4kStSmi2User(vlan_4k_entry, pVlan4kEntry); + +#if defined(CONFIG_RTL8367C_ASICDRV_TEST) + memcpy(pVlan4kEntry, &Rtl8370sVirtualVlanTable[pVlan4kEntry->vid], sizeof(rtl8367c_user_vlan4kentry)); +#endif + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanAccpetFrameType + * Description: + * Set per-port acceptable frame type + * Input: + * port - Physical port number (0~10) + * frameType - The acceptable frame type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype frameType) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(frameType >= FRAME_TYPE_MAX_BOUND) + return RT_ERR_VLAN_ACCEPT_FRAME_TYPE; + + return rtl8367c_setAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), frameType); +} +/* Function Name: + * rtl8367c_getAsicVlanAccpetFrameType + * Description: + * Get per-port acceptable frame type + * Input: + * port - Physical port number (0~10) + * pFrameType - The acceptable frame type + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanAccpetFrameType(rtk_uint32 port, rtl8367c_accframetype *pFrameType) +{ + rtk_uint32 regData; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_ACCEPT_FRAME_TYPE_REG(port), RTL8367C_VLAN_ACCEPT_FRAME_TYPE_MASK(port), ®Data)) != RT_ERR_OK) + return retVal; + + *pFrameType = (rtl8367c_accframetype)regData; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanIngressFilter + * Description: + * Set VLAN Ingress Filter + * Input: + * port - Physical port number (0~10) + * enabled - Enable or disable Ingress filter + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, enabled); +} +/* Function Name: + * rtl8367c_getAsicVlanIngressFilter + * Description: + * Get VLAN Ingress Filter + * Input: + * port - Physical port number (0~10) + * pEnable - Enable or disable Ingress filter + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanIngressFilter(rtk_uint32 port, rtk_uint32 *pEnable) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_VLAN_INGRESS_REG, port, pEnable); +} +/* Function Name: + * rtl8367c_setAsicVlanEgressTagMode + * Description: + * Set CVLAN egress tag mode + * Input: + * port - Physical port number (0~10) + * tagMode - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode tagMode) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(tagMode >= EG_TAG_MODE_END) + return RT_ERR_INPUT; + + return rtl8367c_setAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, tagMode); +} +/* Function Name: + * rtl8367c_getAsicVlanEgressTagMode + * Description: + * Get CVLAN egress tag mode + * Input: + * port - Physical port number (0~10) + * pTagMode - The egress tag mode. Including Original mode, Keep tag mode and Priority tag mode + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanEgressTagMode(rtk_uint32 port, rtl8367c_egtagmode *pTagMode) +{ + rtk_uint32 regData; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if((retVal = rtl8367c_getAsicRegBits(RTL8367C_PORT_MISC_CFG_REG(port), RTL8367C_VLAN_EGRESS_MDOE_MASK, ®Data)) != RT_ERR_OK) + return retVal; + + *pTagMode = (rtl8367c_egtagmode)regData; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanPortBasedVID + * Description: + * Set port based VID which is indexed to 32 VLAN member configurations + * Input: + * port - Physical port number (0~10) + * index - Index to VLAN member configuration + * pri - 1Q Port based VLAN priority + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 index, rtk_uint32 pri) +{ + rtk_uint32 regAddr, bit_mask; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index > RTL8367C_CVIDXMAX) + return RT_ERR_VLAN_ENTRY_NOT_FOUND; + + if(pri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port); + bit_mask = RTL8367C_PORT_VIDX_MASK(port); + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, index); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port); + bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port); + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, pri); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicVlanPortBasedVID + * Description: + * Get port based VID which is indexed to 32 VLAN member configurations + * Input: + * port - Physical port number (0~10) + * pIndex - Index to VLAN member configuration + * pPri - 1Q Port based VLAN priority + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanPortBasedVID(rtk_uint32 port, rtk_uint32 *pIndex, rtk_uint32 *pPri) +{ + rtk_uint32 regAddr,bit_mask; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + regAddr = RTL8367C_VLAN_PVID_CTRL_REG(port); + bit_mask = RTL8367C_PORT_VIDX_MASK(port); + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pIndex); + if(retVal != RT_ERR_OK) + return retVal; + + regAddr = RTL8367C_VLAN_PORTBASED_PRIORITY_REG(port); + bit_mask = RTL8367C_VLAN_PORTBASED_PRIORITY_MASK(port); + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, pPri); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanProtocolBasedGroupData + * Description: + * Set protocol and port based group database + * Input: + * index - Index to VLAN member configuration + * pPbCfg - Protocol and port based group database entry + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg) +{ + rtk_uint32 frameType; + rtk_uint32 etherType; + ret_t retVal; + + /* Error Checking */ + if(index > RTL8367C_PROTOVLAN_GIDX_MAX) + return RT_ERR_VLAN_PROTO_AND_PORT; + + if(pPbCfg->frameType >= PPVLAN_FRAME_TYPE_END ) + return RT_ERR_INPUT; + + frameType = pPbCfg->frameType; + etherType = pPbCfg->etherType; + + /* Frame type */ + retVal = rtl8367c_setAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, frameType); + if(retVal != RT_ERR_OK) + return retVal; + + /* Ether type */ + retVal = rtl8367c_setAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), etherType); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicVlanProtocolBasedGroupData + * Description: + * Get protocol and port based group database + * Input: + * index - Index to VLAN member configuration + * pPbCfg - Protocol and port based group database entry + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanProtocolBasedGroupData(rtk_uint32 index, rtl8367c_protocolgdatacfg *pPbCfg) +{ + rtk_uint32 frameType; + rtk_uint32 etherType; + ret_t retVal; + + /* Error Checking */ + if(index > RTL8367C_PROTOVLAN_GIDX_MAX) + return RT_ERR_VLAN_PROTO_AND_PORT; + + /* Read Frame type */ + retVal = rtl8367c_getAsicRegBits(RTL8367C_VLAN_PPB_FRAMETYPE_REG(index), RTL8367C_VLAN_PPB_FRAMETYPE_MASK, &frameType); + if(retVal != RT_ERR_OK) + return retVal; + + /* Read Ether type */ + retVal = rtl8367c_getAsicReg(RTL8367C_VLAN_PPB_ETHERTYPR_REG(index), ðerType); + if(retVal != RT_ERR_OK) + return retVal; + + + pPbCfg->frameType = frameType; + pPbCfg->etherType = etherType; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanPortAndProtocolBased + * Description: + * Set protocol and port based VLAN configuration + * Input: + * port - Physical port number (0~10) + * index - Index of protocol and port based database index + * pPpbCfg - Protocol and port based VLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_QOS_INT_PRIORITY - Invalid priority + * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index + * RT_ERR_VLAN_ENTRY_NOT_FOUND - Invalid VLAN member configuration index + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg) +{ + rtk_uint32 reg_addr, bit_mask, bit_value; + ret_t retVal; + + /* Error Checking */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index > RTL8367C_PROTOVLAN_GIDX_MAX) + return RT_ERR_VLAN_PROTO_AND_PORT; + + if( (pPpbCfg->valid != FALSE) && (pPpbCfg->valid != TRUE) ) + return RT_ERR_INPUT; + + if(pPpbCfg->vlan_idx > RTL8367C_CVIDXMAX) + return RT_ERR_VLAN_ENTRY_NOT_FOUND; + + if(pPpbCfg->priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + /* Valid bit */ + reg_addr = RTL8367C_VLAN_PPB_VALID_REG(index); + bit_mask = 0x0001 << port; + bit_value = ((TRUE == pPpbCfg->valid) ? 0x1 : 0x0); + retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + /* Calculate the actual register address for CVLAN index*/ + if(port < 8) + { + reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port); + bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port); + } + else if(port == 8) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK; + } + else if(port == 9) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK; + } + else if(port == 10) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK; + } + + bit_value = pPpbCfg->vlan_idx; + retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + /* write priority */ + reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port, index); + bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port); + bit_value = pPpbCfg->priority; + retVal = rtl8367c_setAsicRegBits(reg_addr, bit_mask, bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_getAsicVlanPortAndProtocolBased + * Description: + * Get protocol and port based VLAN configuration + * Input: + * port - Physical port number (0~7) + * index - Index of protocol and port based database index + * pPpbCfg - Protocol and port based VLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_VLAN_PROTO_AND_PORT - Invalid protocol base group database index + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanPortAndProtocolBased(rtk_uint32 port, rtk_uint32 index, rtl8367c_protocolvlancfg *pPpbCfg) +{ + rtk_uint32 reg_addr, bit_mask, bit_value; + ret_t retVal; + + /* Error Checking */ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(index > RTL8367C_PROTOVLAN_GIDX_MAX) + return RT_ERR_VLAN_PROTO_AND_PORT; + + if(pPpbCfg == NULL) + return RT_ERR_INPUT; + + /* Valid bit */ + reg_addr = RTL8367C_VLAN_PPB_VALID_REG(index); + bit_mask = 0x0001 << port; + retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + pPpbCfg->valid = bit_value; + + /* CVLAN index */ + if(port < 8) + { + reg_addr = RTL8367C_VLAN_PPB_CTRL_REG(index, port); + bit_mask = RTL8367C_VLAN_PPB_CTRL_MASK(port); + } + else if(port == 8) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT8_INDEX_MASK; + } + else if(port == 9) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT9_INDEX_MASK; + } + else if(port == 10) + { + reg_addr = RTL8367C_REG_VLAN_PPB0_CTRL4; + bit_mask = RTL8367C_VLAN_PPB0_CTRL4_PORT10_INDEX_MASK; + } + + retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + pPpbCfg->vlan_idx = bit_value; + + + /* priority */ + reg_addr = RTL8367C_VLAN_PPB_PRIORITY_ITEM_REG(port,index); + bit_mask = RTL8367C_VLAN_PPB_PRIORITY_ITEM_MASK(port); + retVal = rtl8367c_getAsicRegBits(reg_addr, bit_mask, &bit_value); + if(retVal != RT_ERR_OK) + return retVal; + + pPpbCfg->priority = bit_value; + return RT_ERR_OK; +} +/* Function Name: + * rtl8367c_setAsicVlanFilter + * Description: + * Set enable CVLAN filtering function + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanFilter(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicVlanFilter + * Description: + * Get enable CVLAN filtering function + * Input: + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanFilter(rtk_uint32* pEnabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_CTRL, RTL8367C_VLAN_CTRL_OFFSET, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicVlanUntagDscpPriorityEn + * Description: + * Set enable Dscp to untag 1Q priority + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanUntagDscpPriorityEn(rtk_uint32 enabled) +{ + return rtl8367c_setAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_getAsicVlanUntagDscpPriorityEn + * Description: + * Get enable Dscp to untag 1Q priority + * Input: + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanUntagDscpPriorityEn(rtk_uint32* enabled) +{ + return rtl8367c_getAsicRegBit(RTL8367C_REG_UNTAG_DSCP_PRI_CFG, RTL8367C_UNTAG_DSCP_PRI_CFG_OFFSET, enabled); +} +/* Function Name: + * rtl8367c_setAsicPortBasedFid + * Description: + * Set port based FID + * Input: + * port - Physical port number (0~10) + * fid - Port based fid + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid FID + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortBasedFid(rtk_uint32 port, rtk_uint32 fid) +{ + rtk_uint32 reg_addr; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if(port < 8) + return rtl8367c_setAsicReg(RTL8367C_PORT_PBFID_REG(port),fid); + else { + reg_addr = RTL8367C_REG_PORT8_PBFID + port-8; + return rtl8367c_setAsicReg(reg_addr, fid); + } + +} +/* Function Name: + * rtl8367c_getAsicPortBasedFid + * Description: + * Get port based FID + * Input: + * port - Physical port number (0~7) + * pFid - Port based fid + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortBasedFid(rtk_uint32 port, rtk_uint32* pFid) +{ + rtk_uint32 reg_addr; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8) + return rtl8367c_getAsicReg(RTL8367C_PORT_PBFID_REG(port), pFid); + else{ + reg_addr = RTL8367C_REG_PORT8_PBFID + port-8; + return rtl8367c_getAsicReg(reg_addr, pFid); + } +} +/* Function Name: + * rtl8367c_setAsicPortBasedFidEn + * Description: + * Set port based FID selection enable + * Input: + * port - Physical port number (0~10) + * enabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32 enabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_setAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, enabled); +} +/* Function Name: + * rtl8367c_getAsicPortBasedFidEn + * Description: + * Get port based FID selection enable + * Input: + * port - Physical port number (0~10) + * pEnabled - 1: enabled, 0: disabled + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicPortBasedFidEn(rtk_uint32 port, rtk_uint32* pEnabled) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBit(RTL8367C_REG_PORT_PBFIDEN,port, pEnabled); +} +/* Function Name: + * rtl8367c_setAsicSpanningTreeStatus + * Description: + * Set spanning tree state per each port + * Input: + * port - Physical port number (0~10) + * msti - Multiple spanning tree instance + * state - Spanning tree state for msti + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_MSTI - Invalid msti parameter + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_MSTP_STATE - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32 state) +{ + rtk_uint32 reg_addr,bits_msk; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(msti > RTL8367C_MSTIMAX) + return RT_ERR_MSTI; + + if(state > STPST_FORWARDING) + return RT_ERR_MSTP_STATE; + + if(port < 8) + return rtl8367c_setAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port),state); + else{ + reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port); + switch(port){ + case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break; + case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break; + case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break; + } + return rtl8367c_setAsicRegBits(reg_addr, bits_msk,state); + } +} +/* Function Name: + * rtl8367c_getAsicSpanningTreeStatus + * Description: + * Set spanning tree state per each port + * Input: + * port - Physical port number (0~10) + * msti - Multiple spanning tree instance + * pState - Spanning tree state for msti + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_MSTI - Invalid msti parameter + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicSpanningTreeStatus(rtk_uint32 port, rtk_uint32 msti, rtk_uint32* pState) +{ + rtk_uint32 reg_addr,bits_msk; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(msti > RTL8367C_MSTIMAX) + return RT_ERR_MSTI; + + if(port < 8) + return rtl8367c_getAsicRegBits(RTL8367C_VLAN_MSTI_REG(msti,port), RTL8367C_VLAN_MSTI_MASK(port), pState); + else{ + reg_addr = RTL8367C_VLAN_MSTI_REG(msti,port); + switch(port){ + case 8: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT8_STATE_MASK;break; + case 9: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT9_STATE_MASK;break; + case 10: bits_msk = RTL8367C_VLAN_MSTI0_CTRL1_PORT10_STATE_MASK;break; + } + return rtl8367c_getAsicRegBits(reg_addr, bits_msk, pState); + } + +} + +/* Function Name: + * rtl8367c_setAsicVlanTransparent + * Description: + * Set VLAN transparent + * Input: + * port - Physical port number (0~10) + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanTransparent(rtk_uint32 port, rtk_uint32 portmask) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + return rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, portmask); +} + +/* Function Name: + * rtl8367c_getAsicVlanTransparent + * Description: + * Get VLAN transparent + * Input: + * port - Physical port number (0~10) + * Output: + * pPortmask - Ingress port mask + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanTransparent(rtk_uint32 port, rtk_uint32 *pPortmask) +{ + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + return rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_TRANS_CTRL0 + port, RTL8367C_VLAN_EGRESS_TRANS_CTRL0_MASK, pPortmask); +} + +/* Function Name: + * rtl8367c_setAsicVlanEgressKeep + * Description: + * Set per egress port VLAN keep mode + * Input: + * port - Physical port number (0~10) + * portmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_MASK - Invalid portmask + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_setAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32 portmask) +{ + rtk_uint32 regAddr, bit_mask; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(portmask > RTL8367C_PORTMASK) + return RT_ERR_PORT_MASK; + + if(port < 8){ + retVal = rtl8367c_setAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1); + bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK; + bit_mask <<= (port&1)*3; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); + if(retVal != RT_ERR_OK) + return retVal; + } + else{ + switch(port){ + case 8: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; + bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; + bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); + if(retVal != RT_ERR_OK) + return retVal; + break; + + case 9: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; + bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; + bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); + if(retVal != RT_ERR_OK) + return retVal; + break; + + case 10: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5; + bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, portmask & 0xff); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT; + bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK; + retVal = rtl8367c_setAsicRegBits(regAddr, bit_mask, (portmask>>8)&0x7); + if(retVal != RT_ERR_OK) + return retVal; + break; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getAsicVlanEgressKeep + * Description: + * Get per egress port VLAN keep mode + * Input: + * port - Physical port number (0~7) + * pPortmask - portmask(0~0xFF) + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * Note: + * None + */ +ret_t rtl8367c_getAsicVlanEgressKeep(rtk_uint32 port, rtk_uint32* pPortmask) +{ + rtk_uint32 regAddr, bit_mask, regval_l, regval_h; + ret_t retVal; + + if(port > RTL8367C_PORTIDMAX) + return RT_ERR_PORT_ID; + + if(port < 8){ + retVal = rtl8367c_getAsicRegBits(RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0 + (port>>1),RTL8367C_PORT0_VLAN_KEEP_MASK_MASK<<((port&1)*8),®val_l); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL0_EXT + (port>>1); + bit_mask = RTL8367C_PORT0_VLAN_KEEP_MASK_EXT_MASK; + bit_mask <<= (port&1)*3; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); + if(retVal != RT_ERR_OK) + return retVal; + *pPortmask = (regval_h << 8) | regval_l; + } + else{ + switch(port){ + case 8: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; + bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; + bit_mask = RTL8367C_PORT8_VLAN_KEEP_MASK_EXT_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); + if(retVal != RT_ERR_OK) + return retVal; + + *pPortmask = (regval_h << 8) | regval_l; + break; + + case 9: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4; + bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL4_EXT; + bit_mask = RTL8367C_PORT9_VLAN_KEEP_MASK_EXT_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); + if(retVal != RT_ERR_OK) + return retVal; + + *pPortmask = (regval_h << 8) | regval_l; + break; + + case 10: + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5; + bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_l); + if(retVal != RT_ERR_OK) + return retVal; + regAddr = RTL8367C_REG_VLAN_EGRESS_KEEP_CTRL5_EXT; + bit_mask = RTL8367C_VLAN_EGRESS_KEEP_CTRL5_EXT_MASK; + retVal = rtl8367c_getAsicRegBits(regAddr, bit_mask, ®val_h); + if(retVal != RT_ERR_OK) + return retVal; + + *pPortmask = (regval_h << 8) | regval_l; + break; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_setReservedVidAction + * Description: + * Set reserved VID action + * Input: + * vid0Action - VID 0 action + * vid4095Action - VID 4095 action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error input + * Note: + * None + */ +ret_t rtl8367c_setReservedVidAction(rtk_uint32 vid0Action, rtk_uint32 vid4095Action) +{ + ret_t retVal; + + if(vid0Action >= RES_VID_ACT_END) + return RT_ERR_INPUT; + + if(vid4095Action >= RES_VID_ACT_END) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, vid0Action)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, vid4095Action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getReservedVidAction + * Description: + * Get reserved VID action + * Input: + * pVid0Action - VID 0 action + * pVid4095Action - VID 4095 action + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * None + */ +ret_t rtl8367c_getReservedVidAction(rtk_uint32 *pVid0Action, rtk_uint32 *pVid4095Action) +{ + ret_t retVal; + + if(pVid0Action == NULL) + return RT_ERR_NULL_POINTER; + + if(pVid4095Action == NULL) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID0_TYPE_OFFSET, pVid0Action)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_VID4095_TYPE_OFFSET, pVid4095Action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtl8367c_setRealKeepRemarkEn + * Description: + * Set Real Keep Remark + * Input: + * enabled - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet + * Output: + * None + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error input + * Note: + * None + */ +ret_t rtl8367c_setRealKeepRemarkEn(rtk_uint32 enabled) +{ + ret_t retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, enabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_getRealKeepRemarkEn + * Description: + * Get Real Keep Remark + * Input: + * None + * Output: + * pEnabled - 0: 1P remarking is forbidden at real keep packet, 1: 1P remarking is enabled at real keep packet + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error input + * Note: + * None + */ +ret_t rtl8367c_getRealKeepRemarkEn(rtk_uint32 *pEnabled) +{ + ret_t retVal; + + if((retVal = rtl8367c_getAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL, RTL8367C_VLAN_1P_REMARK_BYPASS_REALKEEP_OFFSET, pEnabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtl8367c_resetVlan + * Description: + * Reset VLAN table + * Input: + * None. + * Output: + * None. + * Return: + * RT_ERR_OK - Success + * RT_ERR_SMI - SMI access error + * Note: + * None + */ +ret_t rtl8367c_resetVlan(void) +{ + ret_t retVal; + + if((retVal = rtl8367c_setAsicRegBit(RTL8367C_REG_VLAN_EXT_CTRL2, RTL8367C_VLAN_EXT_CTRL2_OFFSET, 1)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/smi.c b/drivers/net/phy/rtk/rtl8367c/smi.c new file mode 100644 index 000000000000..e707e4b9c583 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/smi.c @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * Purpose : RTL8367C switch low-level function for access register + * Feature : SMI related functions + * + */ + + +#include +#include +#include + +#include "rtk_error.h" + + +#if defined(MDC_MDIO_OPERATION) +/*******************************************************************************/ +/* MDC/MDIO porting */ +/*******************************************************************************/ +/* define the PHY ID currently used */ +/* carlos */ +#if 0 +#define MDC_MDIO_PHY_ID 0 /* PHY ID 0 or 29 */ +#else +#define MDC_MDIO_PHY_ID 29 /* PHY ID 0 or 29 */ +#endif + +/* MDC/MDIO, redefine/implement the following Macro */ /*carlos*/ +#if 0 +#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) +#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) +#else +#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) mii_mgr_write(phyID, regID, data) +#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) mii_mgr_read(phyID, regID, pData) +#endif + + + + + +#elif defined(SPI_OPERATION) +/*******************************************************************************/ +/* SPI porting */ +/*******************************************************************************/ +/* SPI, redefine/implement the following Macro */ +#define SPI_WRITE(data, length) +#define SPI_READ(pData, length) + + + + + +#else +/*******************************************************************************/ +/* I2C porting */ +/*******************************************************************************/ +/* Define the GPIO ID for SCK & SDA */ +rtk_uint32 smi_SCK = 1; /* GPIO used for SMI Clock Generation */ +rtk_uint32 smi_SDA = 2; /* GPIO used for SMI Data signal */ + +/* I2C, redefine/implement the following Macro */ +#define GPIO_DIRECTION_SET(gpioID, direction) +#define GPIO_DATA_SET(gpioID, data) +#define GPIO_DATA_GET(gpioID, pData) + + + + + +#endif + +static void rtlglue_drvMutexLock(void) +{ + /* It is empty currently. Implement this function if Lock/Unlock function is needed */ + return; +} + +static void rtlglue_drvMutexUnlock(void) +{ + /* It is empty currently. Implement this function if Lock/Unlock function is needed */ + return; +} + + + +#if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) + /* No local function in MDC/MDIO & SPI mode */ +#else +static void _smi_start(void) +{ + + /* change GPIO pin to Output only */ + GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_OUT); + GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); + + /* Initial state: SCK: 0, SDA: 1 */ + GPIO_DATA_SET(smi_SCK, 0); + GPIO_DATA_SET(smi_SDA, 1); + CLK_DURATION(DELAY); + + /* CLK 1: 0 -> 1, 1 -> 0 */ + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 0); + CLK_DURATION(DELAY); + + /* CLK 2: */ + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SDA, 0); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 0); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SDA, 1); + +} + + + +static void _smi_writeBit(rtk_uint16 signal, rtk_uint32 bitLen) +{ + for( ; bitLen > 0; bitLen--) + { + CLK_DURATION(DELAY); + + /* prepare data */ + if ( signal & (1<<(bitLen-1)) ) + { + GPIO_DATA_SET(smi_SDA, 1); + } + else + { + GPIO_DATA_SET(smi_SDA, 0); + } + CLK_DURATION(DELAY); + + /* clocking */ + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 0); + } +} + + + +static void _smi_readBit(rtk_uint32 bitLen, rtk_uint32 *rData) +{ + rtk_uint32 u = 0; + + /* change GPIO pin to Input only */ + GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); + + for (*rData = 0; bitLen > 0; bitLen--) + { + CLK_DURATION(DELAY); + + /* clocking */ + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_GET(smi_SDA, &u); + GPIO_DATA_SET(smi_SCK, 0); + + *rData |= (u << (bitLen - 1)); + } + + /* change GPIO pin to Output only */ + GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); +} + + + +static void _smi_stop(void) +{ + + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SDA, 0); + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SDA, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 1); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 0); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 1); + + /* add a click */ + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 0); + CLK_DURATION(DELAY); + GPIO_DATA_SET(smi_SCK, 1); + + + /* change GPIO pin to Input only */ + GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); + GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_IN); +} + +#endif /* End of #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) */ + +rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData) +{ +#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) + rtk_uint32 rawData=0, ACK; + rtk_uint8 con; + rtk_uint32 ret = RT_ERR_OK; +#endif + + if(mAddrs > 0xFFFF) + return RT_ERR_INPUT; + + if(rData == NULL) + return RT_ERR_NULL_POINTER; + +#if defined(MDC_MDIO_OPERATION) + + /* Lock */ + rtlglue_drvMutexLock(); + + /* Write address control code to register 31 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write address to register 23 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); + + /* Write read control code to register 21 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); + + /* Read data from register 25 */ + MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData); + + /* Unlock */ + rtlglue_drvMutexUnlock(); + + return RT_ERR_OK; + +#elif defined(SPI_OPERATION) + + /* Lock */ + rtlglue_drvMutexLock(); + + /* Write 8 bits READ OP_CODE */ + SPI_WRITE(SPI_READ_OP, SPI_READ_OP_LEN); + + /* Write 16 bits register address */ + SPI_WRITE(mAddrs, SPI_REG_LEN); + + /* Read 16 bits data */ + SPI_READ(rData, SPI_DATA_LEN); + + /* Unlock */ + rtlglue_drvMutexUnlock(); + + return RT_ERR_OK; + +#else + + /*Disable CPU interrupt to ensure that the SMI operation is atomic. + The API is based on RTL865X, rewrite the API if porting to other platform.*/ + rtlglue_drvMutexLock(); + + _smi_start(); /* Start SMI */ + + _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370 */ + + _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ + + _smi_writeBit(0x1, 1); /* 1: issue READ command */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for issuing READ command*/ + } while ((ACK != 0) && (con < ack_timer)); + + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ + } while ((ACK != 0) && (con < ack_timer)); + + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK by RTL8369 */ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_readBit(8, &rawData); /* Read DATA [7:0] */ + *rData = rawData&0xff; + + _smi_writeBit(0x00, 1); /* ACK by CPU */ + + _smi_readBit(8, &rawData); /* Read DATA [15: 8] */ + + _smi_writeBit(0x01, 1); /* ACK by CPU */ + *rData |= (rawData<<8); + + _smi_stop(); + + rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ + + return ret; +#endif /* end of #if defined(MDC_MDIO_OPERATION) */ +} + + + +rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData) +{ +#if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) + rtk_int8 con; + rtk_uint32 ACK; + rtk_uint32 ret = RT_ERR_OK; +#endif + + if(mAddrs > 0xFFFF) + return RT_ERR_INPUT; + + if(rData > 0xFFFF) + return RT_ERR_INPUT; + +#if defined(MDC_MDIO_OPERATION) + + /* Lock */ + rtlglue_drvMutexLock(); + + /* Write address control code to register 31 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write address to register 23 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); + + /* Write data to register 24 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_WRITE_REG, rData); + + /* Write data control code to register 21 */ + MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); + + /* Unlock */ + rtlglue_drvMutexUnlock(); + + return RT_ERR_OK; + +#elif defined(SPI_OPERATION) + + /* Lock */ + rtlglue_drvMutexLock(); + + /* Write 8 bits WRITE OP_CODE */ + SPI_WRITE(SPI_WRITE_OP, SPI_WRITE_OP_LEN); + + /* Write 16 bits register address */ + SPI_WRITE(mAddrs, SPI_REG_LEN); + + /* Write 16 bits data */ + SPI_WRITE(rData, SPI_DATA_LEN); + + /* Unlock */ + rtlglue_drvMutexUnlock(); + + return RT_ERR_OK; +#else + + /*Disable CPU interrupt to ensure that the SMI operation is atomic. + The API is based on RTL865X, rewrite the API if porting to other platform.*/ + rtlglue_drvMutexLock(); + + _smi_start(); /* Start SMI */ + + _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370*/ + + _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ + + _smi_writeBit(0x0, 1); /* 0: issue WRITE command */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for issuing WRITE command*/ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for setting reg_addr[15:8] */ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit(rData&0xff, 8); /* Write Data [7:0] out */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for writing data [7:0] */ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_writeBit(rData>>8, 8); /* Write Data [15:8] out */ + + con = 0; + do { + con++; + _smi_readBit(1, &ACK); /* ACK for writing data [15:8] */ + } while ((ACK != 0) && (con < ack_timer)); + if (ACK != 0) ret = RT_ERR_FAILED; + + _smi_stop(); + + rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ + + return ret; +#endif /* end of #if defined(MDC_MDIO_OPERATION) */ +} + diff --git a/drivers/net/phy/rtk/rtl8367c/stat.c b/drivers/net/phy/rtk/rtl8367c/stat.c new file mode 100644 index 000000000000..3fd028a296e4 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/stat.c @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in MIB module. + * + */ + +#include +#include +#include +#include + +#include +#include + +/* Function Name: + * rtk_stat_global_reset + * Description: + * Reset global MIB counter. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Reset MIB counter of ports. API will use global reset while port mask is all-ports. + */ +rtk_api_ret_t rtk_stat_global_reset(void) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_setAsicMIBsCounterReset(TRUE,FALSE, 0)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_port_reset + * Description: + * Reset per port MIB counter by port. + * Input: + * port - port id. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_stat_port_reset(rtk_port_t port) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,FALSE,1 << rtk_switch_port_L2P_get(port))) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_queueManage_reset + * Description: + * Reset queue manage MIB counter. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_stat_queueManage_reset(void) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_setAsicMIBsCounterReset(FALSE,TRUE,0)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_stat_global_get + * Description: + * Get global MIB counter + * Input: + * cntr_idx - global counter index. + * Output: + * pCntr - global counter value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get global MIB counter by index definition. + */ +rtk_api_ret_t rtk_stat_global_get(rtk_stat_global_type_t cntr_idx, rtk_stat_counter_t *pCntr) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pCntr) + return RT_ERR_NULL_POINTER; + + if (cntr_idx!=DOT1D_TP_LEARNED_ENTRY_DISCARDS_INDEX) + return RT_ERR_STAT_INVALID_GLOBAL_CNTR; + + if ((retVal = rtl8367c_getAsicMIBsCounter(0, (RTL8367C_MIBCOUNTER)cntr_idx, pCntr)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_global_getAll + * Description: + * Get all global MIB counter + * Input: + * None + * Output: + * pGlobal_cntrs - global counter structure. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get all global MIB counter by index definition. + */ +rtk_api_ret_t rtk_stat_global_getAll(rtk_stat_global_cntr_t *pGlobal_cntrs) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pGlobal_cntrs) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicMIBsCounter(0, dot1dTpLearnedEntryDiscards, &pGlobal_cntrs->dot1dTpLearnedEntryDiscards)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +#define MIB_NOT_SUPPORT (0xFFFF) +static rtk_api_ret_t _get_asic_mib_idx(rtk_stat_port_type_t cnt_idx, RTL8367C_MIBCOUNTER *pMib_idx) +{ + RTL8367C_MIBCOUNTER mib_asic_idx[STAT_PORT_CNTR_END]= + { + ifInOctets, /* STAT_IfInOctets */ + dot3StatsFCSErrors, /* STAT_Dot3StatsFCSErrors */ + dot3StatsSymbolErrors, /* STAT_Dot3StatsSymbolErrors */ + dot3InPauseFrames, /* STAT_Dot3InPauseFrames */ + dot3ControlInUnknownOpcodes, /* STAT_Dot3ControlInUnknownOpcodes */ + etherStatsFragments, /* STAT_EtherStatsFragments */ + etherStatsJabbers, /* STAT_EtherStatsJabbers */ + ifInUcastPkts, /* STAT_IfInUcastPkts */ + etherStatsDropEvents, /* STAT_EtherStatsDropEvents */ + etherStatsOctets, /* STAT_EtherStatsOctets */ + etherStatsUnderSizePkts, /* STAT_EtherStatsUnderSizePkts */ + etherOversizeStats, /* STAT_EtherOversizeStats */ + etherStatsPkts64Octets, /* STAT_EtherStatsPkts64Octets */ + etherStatsPkts65to127Octets, /* STAT_EtherStatsPkts65to127Octets */ + etherStatsPkts128to255Octets, /* STAT_EtherStatsPkts128to255Octets */ + etherStatsPkts256to511Octets, /* STAT_EtherStatsPkts256to511Octets */ + etherStatsPkts512to1023Octets, /* STAT_EtherStatsPkts512to1023Octets */ + etherStatsPkts1024to1518Octets, /* STAT_EtherStatsPkts1024to1518Octets */ + ifInMulticastPkts, /* STAT_EtherStatsMulticastPkts */ + ifInBroadcastPkts, /* STAT_EtherStatsBroadcastPkts */ + ifOutOctets, /* STAT_IfOutOctets */ + dot3StatsSingleCollisionFrames, /* STAT_Dot3StatsSingleCollisionFrames */ + dot3StatMultipleCollisionFrames,/* STAT_Dot3StatsMultipleCollisionFrames */ + dot3sDeferredTransmissions, /* STAT_Dot3StatsDeferredTransmissions */ + dot3StatsLateCollisions, /* STAT_Dot3StatsLateCollisions */ + etherStatsCollisions, /* STAT_EtherStatsCollisions */ + dot3StatsExcessiveCollisions, /* STAT_Dot3StatsExcessiveCollisions */ + dot3OutPauseFrames, /* STAT_Dot3OutPauseFrames */ + MIB_NOT_SUPPORT, /* STAT_Dot1dBasePortDelayExceededDiscards */ + dot1dTpPortInDiscards, /* STAT_Dot1dTpPortInDiscards */ + ifOutUcastPkts, /* STAT_IfOutUcastPkts */ + ifOutMulticastPkts, /* STAT_IfOutMulticastPkts */ + ifOutBroadcastPkts, /* STAT_IfOutBroadcastPkts */ + outOampduPkts, /* STAT_OutOampduPkts */ + inOampduPkts, /* STAT_InOampduPkts */ + MIB_NOT_SUPPORT, /* STAT_PktgenPkts */ + inMldChecksumError, /* STAT_InMldChecksumError */ + inIgmpChecksumError, /* STAT_InIgmpChecksumError */ + inMldSpecificQuery, /* STAT_InMldSpecificQuery */ + inMldGeneralQuery, /* STAT_InMldGeneralQuery */ + inIgmpSpecificQuery, /* STAT_InIgmpSpecificQuery */ + inIgmpGeneralQuery, /* STAT_InIgmpGeneralQuery */ + inMldLeaves, /* STAT_InMldLeaves */ + inIgmpLeaves, /* STAT_InIgmpInterfaceLeaves */ + inIgmpJoinsSuccess, /* STAT_InIgmpJoinsSuccess */ + inIgmpJoinsFail, /* STAT_InIgmpJoinsFail */ + inMldJoinsSuccess, /* STAT_InMldJoinsSuccess */ + inMldJoinsFail, /* STAT_InMldJoinsFail */ + inReportSuppressionDrop, /* STAT_InReportSuppressionDrop */ + inLeaveSuppressionDrop, /* STAT_InLeaveSuppressionDrop */ + outIgmpReports, /* STAT_OutIgmpReports */ + outIgmpLeaves, /* STAT_OutIgmpLeaves */ + outIgmpGeneralQuery, /* STAT_OutIgmpGeneralQuery */ + outIgmpSpecificQuery, /* STAT_OutIgmpSpecificQuery */ + outMldReports, /* STAT_OutMldReports */ + outMldLeaves, /* STAT_OutMldLeaves */ + outMldGeneralQuery, /* STAT_OutMldGeneralQuery */ + outMldSpecificQuery, /* STAT_OutMldSpecificQuery */ + inKnownMulticastPkts, /* STAT_InKnownMulticastPkts */ + ifInMulticastPkts, /* STAT_IfInMulticastPkts */ + ifInBroadcastPkts, /* STAT_IfInBroadcastPkts */ + ifOutDiscards /* STAT_IfOutDiscards */ + }; + + if(cnt_idx >= STAT_PORT_CNTR_END) + return RT_ERR_STAT_INVALID_PORT_CNTR; + + if(mib_asic_idx[cnt_idx] == MIB_NOT_SUPPORT) + return RT_ERR_CHIP_NOT_SUPPORTED; + + *pMib_idx = mib_asic_idx[cnt_idx]; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_port_get + * Description: + * Get per port MIB counter by index + * Input: + * port - port id. + * cntr_idx - port counter index. + * Output: + * pCntr - MIB retrieved counter. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Get per port MIB counter by index definition. + */ +rtk_api_ret_t rtk_stat_port_get(rtk_port_t port, rtk_stat_port_type_t cntr_idx, rtk_stat_counter_t *pCntr) +{ + rtk_api_ret_t retVal; + RTL8367C_MIBCOUNTER mib_idx; + rtk_stat_counter_t second_cnt; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pCntr) + return RT_ERR_NULL_POINTER; + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + if (cntr_idx>=STAT_PORT_CNTR_END) + return RT_ERR_STAT_INVALID_PORT_CNTR; + + if((retVal = _get_asic_mib_idx(cntr_idx, &mib_idx)) != RT_ERR_OK) + return retVal; + + if(mib_idx == MIB_NOT_SUPPORT) + return RT_ERR_CHIP_NOT_SUPPORTED; + + if ((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, pCntr)) != RT_ERR_OK) + return retVal; + + if(cntr_idx == STAT_EtherStatsMulticastPkts) + { + if((retVal = _get_asic_mib_idx(STAT_IfOutMulticastPkts, &mib_idx)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK) + return retVal; + + *pCntr += second_cnt; + } + + if(cntr_idx == STAT_EtherStatsBroadcastPkts) + { + if((retVal = _get_asic_mib_idx(STAT_IfOutBroadcastPkts, &mib_idx)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicMIBsCounter(rtk_switch_port_L2P_get(port), mib_idx, &second_cnt)) != RT_ERR_OK) + return retVal; + + *pCntr += second_cnt; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_port_getAll + * Description: + * Get all counters of one specified port in the specified device. + * Input: + * port - port id. + * Output: + * pPort_cntrs - buffer pointer of counter value. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get all MIB counters of one port. + */ +rtk_api_ret_t rtk_stat_port_getAll(rtk_port_t port, rtk_stat_port_cntr_t *pPort_cntrs) +{ + rtk_api_ret_t retVal; + rtk_uint32 mibIndex; + rtk_uint64 mibCounter; + rtk_uint32 *accessPtr; + /* address offset to MIBs counter */ + CONST_T rtk_uint16 mibLength[STAT_PORT_CNTR_END]= { + 2,1,1,1,1,1,1,1,1, + 2,1,1,1,1,1,1,1,1,1,1, + 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPort_cntrs) + return RT_ERR_NULL_POINTER; + + /* Check port valid */ + RTK_CHK_PORT_VALID(port); + + accessPtr = (rtk_uint32*)pPort_cntrs; + for (mibIndex=0;mibIndex RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_OUT_OF_RANGE; + + if((idx % 2) == 1) + return RT_ERR_INPUT; + + if(mode >= LOGGING_MODE_END) + return RT_ERR_OUT_OF_RANGE; + + if(type >= LOGGING_TYPE_END) + return RT_ERR_OUT_OF_RANGE; + + if((retVal = rtl8367c_setAsicMIBsLoggingType((idx / 2), (rtk_uint32)type)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicMIBsLoggingMode((idx / 2), (rtk_uint32)mode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_logging_counterCfg_get + * Description: + * Get the type and mode of Logging Counter + * Input: + * idx - The index of Logging Counter. Should be even number only.(0,2,4,6,8.....30) + * Output: + * pMode - 32 bits or 64 bits mode + * pType - Packet counter or byte counter + * Return: + * RT_ERR_OK - OK + * RT_ERR_OUT_OF_RANGE - Out of range. + * RT_ERR_FAILED - Failed + * RT_ERR_NULL_POINTER - NULL Pointer + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * Get the type and mode of Logging Counter. + */ +rtk_api_ret_t rtk_stat_logging_counterCfg_get(rtk_uint32 idx, rtk_logging_counter_mode_t *pMode, rtk_logging_counter_type_t *pType) +{ + rtk_api_ret_t retVal; + rtk_uint32 type, mode; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_OUT_OF_RANGE; + + if((idx % 2) == 1) + return RT_ERR_INPUT; + + if(pMode == NULL) + return RT_ERR_NULL_POINTER; + + if(pType == NULL) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicMIBsLoggingType((idx / 2), &type)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicMIBsLoggingMode((idx / 2), &mode)) != RT_ERR_OK) + return retVal; + + *pMode = (rtk_logging_counter_mode_t)mode; + *pType = (rtk_logging_counter_type_t)type; + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_stat_logging_counter_reset + * Description: + * Reset Logging Counter + * Input: + * idx - The index of Logging Counter. (0~31) + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_OUT_OF_RANGE - Out of range. + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Reset Logging Counter. + */ +rtk_api_ret_t rtk_stat_logging_counter_reset(rtk_uint32 idx) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_OUT_OF_RANGE; + + if((retVal = rtl8367c_setAsicMIBsResetLoggingCounter(idx)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_logging_counter_get + * Description: + * Get Logging Counter + * Input: + * idx - The index of Logging Counter. (0~31) + * Output: + * pCnt - Logging counter value + * Return: + * RT_ERR_OK - OK + * RT_ERR_OUT_OF_RANGE - Out of range. + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Get Logging Counter. + */ +rtk_api_ret_t rtk_stat_logging_counter_get(rtk_uint32 idx, rtk_uint32 *pCnt) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pCnt) + return RT_ERR_NULL_POINTER; + + if(idx > RTL8367C_MIB_MAX_LOG_CNT_IDX) + return RT_ERR_OUT_OF_RANGE; + + if((retVal = rtl8367c_getAsicMIBsLogCounter(idx, pCnt)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_lengthMode_set + * Description: + * Set Legnth mode. + * Input: + * txMode - The length counting mode + * rxMode - The length counting mode + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Out of range. + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * + */ +rtk_api_ret_t rtk_stat_lengthMode_set(rtk_stat_lengthMode_t txMode, rtk_stat_lengthMode_t rxMode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(txMode >= LENGTH_MODE_END) + return RT_ERR_INPUT; + + if(rxMode >= LENGTH_MODE_END) + return RT_ERR_INPUT; + + if((retVal = rtl8367c_setAsicMIBsLength((rtk_uint32)txMode, (rtk_uint32)rxMode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stat_lengthMode_get + * Description: + * Get Length mode. + * Input: + * None. + * Output: + * pTxMode - The length counting mode + * pRxMode - The length counting mode + * Return: + * RT_ERR_OK - OK + * RT_ERR_INPUT - Out of range. + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + */ +rtk_api_ret_t rtk_stat_lengthMode_get(rtk_stat_lengthMode_t *pTxMode, rtk_stat_lengthMode_t *pRxMode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pTxMode) + return RT_ERR_NULL_POINTER; + + if(NULL == pRxMode) + return RT_ERR_NULL_POINTER; + + if((retVal = rtl8367c_getAsicMIBsLength((rtk_uint32 *)pTxMode, (rtk_uint32 *)pRxMode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/storm.c b/drivers/net/phy/rtk/rtl8367c/storm.c new file mode 100644 index 000000000000..68063cdfa75f --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/storm.c @@ -0,0 +1,816 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Storm module. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function Name: + * rtk_rate_stormControlMeterIdx_set + * Description: + * Set the storm control meter index. + * Input: + * port - port id + * storm_type - storm group type + * index - storm control meter index. + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - Invalid port id + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlMeterIdx_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 index) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_setAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), index))!=RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlMeterIdx_get + * Description: + * Get the storm control meter index. + * Input: + * port - port id + * storm_type - storm group type + * Output: + * pIndex - storm control meter index. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_PORT_ID - Invalid port id + * RT_ERR_FILTER_METER_ID - Invalid meter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlMeterIdx_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (NULL == pIndex ) + return RT_ERR_NULL_POINTER; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterMulticastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_getAsicStormFilterBroadcastMeter(rtk_switch_port_L2P_get(port), pIndex))!=RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlPortEnable_set + * Description: + * Set enable status of storm control on specified port. + * Input: + * port - port id + * stormType - storm group type + * enable - enable status of storm control + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlPortEnable_set(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_setAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_setAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlPortEnable_set + * Description: + * Set enable status of storm control on specified port. + * Input: + * port - port id + * stormType - storm group type + * Output: + * pEnable - enable status of storm control + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_PORT_ID - invalid port id + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlPortEnable_get(rtk_port_t port, rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (NULL == pEnable) + return RT_ERR_ENABLE; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_getAsicStormFilterUnknownUnicastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterUnknownMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterMulticastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_getAsicStormFilterBroadcastEnable(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_storm_bypass_set + * Description: + * Set bypass storm filter control configuration. + * Input: + * type - Bypass storm filter control type. + * enable - Bypass status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid IFG parameter + * Note: + * + * This API can set per-port bypass storm filter control frame type including RMA and IGMP. + * The bypass frame type is as following: + * - BYPASS_BRG_GROUP, + * - BYPASS_FD_PAUSE, + * - BYPASS_SP_MCAST, + * - BYPASS_1X_PAE, + * - BYPASS_UNDEF_BRG_04, + * - BYPASS_UNDEF_BRG_05, + * - BYPASS_UNDEF_BRG_06, + * - BYPASS_UNDEF_BRG_07, + * - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - BYPASS_UNDEF_BRG_09, + * - BYPASS_UNDEF_BRG_0A, + * - BYPASS_UNDEF_BRG_0B, + * - BYPASS_UNDEF_BRG_0C, + * - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - BYPASS_8021AB, + * - BYPASS_UNDEF_BRG_0F, + * - BYPASS_BRG_MNGEMENT, + * - BYPASS_UNDEFINED_11, + * - BYPASS_UNDEFINED_12, + * - BYPASS_UNDEFINED_13, + * - BYPASS_UNDEFINED_14, + * - BYPASS_UNDEFINED_15, + * - BYPASS_UNDEFINED_16, + * - BYPASS_UNDEFINED_17, + * - BYPASS_UNDEFINED_18, + * - BYPASS_UNDEFINED_19, + * - BYPASS_UNDEFINED_1A, + * - BYPASS_UNDEFINED_1B, + * - BYPASS_UNDEFINED_1C, + * - BYPASS_UNDEFINED_1D, + * - BYPASS_UNDEFINED_1E, + * - BYPASS_UNDEFINED_1F, + * - BYPASS_GMRP, + * - BYPASS_GVRP, + * - BYPASS_UNDEF_GARP_22, + * - BYPASS_UNDEF_GARP_23, + * - BYPASS_UNDEF_GARP_24, + * - BYPASS_UNDEF_GARP_25, + * - BYPASS_UNDEF_GARP_26, + * - BYPASS_UNDEF_GARP_27, + * - BYPASS_UNDEF_GARP_28, + * - BYPASS_UNDEF_GARP_29, + * - BYPASS_UNDEF_GARP_2A, + * - BYPASS_UNDEF_GARP_2B, + * - BYPASS_UNDEF_GARP_2C, + * - BYPASS_UNDEF_GARP_2D, + * - BYPASS_UNDEF_GARP_2E, + * - BYPASS_UNDEF_GARP_2F, + * - BYPASS_IGMP. + * - BYPASS_CDP. + * - BYPASS_CSSTP. + * - BYPASS_LLDP. + */ +rtk_api_ret_t rtk_storm_bypass_set(rtk_storm_bypass_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= BYPASS_END) + return RT_ERR_INPUT; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.discard_storm_filter = enable; + + if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else if(type == BYPASS_IGMP) + { + if ((retVal = rtl8367c_setAsicIGMPBypassStormCTRL(enable)) != RT_ERR_OK) + return retVal; + } + else if (type == BYPASS_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.discard_storm_filter = enable; + + if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == BYPASS_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.discard_storm_filter = enable; + + if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == BYPASS_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.discard_storm_filter = enable; + + if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_storm_bypass_get + * Description: + * Get bypass storm filter control configuration. + * Input: + * type - Bypass storm filter control type. + * Output: + * pEnable - Bypass status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get per-port bypass storm filter control frame type including RMA and IGMP. + * The bypass frame type is as following: + * - BYPASS_BRG_GROUP, + * - BYPASS_FD_PAUSE, + * - BYPASS_SP_MCAST, + * - BYPASS_1X_PAE, + * - BYPASS_UNDEF_BRG_04, + * - BYPASS_UNDEF_BRG_05, + * - BYPASS_UNDEF_BRG_06, + * - BYPASS_UNDEF_BRG_07, + * - BYPASS_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - BYPASS_UNDEF_BRG_09, + * - BYPASS_UNDEF_BRG_0A, + * - BYPASS_UNDEF_BRG_0B, + * - BYPASS_UNDEF_BRG_0C, + * - BYPASS_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - BYPASS_8021AB, + * - BYPASS_UNDEF_BRG_0F, + * - BYPASS_BRG_MNGEMENT, + * - BYPASS_UNDEFINED_11, + * - BYPASS_UNDEFINED_12, + * - BYPASS_UNDEFINED_13, + * - BYPASS_UNDEFINED_14, + * - BYPASS_UNDEFINED_15, + * - BYPASS_UNDEFINED_16, + * - BYPASS_UNDEFINED_17, + * - BYPASS_UNDEFINED_18, + * - BYPASS_UNDEFINED_19, + * - BYPASS_UNDEFINED_1A, + * - BYPASS_UNDEFINED_1B, + * - BYPASS_UNDEFINED_1C, + * - BYPASS_UNDEFINED_1D, + * - BYPASS_UNDEFINED_1E, + * - BYPASS_UNDEFINED_1F, + * - BYPASS_GMRP, + * - BYPASS_GVRP, + * - BYPASS_UNDEF_GARP_22, + * - BYPASS_UNDEF_GARP_23, + * - BYPASS_UNDEF_GARP_24, + * - BYPASS_UNDEF_GARP_25, + * - BYPASS_UNDEF_GARP_26, + * - BYPASS_UNDEF_GARP_27, + * - BYPASS_UNDEF_GARP_28, + * - BYPASS_UNDEF_GARP_29, + * - BYPASS_UNDEF_GARP_2A, + * - BYPASS_UNDEF_GARP_2B, + * - BYPASS_UNDEF_GARP_2C, + * - BYPASS_UNDEF_GARP_2D, + * - BYPASS_UNDEF_GARP_2E, + * - BYPASS_UNDEF_GARP_2F, + * - BYPASS_IGMP. + * - BYPASS_CDP. + * - BYPASS_CSSTP. + * - BYPASS_LLDP. + */ +rtk_api_ret_t rtk_storm_bypass_get(rtk_storm_bypass_t type, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= BYPASS_END) + return RT_ERR_INPUT; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if (type >= 0 && type <= BYPASS_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.discard_storm_filter; + } + else if(type == BYPASS_IGMP) + { + if ((retVal = rtl8367c_getAsicIGMPBypassStormCTRL(pEnable)) != RT_ERR_OK) + return retVal; + } + else if (type == BYPASS_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.discard_storm_filter; + } + else if (type == BYPASS_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.discard_storm_filter; + } + else if (type == BYPASS_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.discard_storm_filter; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtPortmask_set + * Description: + * Set extension storm control port mask + * Input: + * pPortmask - port mask + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtPortmask_set(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtk_switch_portmask_L2P_get(pPortmask, &pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicStormFilterExtEnablePortMask(pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtPortmask_get + * Description: + * Set extension storm control port mask + * Input: + * None + * Output: + * pPortmask - port mask + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtPortmask_get(rtk_portmask_t *pPortmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pPortmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicStormFilterExtEnablePortMask(&pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pPortmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtEnable_set + * Description: + * Set extension storm control state + * Input: + * stormType - storm group type + * enable - extension storm control state + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtEnable_set(rtk_rate_storm_group_t stormType, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastEnable(enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastEnable(enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtMulticastEnable(enable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastEnable(enable)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtEnable_get + * Description: + * Get extension storm control state + * Input: + * stormType - storm group type + * Output: + * pEnable - extension storm control state + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtEnable_get(rtk_rate_storm_group_t stormType, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (NULL == pEnable) + return RT_ERR_NULL_POINTER; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtMulticastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastEnable((rtk_uint32 *)pEnable)) != RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtMeterIdx_set + * Description: + * Set extension storm control meter index + * Input: + * stormType - storm group type + * index - extension storm control state + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_set(rtk_rate_storm_group_t stormType, rtk_uint32 index) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if (index > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtUnknownUnicastMeter(index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtUnknownMulticastMeter(index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_setAsicStormFilterExtMulticastMeter(index))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_setAsicStormFilterExtBroadcastMeter(index))!=RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_rate_stormControlExtMeterIdx_get + * Description: + * Get extension storm control meter index + * Input: + * stormType - storm group type + * pIndex - extension storm control state + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - invalid input parameter + * Note: + * + */ +rtk_api_ret_t rtk_rate_stormControlExtMeterIdx_get(rtk_rate_storm_group_t stormType, rtk_uint32 *pIndex) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (stormType >= STORM_GROUP_END) + return RT_ERR_SFC_UNKNOWN_GROUP; + + if(NULL == pIndex) + return RT_ERR_NULL_POINTER; + + switch (stormType) + { + case STORM_GROUP_UNKNOWN_UNICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtUnknownUnicastMeter(pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_UNKNOWN_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtUnknownMulticastMeter(pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_MULTICAST: + if ((retVal = rtl8367c_getAsicStormFilterExtMulticastMeter(pIndex))!=RT_ERR_OK) + return retVal; + break; + case STORM_GROUP_BROADCAST: + if ((retVal = rtl8367c_getAsicStormFilterExtBroadcastMeter(pIndex))!=RT_ERR_OK) + return retVal; + break; + default: + break; + } + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/svlan.c b/drivers/net/phy/rtk/rtl8367c/svlan.c new file mode 100644 index 000000000000..067291526ac8 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/svlan.c @@ -0,0 +1,2415 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in SVLAN module. + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +rtk_uint8 svlan_mbrCfgUsage[RTL8367C_SVIDXNO]; +rtk_uint16 svlan_mbrCfgVid[RTL8367C_SVIDXNO]; +rtk_svlan_lookupType_t svlan_lookupType; +/* Function Name: + * rtk_svlan_init + * Description: + * Initialize SVLAN Configuration + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * Ether type of S-tag in 802.1ad is 0x88a8 and there are existed ether type 0x9100 and 0x9200 for Q-in-Q SLAN design. + * User can set matched ether type as service provider supported protocol. + */ +rtk_api_ret_t rtk_svlan_init(void) +{ + rtk_uint32 i; + rtk_api_ret_t retVal; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_s2c_t svlanSP2CConf; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + rtk_uint32 svidx; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /*default use C-priority*/ + if ((retVal = rtl8367c_setAsicSvlanPrioritySel(SPRISEL_CTAGPRI)) != RT_ERR_OK) + return retVal; + + /*Drop SVLAN untag frame*/ + if ((retVal = rtl8367c_setAsicSvlanIngressUntag(UNTAG_DROP)) != RT_ERR_OK) + return retVal; + + /*Drop SVLAN unmatch frame*/ + if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch(UNMATCH_DROP)) != RT_ERR_OK) + return retVal; + + /*Set TPID to 0x88a8*/ + if ((retVal = rtl8367c_setAsicSvlanTpid(0x88a8)) != RT_ERR_OK) + return retVal; + + /*Clean Uplink Port Mask to none*/ + if ((retVal = rtl8367c_setAsicSvlanUplinkPortMask(0)) != RT_ERR_OK) + return retVal; + + /*Clean SVLAN Member Configuration*/ + for (i=0; i<= RTL8367C_SVIDXMAX; i++) + { + memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + } + + /*Clean C2S Configuration*/ + for (i=0; i<= RTL8367C_C2SIDXMAX; i++) + { + if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, 0,0,0)) != RT_ERR_OK) + return retVal; + } + + /*Clean SP2C Configuration*/ + for (i=0; i <= RTL8367C_SP2CMAX ; i++) + { + memset(&svlanSP2CConf, 0, sizeof(rtl8367c_svlan_s2c_t)); + if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + } + + /*Clean MC2S Configuration*/ + for (i=0 ; i<= RTL8367C_MC2SIDXMAX; i++) + { + memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + } + + + if ((retVal = rtk_svlan_lookupType_set(SVLAN_LOOKUP_S64MBRCGF)) != RT_ERR_OK) + return retVal; + + + for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++) + { + svlan_mbrCfgUsage[svidx] = FALSE; + } + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_servicePort_add + * Description: + * Add one service port in the specified device + * Input: + * port - Port id. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API is setting which port is connected to provider switch. All frames receiving from this port must + * contain accept SVID in S-tag field. + */ +rtk_api_ret_t rtk_svlan_servicePort_add(rtk_port_t port) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicSvlanUplinkPortMask(&pmsk)) != RT_ERR_OK) + return retVal; + + pmsk = pmsk | (1<RTK_MAX_NUM_OF_PROTO_TYPE) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicSvlanTpid(svlan_tag_id)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_tpidEntry_get + * Description: + * Get accepted S-VLAN ether type setting. + * Input: + * None + * Output: + * pSvlan_tag_id - Ether type of S-tag frame parsing in uplink ports. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * This API is setting which port is connected to provider switch. All frames receiving from this port must + * contain accept SVID in S-tag field. + */ +rtk_api_ret_t rtk_svlan_tpidEntry_get(rtk_svlan_tpid_t *pSvlan_tag_id) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvlan_tag_id) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSvlanTpid(pSvlan_tag_id)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_priorityRef_set + * Description: + * Set S-VLAN upstream priority reference setting. + * Input: + * ref - reference selection parameter. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * Note: + * The API can set the upstream SVLAN tag priority reference source. The related priority + * sources are as following: + * - REF_INTERNAL_PRI, + * - REF_CTAG_PRI, + * - REF_SVLAN_PRI, + * - REF_PB_PRI. + */ +rtk_api_ret_t rtk_svlan_priorityRef_set(rtk_svlan_pri_ref_t ref) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (ref >= REF_PRI_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicSvlanPrioritySel(ref)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_priorityRef_get + * Description: + * Get S-VLAN upstream priority reference setting. + * Input: + * None + * Output: + * pRef - reference selection parameter. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * The API can get the upstream SVLAN tag priority reference source. The related priority + * sources are as following: + * - REF_INTERNAL_PRI, + * - REF_CTAG_PRI, + * - REF_SVLAN_PRI, + * - REF_PB_PRI + */ +rtk_api_ret_t rtk_svlan_priorityRef_get(rtk_svlan_pri_ref_t *pRef) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pRef) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSvlanPrioritySel(pRef)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_memberPortEntry_set + * Description: + * Configure system SVLAN member content + * Input: + * svid - SVLAN id + * psvlan_cfg - SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. + * Note: + * The API can set system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted + * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped by default setup. + * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. + */ +rtk_api_ret_t rtk_svlan_memberPortEntry_set(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg) +{ + rtk_api_ret_t retVal; + rtk_int32 i; + rtk_uint32 empty_idx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtk_uint32 phyMbrPmask; + rtk_vlan_cfg_t vlanCfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvlan_cfg) + return RT_ERR_NULL_POINTER; + + if(svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport)); + + RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport)); + + if (pSvlan_cfg->fiden > ENABLED) + return RT_ERR_ENABLE; + + if (pSvlan_cfg->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if (pSvlan_cfg->priority > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if (pSvlan_cfg->efiden > ENABLED) + return RT_ERR_ENABLE; + + if (pSvlan_cfg->efid > RTL8367C_EFIDMAX) + return RT_ERR_L2_FID; + + if(SVLAN_LOOKUP_C4KVLAN == svlan_lookupType) + { + if ((retVal = rtk_vlan_get(svid, &vlanCfg)) != RT_ERR_OK) + return retVal; + + vlanCfg.mbr = pSvlan_cfg->memberport; + vlanCfg.untag = pSvlan_cfg->untagport; + + if ((retVal = rtk_vlan_set(svid, &vlanCfg)) != RT_ERR_OK) + return retVal; + + empty_idx = 0xFF; + + for (i = 0; i<= RTL8367C_SVIDXMAX; i++) + { + if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i]) + { + memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); + svlanMemConf.vs_svid = svid; + svlanMemConf.vs_efiden = pSvlan_cfg->efiden; + svlanMemConf.vs_efid = pSvlan_cfg->efid; + svlanMemConf.vs_priority = pSvlan_cfg->priority; + + /*for create check*/ + if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) + svlanMemConf.vs_efid = 1; + + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx) + { + empty_idx = i; + } + } + + if (empty_idx != 0xFF) + { + svlan_mbrCfgUsage[empty_idx] = TRUE; + svlan_mbrCfgVid[empty_idx] = svid; + + memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); + svlanMemConf.vs_svid = svid; + svlanMemConf.vs_efiden = pSvlan_cfg->efiden; + svlanMemConf.vs_efid = pSvlan_cfg->efid; + svlanMemConf.vs_priority = pSvlan_cfg->priority; + + /*for create check*/ + if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) + svlanMemConf.vs_efid = 1; + + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + } + + return RT_ERR_OK; + } + + + empty_idx = 0xFF; + + for (i = 0; i<= RTL8367C_SVIDXMAX; i++) + { + /* + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + */ + if (svid == svlan_mbrCfgVid[i] && TRUE == svlan_mbrCfgUsage[i]) + { + svlanMemConf.vs_svid = svid; + + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_member = phyMbrPmask; + + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_untag = phyMbrPmask; + + svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; + svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; + svlanMemConf.vs_priority = pSvlan_cfg->priority; + svlanMemConf.vs_efiden = pSvlan_cfg->efiden; + svlanMemConf.vs_efid = pSvlan_cfg->efid; + + /*all items are reset means deleting*/ + if( 0 == svlanMemConf.vs_member && + 0 == svlanMemConf.vs_untag && + 0 == svlanMemConf.vs_force_fid && + 0 == svlanMemConf.vs_fid_msti && + 0 == svlanMemConf.vs_priority && + 0 == svlanMemConf.vs_efiden && + 0 == svlanMemConf.vs_efid) + { + svlan_mbrCfgUsage[i] = FALSE; + svlan_mbrCfgVid[i] = 0; + + /* Clear SVID also */ + svlanMemConf.vs_svid = 0; + } + else + { + svlan_mbrCfgUsage[i] = TRUE; + svlan_mbrCfgVid[i] = svlanMemConf.vs_svid; + + if(0 == svlanMemConf.vs_svid) + { + /*for create check*/ + if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) + { + svlanMemConf.vs_efid = 1; + } + } + } + + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + else if (FALSE == svlan_mbrCfgUsage[i] && 0xFF == empty_idx) + { + empty_idx = i; + } + } + + if (empty_idx != 0xFF) + { + memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); + svlanMemConf.vs_svid = svid; + + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_member = phyMbrPmask; + + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_untag = phyMbrPmask; + + svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; + svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; + svlanMemConf.vs_priority = pSvlan_cfg->priority; + + svlanMemConf.vs_efiden = pSvlan_cfg->efiden; + svlanMemConf.vs_efid = pSvlan_cfg->efid; + + /*change efid for empty svid 0*/ + if(0 == svlanMemConf.vs_svid) + { /*for create check*/ + if(0 == svlanMemConf.vs_efiden && 0 == svlanMemConf.vs_efid) + { + svlanMemConf.vs_efid = 1; + } + } + + svlan_mbrCfgUsage[empty_idx] = TRUE; + svlan_mbrCfgVid[empty_idx] = svlanMemConf.vs_svid; + + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlanMemConf)) != RT_ERR_OK) + { + return retVal; + } + + return RT_ERR_OK; + } + + return RT_ERR_SVLAN_TABLE_FULL; +} + +/* Function Name: + * rtk_svlan_memberPortEntry_get + * Description: + * Get SVLAN member Configure. + * Input: + * svid - SVLAN id + * Output: + * pSvlan_cfg - SVLAN member configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted + * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped. + */ +rtk_api_ret_t rtk_svlan_memberPortEntry_get(rtk_vlan_t svid, rtk_svlan_memberCfg_t *pSvlan_cfg) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvlan_cfg) + return RT_ERR_NULL_POINTER; + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + + for (i = 0; i<= RTL8367C_SVIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + pSvlan_cfg->svid = svlanMemConf.vs_svid; + + if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK) + return RT_ERR_FAILED; + + if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK) + return RT_ERR_FAILED; + + pSvlan_cfg->fiden = svlanMemConf.vs_force_fid; + pSvlan_cfg->fid = svlanMemConf.vs_fid_msti; + pSvlan_cfg->priority = svlanMemConf.vs_priority; + pSvlan_cfg->efiden = svlanMemConf.vs_efiden; + pSvlan_cfg->efid = svlanMemConf.vs_efid; + + return RT_ERR_OK; + } + } + + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + +} + +/* Function Name: + * rtk_svlan_memberPortEntry_adv_set + * Description: + * Configure system SVLAN member by index + * Input: + * idx - Index (0 ~ 63) + * psvlan_cfg - SVLAN member configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_PORT_MASK - Invalid portmask. + * RT_ERR_SVLAN_TABLE_FULL - SVLAN configuration is full. + * Note: + * The API can set system 64 accepted s-tag frame format by index. + * - rtk_svlan_memberCfg_t->svid is SVID of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->memberport is member port mask of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->fid is filtering database of SVLAN member configuration. + * - rtk_svlan_memberCfg_t->priority is priority of SVLAN member configuration. + */ +rtk_api_ret_t rtk_svlan_memberPortEntry_adv_set(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg) +{ + rtk_api_ret_t retVal; + rtl8367c_svlan_memconf_t svlanMemConf; + rtk_uint32 phyMbrPmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvlan_cfg) + return RT_ERR_NULL_POINTER; + + if (idx > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + if (pSvlan_cfg->svid>RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->memberport)); + + RTK_CHK_PORTMASK_VALID(&(pSvlan_cfg->untagport)); + + if (pSvlan_cfg->fiden > ENABLED) + return RT_ERR_ENABLE; + + if (pSvlan_cfg->fid > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if (pSvlan_cfg->priority > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if (pSvlan_cfg->efiden > ENABLED) + return RT_ERR_ENABLE; + + if (pSvlan_cfg->efid > RTL8367C_EFIDMAX) + return RT_ERR_L2_FID; + + memset(&svlanMemConf, 0, sizeof(rtl8367c_svlan_memconf_t)); + svlanMemConf.vs_svid = pSvlan_cfg->svid; + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->memberport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_member = phyMbrPmask; + + if(rtk_switch_portmask_L2P_get(&(pSvlan_cfg->untagport), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + svlanMemConf.vs_untag = phyMbrPmask; + + + svlanMemConf.vs_force_fid = pSvlan_cfg->fiden; + svlanMemConf.vs_fid_msti = pSvlan_cfg->fid; + svlanMemConf.vs_priority = pSvlan_cfg->priority; + svlanMemConf.vs_efiden = pSvlan_cfg->efiden; + svlanMemConf.vs_efid = pSvlan_cfg->efid; + + if(0 == svlanMemConf.vs_svid && + 0 == svlanMemConf.vs_member && + 0 == svlanMemConf.vs_untag && + 0 == svlanMemConf.vs_force_fid && + 0 == svlanMemConf.vs_fid_msti && + 0 == svlanMemConf.vs_priority && + 0 == svlanMemConf.vs_efiden && + 0 == svlanMemConf.vs_efid) + { + svlan_mbrCfgUsage[idx] = FALSE; + svlan_mbrCfgVid[idx] = 0; + } + else + { + svlan_mbrCfgUsage[idx] = TRUE; + svlan_mbrCfgVid[idx] = svlanMemConf.vs_svid; + } + + if ((retVal = rtl8367c_setAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_memberPortEntry_adv_get + * Description: + * Get SVLAN member Configure by index. + * Input: + * idx - Index (0 ~ 63) + * Output: + * pSvlan_cfg - SVLAN member configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get system 64 accepted s-tag frame format. Only 64 SVID S-tag frame will be accepted + * to receiving from uplink ports. Other SVID S-tag frame or S-untagged frame will be dropped. + */ +rtk_api_ret_t rtk_svlan_memberPortEntry_adv_get(rtk_uint32 idx, rtk_svlan_memberCfg_t *pSvlan_cfg) +{ + rtk_api_ret_t retVal; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvlan_cfg) + return RT_ERR_NULL_POINTER; + + if (idx > RTL8367C_SVIDXMAX) + return RT_ERR_SVLAN_ENTRY_INDEX; + + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + pSvlan_cfg->svid = svlanMemConf.vs_svid; + if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_member,&(pSvlan_cfg->memberport)) != RT_ERR_OK) + return RT_ERR_FAILED; + + if(rtk_switch_portmask_P2L_get(svlanMemConf.vs_untag,&(pSvlan_cfg->untagport)) != RT_ERR_OK) + return RT_ERR_FAILED; + + pSvlan_cfg->fiden = svlanMemConf.vs_force_fid; + pSvlan_cfg->fid = svlanMemConf.vs_fid_msti; + pSvlan_cfg->priority = svlanMemConf.vs_priority; + pSvlan_cfg->efiden = svlanMemConf.vs_efiden; + pSvlan_cfg->efid = svlanMemConf.vs_efid; + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_svlan_defaultSvlan_set + * Description: + * Configure default egress SVLAN. + * Input: + * port - Source port + * svid - SVLAN id + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * Note: + * The API can set port n S-tag format index while receiving frame from port n + * is transmit through uplink port with s-tag field + */ +rtk_api_ret_t rtk_svlan_defaultSvlan_set(rtk_port_t port, rtk_vlan_t svid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + /* svid must be 0~4095 */ + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + if ((retVal = rtl8367c_setAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), i)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; +} + +/* Function Name: + * rtk_svlan_defaultSvlan_get + * Description: + * Get the configure default egress SVLAN. + * Input: + * port - Source port + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can get port n S-tag format index while receiving frame from port n + * is transmit through uplink port with s-tag field + */ +rtk_api_ret_t rtk_svlan_defaultSvlan_get(rtk_port_t port, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 idx; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvid) + return RT_ERR_NULL_POINTER; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicSvlanDefaultVlan(rtk_switch_port_L2P_get(port), &idx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(idx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + *pSvid = svlanMemConf.vs_svid; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_c2s_add + * Description: + * Configure SVLAN C2S table + * Input: + * vid - VLAN ID + * src_port - Ingress Port + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set system C2S configuration. ASIC will check upstream's VID and assign related + * SVID to matched packet. There are 128 SVLAN C2S configurations. + */ +rtk_api_ret_t rtk_svlan_c2s_add(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t svid) +{ + rtk_api_ret_t retVal, i; + rtk_uint32 empty_idx; + rtk_uint32 evid, pmsk, svidx, c2s_svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtk_port_t phyPort; + rtk_uint16 doneFlag; + + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(src_port); + + phyPort = rtk_switch_port_L2P_get(src_port); + + empty_idx = 0xFFFF; + svidx = 0xFFFF; + doneFlag = FALSE; + + for (i = 0; i<= RTL8367C_SVIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_VID; + + for (i=RTL8367C_C2SIDXMAX; i>=0; i--) + { + if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &c2s_svidx)) != RT_ERR_OK) + return retVal; + + if (evid == vid) + { + /* Check Src_port */ + if(pmsk & (1 << phyPort)) + { + /* Check SVIDX */ + if(c2s_svidx == svidx) + { + /* All the same, do nothing */ + } + else + { + /* New svidx, remove src_port and find a new slot to add a new entry */ + pmsk = pmsk & ~(1 << phyPort); + if(pmsk == 0) + c2s_svidx = 0; + + if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, c2s_svidx)) != RT_ERR_OK) + return retVal; + } + } + else + { + if(c2s_svidx == svidx && doneFlag == FALSE) + { + pmsk = pmsk | (1 << phyPort); + if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK) + return retVal; + + doneFlag = TRUE; + } + } + } + else if (evid==0&&pmsk==0) + { + empty_idx = i; + } + } + + if (0xFFFF != empty_idx && doneFlag ==FALSE) + { + if ((retVal = rtl8367c_setAsicSvlanC2SConf(empty_idx, vid, (1< RTL8367C_EVIDMAX) + return RT_ERR_VLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(src_port); + phyPort = rtk_switch_port_L2P_get(src_port); + + for (i = 0; i <= RTL8367C_C2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK) + return retVal; + + if (evid == vid) + { + if(pmsk & (1 << phyPort)) + { + pmsk = pmsk & ~(1 << phyPort); + if(pmsk == 0) + { + vid = 0; + svidx = 0; + } + + if ((retVal = rtl8367c_setAsicSvlanC2SConf(i, vid, pmsk, svidx)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_c2s_get + * Description: + * Get configure SVLAN C2S table + * Input: + * vid - VLAN ID + * src_port - Ingress Port + * Output: + * pSvid - SVLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get system C2S configuration. There are 128 SVLAN C2S configurations. + */ +rtk_api_ret_t rtk_svlan_c2s_get(rtk_vlan_t vid, rtk_port_t src_port, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtk_uint32 evid, pmsk, svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtk_port_t phyPort; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvid) + return RT_ERR_NULL_POINTER; + + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(src_port); + phyPort = rtk_switch_port_L2P_get(src_port); + + for (i = 0; i <= RTL8367C_C2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanC2SConf(i, &evid, &pmsk, &svidx)) != RT_ERR_OK) + return retVal; + + if (evid == vid) + { + if(pmsk & (1 << phyPort)) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + *pSvid = svlanMemConf.vs_svid; + return RT_ERR_OK; + } + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_untag_action_set + * Description: + * Configure Action of downstream UnStag packet + * Input: + * action - Action for UnStag + * svid - The SVID assigned to UnStag packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of downstream Un-Stag packet. A SVID assigned + * to the un-stag is also supported by this API. The parameter of svid is + * only referenced when the action is set to UNTAG_ASSIGN + */ +rtk_api_ret_t rtk_svlan_untag_action_set(rtk_svlan_untag_action_t action, rtk_vlan_t svid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (action >= UNTAG_END) + return RT_ERR_OUT_OF_RANGE; + + if(action == UNTAG_ASSIGN) + { + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + } + + if ((retVal = rtl8367c_setAsicSvlanIngressUntag((rtk_uint32)action)) != RT_ERR_OK) + return retVal; + + if(action == UNTAG_ASSIGN) + { + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + if ((retVal = rtl8367c_setAsicSvlanUntagVlan(i)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_untag_action_get + * Description: + * Get Action of downstream UnStag packet + * Input: + * None + * Output: + * pAction - Action for UnStag + * pSvid - The SVID assigned to UnStag packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can Get action of downstream Un-Stag packet. A SVID assigned + * to the un-stag is also retrieved by this API. The parameter pSvid is + * only referenced when the action is UNTAG_ASSIGN + */ +rtk_api_ret_t rtk_svlan_untag_action_get(rtk_svlan_untag_action_t *pAction, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction || NULL == pSvid) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSvlanIngressUntag(pAction)) != RT_ERR_OK) + return retVal; + + if(*pAction == UNTAG_ASSIGN) + { + if ((retVal = rtl8367c_getAsicSvlanUntagVlan(&svidx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + *pSvid = svlanMemConf.vs_svid; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_unmatch_action_set + * Description: + * Configure Action of downstream Unmatch packet + * Input: + * action - Action for Unmatch + * svid - The SVID assigned to Unmatch packet + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of downstream Un-match packet. A SVID assigned + * to the un-match is also supported by this API. The parameter of svid is + * only referenced when the action is set to UNMATCH_ASSIGN + */ +rtk_api_ret_t rtk_svlan_unmatch_action_set(rtk_svlan_unmatch_action_t action, rtk_vlan_t svid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (action >= UNMATCH_END) + return RT_ERR_OUT_OF_RANGE; + + if (action == UNMATCH_ASSIGN) + { + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + } + + if ((retVal = rtl8367c_setAsicSvlanIngressUnmatch((rtk_uint32)action)) != RT_ERR_OK) + return retVal; + + if(action == UNMATCH_ASSIGN) + { + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + if ((retVal = rtl8367c_setAsicSvlanUnmatchVlan(i)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; + } + } + + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_unmatch_action_get + * Description: + * Get Action of downstream Unmatch packet + * Input: + * None + * Output: + * pAction - Action for Unmatch + * pSvid - The SVID assigned to Unmatch packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can Get action of downstream Un-match packet. A SVID assigned + * to the un-match is also retrieved by this API. The parameter pSvid is + * only referenced when the action is UNMATCH_ASSIGN + */ +rtk_api_ret_t rtk_svlan_unmatch_action_get(rtk_svlan_unmatch_action_t *pAction, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction || NULL == pSvid) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSvlanIngressUnmatch(pAction)) != RT_ERR_OK) + return retVal; + + if(*pAction == UNMATCH_ASSIGN) + { + if ((retVal = rtl8367c_getAsicSvlanUnmatchVlan(&svidx)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svidx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + *pSvid = svlanMemConf.vs_svid; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_unassign_action_set + * Description: + * Configure Action of upstream without svid assign action + * Input: + * action - Action for Un-assign + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can configure action of upstream Un-assign svid packet. If action is not + * trap to CPU, the port-based SVID sure be assign as system need + */ +rtk_api_ret_t rtk_svlan_unassign_action_set(rtk_svlan_unassign_action_t action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (action >= UNASSIGN_END) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicSvlanEgressUnassign((rtk_uint32)action); + + return retVal; +} + +/* Function Name: + * rtk_svlan_unassign_action_get + * Description: + * Get action of upstream without svid assignment + * Input: + * None + * Output: + * pAction - Action for Un-assign + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * Note: + * None + */ +rtk_api_ret_t rtk_svlan_unassign_action_get(rtk_svlan_unassign_action_t *pAction) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pAction) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicSvlanEgressUnassign(pAction); + + return retVal; +} + +/* Function Name: + * rtk_svlan_dmac_vidsel_set + * Description: + * Set DMAC CVID selection + * Input: + * port - Port + * enable - state of DMAC CVID Selection + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set DMAC CVID Selection state + */ +rtk_api_ret_t rtk_svlan_dmac_vidsel_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if (enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_dmac_vidsel_get + * Description: + * Get DMAC CVID selection + * Input: + * port - Port + * Output: + * pEnable - state of DMAC CVID Selection + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can get DMAC CVID Selection state + */ +rtk_api_ret_t rtk_svlan_dmac_vidsel_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(port); + + if ((retVal = rtl8367c_getAsicSvlanDmacCvidSel(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_svlan_ipmc2s_add + * Description: + * add ip multicast address to SVLAN + * Input: + * svid - SVLAN VID + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set IP multicast to SVID configuration. If upstream packet is IPv4 multicast + * packet and DIP is matched MC2S configuration, ASIC will assign egress SVID to the packet. + * There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_ipmc2s_add(ipaddr_t ipmc, ipaddr_t ipmcMsk,rtk_vlan_t svid) +{ + rtk_api_ret_t retVal, i; + rtk_uint32 empty_idx; + rtk_uint32 svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + if ((ipmc&0xF0000000)!=0xE0000000) + return RT_ERR_INPUT; + + svidx = 0xFFFF; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + + + empty_idx = 0xFFFF; + + for (i = RTL8367C_MC2SIDXMAX; i >= 0; i--) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid) + { + if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && + svlanMC2SConf.sdata==ipmc&& + svlanMC2SConf.smask==ipmcMsk) + { + svlanMC2SConf.svidx = svidx; + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + } + } + else + { + empty_idx = i; + } + } + + if (empty_idx!=0xFFFF) + { + svlanMC2SConf.valid = TRUE; + svlanMC2SConf.svidx = svidx; + svlanMC2SConf.format = SVLAN_MC2S_MODE_IP; + svlanMC2SConf.sdata = ipmc; + svlanMC2SConf.smask = ipmcMsk; + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + + return RT_ERR_OUT_OF_RANGE; + +} + +/* Function Name: + * rtk_svlan_ipmc2s_del + * Description: + * delete ip multicast address to SVLAN + * Input: + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete IP multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_ipmc2s_del(ipaddr_t ipmc, ipaddr_t ipmcMsk) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((ipmc&0xF0000000)!=0xE0000000) + return RT_ERR_INPUT; + + for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid) + { + if (svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && + svlanMC2SConf.sdata==ipmc&& + svlanMC2SConf.smask==ipmcMsk) + { + memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_ipmc2s_get + * Description: + * Get ip multicast address to SVLAN + * Input: + * ipmc - ip multicast address + * ipmcMsk - ip multicast mask + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get IP multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_ipmc2s_get(ipaddr_t ipmc, ipaddr_t ipmcMsk, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvid) + return RT_ERR_NULL_POINTER; + + if ((ipmc&0xF0000000)!=0xE0000000) + return RT_ERR_INPUT; + + for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid && + svlanMC2SConf.format == SVLAN_MC2S_MODE_IP && + svlanMC2SConf.sdata == ipmc && + svlanMC2SConf.smask == ipmcMsk) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + *pSvid = svlanMemConf.vs_svid; + return RT_ERR_OK; + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_l2mc2s_add + * Description: + * Add L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_SVLAN_ENTRY_NOT_FOUND - specified svlan entry not found. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can set L2 Multicast to SVID configuration. If upstream packet is L2 multicast + * packet and DMAC is matched, ASIC will assign egress SVID to the packet. There are 32 + * SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_l2mc2s_add(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t svid) +{ + rtk_api_ret_t retVal, i; + rtk_uint32 empty_idx; + rtk_uint32 svidx, l2add, l2Mask; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + if (mac.octet[0]!= 1&&mac.octet[1]!=0) + return RT_ERR_INPUT; + + l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; + l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; + + svidx = 0xFFFF; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + + empty_idx = 0xFFFF; + + for (i = RTL8367C_MC2SIDXMAX; i >=0; i--) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid) + { + if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && + svlanMC2SConf.sdata==l2add&& + svlanMC2SConf.smask==l2Mask) + { + svlanMC2SConf.svidx = svidx; + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + } + } + else + { + empty_idx = i; + } + } + + if (empty_idx!=0xFFFF) + { + svlanMC2SConf.valid = TRUE; + svlanMC2SConf.svidx = svidx; + svlanMC2SConf.format = SVLAN_MC2S_MODE_MAC; + svlanMC2SConf.sdata = l2add; + svlanMC2SConf.smask = l2Mask; + + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(empty_idx, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_l2mc2s_del + * Description: + * delete L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete Multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_l2mc2s_del(rtk_mac_t mac, rtk_mac_t macMsk) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtk_uint32 l2add, l2Mask; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (mac.octet[0]!= 1&&mac.octet[1]!=0) + return RT_ERR_INPUT; + + l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; + l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; + + for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid) + { + if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && + svlanMC2SConf.sdata==l2add&& + svlanMC2SConf.smask==l2Mask) + { + memset(&svlanMC2SConf, 0, sizeof(rtl8367c_svlan_mc2s_t)); + if ((retVal = rtl8367c_setAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_l2mc2s_get + * Description: + * Get L2 multicast address to SVLAN + * Input: + * mac - L2 multicast address + * macMsk - L2 multicast address mask + * Output: + * pSvid - SVLAN VID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can get L2 multicast to SVID configuration. There are 32 SVLAN multicast configurations for IP and L2 multicast. + */ +rtk_api_ret_t rtk_svlan_l2mc2s_get(rtk_mac_t mac, rtk_mac_t macMsk, rtk_vlan_t *pSvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtk_uint32 l2add,l2Mask; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_mc2s_t svlanMC2SConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pSvid) + return RT_ERR_NULL_POINTER; + + if (mac.octet[0]!= 1&&mac.octet[1]!=0) + return RT_ERR_INPUT; + + l2add = (mac.octet[2] << 24) | (mac.octet[3] << 16) | (mac.octet[4] << 8) | mac.octet[5]; + l2Mask = (macMsk.octet[2] << 24) | (macMsk.octet[3] << 16) | (macMsk.octet[4] << 8) | macMsk.octet[5]; + + for (i = 0; i <= RTL8367C_MC2SIDXMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMC2SConf(i, &svlanMC2SConf)) != RT_ERR_OK) + return retVal; + + if (TRUE == svlanMC2SConf.valid) + { + if (svlanMC2SConf.format == SVLAN_MC2S_MODE_MAC && + svlanMC2SConf.sdata==l2add&& + svlanMC2SConf.smask==l2Mask) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(svlanMC2SConf.svidx, &svlanMemConf)) != RT_ERR_OK) + return retVal; + *pSvid = svlanMemConf.vs_svid; + + return RT_ERR_OK; + } + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_sp2c_add + * Description: + * Add system SP2C configuration + * Input: + * cvid - VLAN ID + * dst_port - Destination port of SVLAN to CVLAN configuration + * svid - SVLAN VID + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * The API can add SVID & Destination Port to CVLAN configuration. The downstream frames with assigned + * SVID will be add C-tag with assigned CVID if the output port is the assigned destination port. + * There are 128 SP2C configurations. + */ +rtk_api_ret_t rtk_svlan_sp2c_add(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t cvid) +{ + rtk_api_ret_t retVal, i; + rtk_uint32 empty_idx, svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_s2c_t svlanSP2CConf; + rtk_port_t port; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + if (cvid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(dst_port); + port = rtk_switch_port_L2P_get(dst_port); + + svidx = 0xFFFF; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + + empty_idx = 0xFFFF; + + for (i=RTL8367C_SP2CMAX; i >=0 ; i--) + { + if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + + if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == port) && (svlanSP2CConf.valid == 1)) + { + empty_idx = i; + break; + } + else if (svlanSP2CConf.valid == 0) + { + empty_idx = i; + } + } + + if (empty_idx!=0xFFFF) + { + svlanSP2CConf.valid = 1; + svlanSP2CConf.vid = cvid; + svlanSP2CConf.svidx = svidx; + svlanSP2CConf.dstport = port; + + if ((retVal = rtl8367c_setAsicSvlanSP2CConf(empty_idx, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + + return RT_ERR_OUT_OF_RANGE; + +} + +/* Function Name: + * rtk_svlan_sp2c_get + * Description: + * Get configure system SP2C content + * Input: + * svid - SVLAN VID + * dst_port - Destination port of SVLAN to CVLAN configuration + * Output: + * pCvid - VLAN ID + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * Note: + * The API can get SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. + */ +rtk_api_ret_t rtk_svlan_sp2c_get(rtk_vlan_t svid, rtk_port_t dst_port, rtk_vlan_t *pCvid) +{ + rtk_api_ret_t retVal; + rtk_uint32 i, svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_s2c_t svlanSP2CConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pCvid) + return RT_ERR_NULL_POINTER; + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(dst_port); + dst_port = rtk_switch_port_L2P_get(dst_port); + + svidx = 0xFFFF; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + + for (i = 0; i <= RTL8367C_SP2CMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + + if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) ) + { + *pCvid = svlanSP2CConf.vid; + return RT_ERR_OK; + } + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_sp2c_del + * Description: + * Delete system SP2C configuration + * Input: + * svid - SVLAN VID + * dst_port - Destination port of SVLAN to CVLAN configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_SVLAN_VID - Invalid SVLAN VID parameter. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The API can delete SVID & Destination Port to CVLAN configuration. There are 128 SP2C configurations. + */ +rtk_api_ret_t rtk_svlan_sp2c_del(rtk_vlan_t svid, rtk_port_t dst_port) +{ + rtk_api_ret_t retVal; + rtk_uint32 i, svidx; + rtl8367c_svlan_memconf_t svlanMemConf; + rtl8367c_svlan_s2c_t svlanSP2CConf; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (svid > RTL8367C_VIDMAX) + return RT_ERR_SVLAN_VID; + + /* Check port Valid */ + RTK_CHK_PORT_VALID(dst_port); + dst_port = rtk_switch_port_L2P_get(dst_port); + + svidx = 0xFFFF; + + for (i = 0; i < RTL8367C_SVIDXNO; i++) + { + if ((retVal = rtl8367c_getAsicSvlanMemberConfiguration(i, &svlanMemConf)) != RT_ERR_OK) + return retVal; + + if (svid == svlanMemConf.vs_svid) + { + svidx = i; + break; + } + } + + if (0xFFFF == svidx) + return RT_ERR_SVLAN_ENTRY_NOT_FOUND; + + for (i = 0; i <= RTL8367C_SP2CMAX; i++) + { + if ((retVal = rtl8367c_getAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + + if ( (svlanSP2CConf.svidx == svidx) && (svlanSP2CConf.dstport == dst_port) && (svlanSP2CConf.valid == 1) ) + { + svlanSP2CConf.valid = 0; + svlanSP2CConf.vid = 0; + svlanSP2CConf.svidx = 0; + svlanSP2CConf.dstport = 0; + + if ((retVal = rtl8367c_setAsicSvlanSP2CConf(i, &svlanSP2CConf)) != RT_ERR_OK) + return retVal; + return RT_ERR_OK; + } + + } + + return RT_ERR_OUT_OF_RANGE; +} + +/* Function Name: + * rtk_svlan_lookupType_set + * Description: + * Set lookup type of SVLAN + * Input: + * type - lookup type + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * none + */ +rtk_api_ret_t rtk_svlan_lookupType_set(rtk_svlan_lookupType_t type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= SVLAN_LOOKUP_END) + return RT_ERR_CHIP_NOT_SUPPORTED; + + + svlan_lookupType = type; + + retVal = rtl8367c_setAsicSvlanLookupType((rtk_uint32)type); + + return retVal; +} + +/* Function Name: + * rtk_svlan_lookupType_get + * Description: + * Get lookup type of SVLAN + * Input: + * pType - lookup type + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * Note: + * none + */ +rtk_api_ret_t rtk_svlan_lookupType_get(rtk_svlan_lookupType_t *pType) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pType) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicSvlanLookupType(pType); + + svlan_lookupType = *pType; + + return retVal; +} + +/* Function Name: + * rtk_svlan_trapPri_set + * Description: + * Set svlan trap priority + * Input: + * priority - priority for trap packets + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_QOS_INT_PRIORITY + * Note: + * None + */ +rtk_api_ret_t rtk_svlan_trapPri_set(rtk_pri_t priority) +{ + rtk_api_ret_t retVal; + + RTK_CHK_INIT_STATE(); + + if(priority > RTL8367C_PRIMAX) + return RT_ERR_OUT_OF_RANGE; + + retVal = rtl8367c_setAsicSvlanTrapPriority(priority); + + return retVal; +} /* end of rtk_svlan_trapPri_set */ + +/* Function Name: + * rtk_svlan_trapPri_get + * Description: + * Get svlan trap priority + * Input: + * None + * Output: + * pPriority - priority for trap packets + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None + */ +rtk_api_ret_t rtk_svlan_trapPri_get(rtk_pri_t *pPriority) +{ + rtk_api_ret_t retVal; + + RTK_CHK_INIT_STATE(); + + if(NULL == pPriority) + return RT_ERR_NULL_POINTER; + + retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority); + + return retVal; +} /* end of rtk_svlan_trapPri_get */ + + +/* Function Name: + * rtk_svlan_checkAndCreateMbr + * Description: + * Check and create Member configuration and return index + * Input: + * vid - VLAN id. + * Output: + * pIndex - Member configuration index + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VLAN ID. + * RT_ERR_TBL_FULL - Member Configuration table full + * Note: + * + */ +rtk_api_ret_t rtk_svlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex) +{ + rtk_api_ret_t retVal; + rtk_uint32 svidx; + rtk_uint32 empty_idx = 0xFFFF; + rtl8367c_svlan_memconf_t svlan_cfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~4095 */ + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + /* Null pointer check */ + if(NULL == pIndex) + return RT_ERR_NULL_POINTER; + + /* Search exist entry */ + for (svidx = 0; svidx <= RTL8367C_SVIDXMAX; svidx++) + { + if(svlan_mbrCfgUsage[svidx] == TRUE) + { + if(svlan_mbrCfgVid[svidx] == vid) + { + /* Found! return index */ + *pIndex = svidx; + return RT_ERR_OK; + } + } + else if(empty_idx == 0xFFFF) + { + empty_idx = svidx; + } + + } + + if(empty_idx == 0xFFFF) + { + /* No empty index */ + return RT_ERR_TBL_FULL; + } + + svlan_mbrCfgUsage[empty_idx] = TRUE; + svlan_mbrCfgVid[empty_idx] = vid; + + memset(&svlan_cfg, 0, sizeof(rtl8367c_svlan_memconf_t)); + + svlan_cfg.vs_svid = vid; + /*for create check*/ + if(vid == 0) + { + svlan_cfg.vs_efid = 1; + } + + if((retVal = rtl8367c_setAsicSvlanMemberConfiguration(empty_idx, &svlan_cfg)) != RT_ERR_OK) + return retVal; + + *pIndex = empty_idx; + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/trap.c b/drivers/net/phy/rtk/rtl8367c/trap.c new file mode 100644 index 000000000000..af9661058b27 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/trap.c @@ -0,0 +1,1229 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Trap module. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function Name: + * rtk_trap_unknownUnicastPktAction_set + * Description: + * Set unknown unicast packet action configuration. + * Input: + * port - ingress port ID for unknown unicast packet + * ucast_action - Unknown unicast action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + * - UCAST_ACTION_FLOODING + */ +rtk_api_ret_t rtk_trap_unknownUnicastPktAction_set(rtk_port_t port, rtk_trap_ucast_action_t ucast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if (ucast_action >= UCAST_ACTION_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), ucast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unknownUnicastPktAction_get + * Description: + * Get unknown unicast packet action configuration. + * Input: + * port - ingress port ID for unknown unicast packet + * Output: + * pUcast_action - Unknown unicast action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * This API can get unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + * - UCAST_ACTION_FLOODING + */ +rtk_api_ret_t rtk_trap_unknownUnicastPktAction_get(rtk_port_t port, rtk_trap_ucast_action_t *pUcast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if (NULL == pUcast_action) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortUnknownDaBehavior(rtk_switch_port_L2P_get(port), pUcast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unknownMacPktAction_set + * Description: + * Set unknown source MAC packet action configuration. + * Input: + * ucast_action - Unknown source MAC action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +rtk_api_ret_t rtk_trap_unknownMacPktAction_set(rtk_trap_ucast_action_t ucast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (ucast_action >= UCAST_ACTION_FLOODING) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortUnknownSaBehavior(ucast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unknownMacPktAction_get + * Description: + * Get unknown source MAC packet action configuration. + * Input: + * None. + * Output: + * pUcast_action - Unknown source MAC action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null Pointer. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_trap_unknownMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pUcast_action) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortUnknownSaBehavior(pUcast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unmatchMacPktAction_set + * Description: + * Set unmatch source MAC packet action configuration. + * Input: + * ucast_action - Unknown source MAC action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +rtk_api_ret_t rtk_trap_unmatchMacPktAction_set(rtk_trap_ucast_action_t ucast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (ucast_action >= UCAST_ACTION_FLOODING) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortUnmatchedSaBehavior(ucast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unmatchMacPktAction_get + * Description: + * Get unmatch source MAC packet action configuration. + * Input: + * None. + * Output: + * pUcast_action - Unknown source MAC action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * This API can set unknown unicast packet action configuration. + * The unknown unicast action is as following: + * - UCAST_ACTION_FORWARD_PMASK + * - UCAST_ACTION_DROP + * - UCAST_ACTION_TRAP2CPU + */ +rtk_api_ret_t rtk_trap_unmatchMacPktAction_get(rtk_trap_ucast_action_t *pUcast_action) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pUcast_action) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortUnmatchedSaBehavior(pUcast_action)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unmatchMacMoving_set + * Description: + * Set unmatch source MAC packet moving state. + * Input: + * port - Port ID. + * enable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + */ +rtk_api_ret_t rtk_trap_unmatchMacMoving_set(rtk_port_t port, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unmatchMacMoving_get + * Description: + * Set unmatch source MAC packet moving state. + * Input: + * port - Port ID. + * Output: + * pEnable - ENABLED: allow SA moving, DISABLE: don't allow SA moving. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + */ +rtk_api_ret_t rtk_trap_unmatchMacMoving_get(rtk_port_t port, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* check port valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortUnmatchedSaMoving(rtk_switch_port_L2P_get(port), pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unknownMcastPktAction_set + * Description: + * Set behavior of unknown multicast + * Input: + * port - Port id. + * type - unknown multicast packet type. + * mcast_action - unknown multicast action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * When receives an unknown multicast packet, switch may trap, drop or flood this packet + * (1) The unknown multicast packet type is as following: + * - MCAST_L2 + * - MCAST_IPV4 + * - MCAST_IPV6 + * (2) The unknown multicast action is as following: + * - MCAST_ACTION_FORWARD + * - MCAST_ACTION_DROP + * - MCAST_ACTION_TRAP2CPU + */ +rtk_api_ret_t rtk_trap_unknownMcastPktAction_set(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t mcast_action) +{ + rtk_api_ret_t retVal; + rtk_uint32 rawAction; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (type >= MCAST_END) + return RT_ERR_INPUT; + + if (mcast_action >= MCAST_ACTION_END) + return RT_ERR_INPUT; + + + switch (type) + { + case MCAST_L2: + if (MCAST_ACTION_ROUTER_PORT == mcast_action) + return RT_ERR_INPUT; + else if(MCAST_ACTION_DROP_EX_RMA == mcast_action) + rawAction = L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA; + else + rawAction = (rtk_uint32)mcast_action; + + if ((retVal = rtl8367c_setAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) + return retVal; + + break; + case MCAST_IPV4: + if (MCAST_ACTION_DROP_EX_RMA == mcast_action) + return RT_ERR_INPUT; + else + rawAction = (rtk_uint32)mcast_action; + + if ((retVal = rtl8367c_setAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) + return retVal; + + break; + case MCAST_IPV6: + if (MCAST_ACTION_DROP_EX_RMA == mcast_action) + return RT_ERR_INPUT; + else + rawAction = (rtk_uint32)mcast_action; + + if ((retVal = rtl8367c_setAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), rawAction)) != RT_ERR_OK) + return retVal; + + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_unknownMcastPktAction_get + * Description: + * Get behavior of unknown multicast + * Input: + * type - unknown multicast packet type. + * Output: + * pMcast_action - unknown multicast action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_NOT_ALLOWED - Invalid operation. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * When receives an unknown multicast packet, switch may trap, drop or flood this packet + * (1) The unknown multicast packet type is as following: + * - MCAST_L2 + * - MCAST_IPV4 + * - MCAST_IPV6 + * (2) The unknown multicast action is as following: + * - MCAST_ACTION_FORWARD + * - MCAST_ACTION_DROP + * - MCAST_ACTION_TRAP2CPU + */ +rtk_api_ret_t rtk_trap_unknownMcastPktAction_get(rtk_port_t port, rtk_mcast_type_t type, rtk_trap_mcast_action_t *pMcast_action) +{ + rtk_api_ret_t retVal; + rtk_uint32 rawAction; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (type >= MCAST_END) + return RT_ERR_INPUT; + + if(NULL == pMcast_action) + return RT_ERR_NULL_POINTER; + + switch (type) + { + case MCAST_L2: + if ((retVal = rtl8367c_getAsicUnknownL2MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) + return retVal; + + if(L2_UNKOWN_MULTICAST_DROP_EXCLUDE_RMA == rawAction) + *pMcast_action = MCAST_ACTION_DROP_EX_RMA; + else + *pMcast_action = (rtk_trap_mcast_action_t)rawAction; + + break; + case MCAST_IPV4: + if ((retVal = rtl8367c_getAsicUnknownIPv4MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) + return retVal; + + *pMcast_action = (rtk_trap_mcast_action_t)rawAction; + break; + case MCAST_IPV6: + if ((retVal = rtl8367c_getAsicUnknownIPv6MulticastBehavior(rtk_switch_port_L2P_get(port), &rawAction)) != RT_ERR_OK) + return retVal; + + *pMcast_action = (rtk_trap_mcast_action_t)rawAction; + break; + default: + break; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_lldpEnable_set + * Description: + * Set LLDP enable. + * Input: + * enabled - LLDP enable, 0: follow RMA, 1: use LLDP action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NOT_ALLOWED - Invalid action. + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * - DMAC Assignment + * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP + * - 01:80:c2:00:00:03 ethertype = 0x88CC + * - 01:80:c2:00:00:00 ethertype = 0x88CC + + */ +rtk_api_ret_t rtk_trap_lldpEnable_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_enable_t tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (enabled >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicRmaLldp(enabled, &rmacfg)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_lldpEnable_get + * Description: + * Get LLDP status. + * Input: + * None + * Output: + * pEnabled - LLDP enable, 0: follow RMA, 1: use LLDP action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * LLDP is as following definition. + * - DMAC Assignment + * - 01:80:c2:00:00:0e ethertype = 0x88CC LLDP + * - 01:80:c2:00:00:03 ethertype = 0x88CC + * - 01:80:c2:00:00:00 ethertype = 0x88CC + */ +rtk_api_ret_t rtk_trap_lldpEnable_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicRmaLldp(pEnabled, &rmacfg)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_reasonTrapToCpuPriority_set + * Description: + * Set priority value of a packet that trapped to CPU port according to specific reason. + * Input: + * type - reason that trap to CPU port. + * priority - internal priority that is going to be set for specific trap reason. + * Output: + * None. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - Invalid input parameter + * Note: + * Currently the trap reason that supported are listed as follows: + * - TRAP_REASON_RMA + * - TRAP_REASON_OAM + * - TRAP_REASON_1XUNAUTH + * - TRAP_REASON_VLANSTACK + * - TRAP_REASON_UNKNOWNMC + */ +rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_set(rtk_trap_reason_type_t type, rtk_pri_t priority) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_REASON_END) + return RT_ERR_INPUT; + + if (priority > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + switch (type) + { + case TRAP_REASON_RMA: + if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK) + return retVal; + rmacfg.trap_priority= priority; + if ((retVal = rtl8367c_setAsicRma(0, &rmacfg)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_OAM: + if ((retVal = rtl8367c_setAsicOamCpuPri(priority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_1XUNAUTH: + if ((retVal = rtl8367c_setAsic1xTrapPriority(priority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_VLANSTACK: + if ((retVal = rtl8367c_setAsicSvlanTrapPriority(priority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_UNKNOWNMC: + if ((retVal = rtl8367c_setAsicUnknownMulticastTrapPriority(priority)) != RT_ERR_OK) + return retVal; + + break; + default: + return RT_ERR_CHIP_NOT_SUPPORTED; + } + + + return RT_ERR_OK; +} + + +/* Function Name: + * rtk_trap_reasonTrapToCpuPriority_get + * Description: + * Get priority value of a packet that trapped to CPU port according to specific reason. + * Input: + * type - reason that trap to CPU port. + * Output: + * pPriority - configured internal priority for such reason. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_INIT - The module is not initial + * RT_ERR_INPUT - Invalid input parameter + * RT_ERR_NULL_POINTER - NULL pointer + * Note: + * Currently the trap reason that supported are listed as follows: + * - TRAP_REASON_RMA + * - TRAP_REASON_OAM + * - TRAP_REASON_1XUNAUTH + * - TRAP_REASON_VLANSTACK + * - TRAP_REASON_UNKNOWNMC + */ +rtk_api_ret_t rtk_trap_reasonTrapToCpuPriority_get(rtk_trap_reason_type_t type, rtk_pri_t *pPriority) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_REASON_END) + return RT_ERR_INPUT; + + if(NULL == pPriority) + return RT_ERR_NULL_POINTER; + + switch (type) + { + case TRAP_REASON_RMA: + if ((retVal = rtl8367c_getAsicRma(0, &rmacfg)) != RT_ERR_OK) + return retVal; + *pPriority = rmacfg.trap_priority; + + break; + case TRAP_REASON_OAM: + if ((retVal = rtl8367c_getAsicOamCpuPri(pPriority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_1XUNAUTH: + if ((retVal = rtl8367c_getAsic1xTrapPriority(pPriority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_VLANSTACK: + if ((retVal = rtl8367c_getAsicSvlanTrapPriority(pPriority)) != RT_ERR_OK) + return retVal; + + break; + case TRAP_REASON_UNKNOWNMC: + if ((retVal = rtl8367c_getAsicUnknownMulticastTrapPriority(pPriority)) != RT_ERR_OK) + return retVal; + + break; + default: + return RT_ERR_CHIP_NOT_SUPPORTED; + + } + + return RT_ERR_OK; +} + + + +/* Function Name: + * rtk_trap_rmaAction_set + * Description: + * Set Reserved multicast address action configuration. + * Input: + * type - rma type. + * rma_action - RMA action. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * + * There are 48 types of Reserved Multicast Address frame for application usage. + * (1)They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + * (2) The RMA action is as following: + * - RMA_ACTION_FORWARD + * - RMA_ACTION_TRAP2CPU + * - RMA_ACTION_DROP + * - RMA_ACTION_FORWARD_EXCLUDE_CPU + */ +rtk_api_ret_t rtk_trap_rmaAction_set(rtk_trap_type_t type, rtk_trap_rma_action_t rma_action) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_END) + return RT_ERR_INPUT; + + if (rma_action >= RMA_ACTION_END) + return RT_ERR_RMA_ACTION; + + if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.operation = rma_action; + + if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.operation = rma_action; + + if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.operation = rma_action; + + if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.operation = rma_action; + + if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_rmaAction_get + * Description: + * Get Reserved multicast address action configuration. + * Input: + * type - rma type. + * Output: + * pRma_action - RMA action. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 48 types of Reserved Multicast Address frame for application usage. + * (1)They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + * (2) The RMA action is as following: + * - RMA_ACTION_FORWARD + * - RMA_ACTION_TRAP2CPU + * - RMA_ACTION_DROP + * - RMA_ACTION_FORWARD_EXCLUDE_CPU + */ +rtk_api_ret_t rtk_trap_rmaAction_get(rtk_trap_type_t type, rtk_trap_rma_action_t *pRma_action) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_END) + return RT_ERR_INPUT; + + if(NULL == pRma_action) + return RT_ERR_NULL_POINTER; + + if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pRma_action = rmacfg.operation; + } + else if (type == TRAP_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pRma_action = rmacfg.operation; + } + else if (type == TRAP_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pRma_action = rmacfg.operation; + } + else if (type == TRAP_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) + return retVal; + + *pRma_action = rmacfg.operation; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_rmaKeepFormat_set + * Description: + * Set Reserved multicast address keep format configuration. + * Input: + * type - rma type. + * enable - enable keep format. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_ENABLE - Invalid IFG parameter + * Note: + * + * There are 48 types of Reserved Multicast Address frame for application usage. + * They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + */ +rtk_api_ret_t rtk_trap_rmaKeepFormat_set(rtk_trap_type_t type, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_END) + return RT_ERR_INPUT; + + if (enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.keep_format = enable; + + if ((retVal = rtl8367c_setAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.keep_format = enable; + + if ((retVal = rtl8367c_setAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.keep_format = enable; + + if ((retVal = rtl8367c_setAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + } + else if (type == TRAP_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + + rmacfg.keep_format = enable; + + if ((retVal = rtl8367c_setAsicRmaLldp(tmp, &rmacfg)) != RT_ERR_OK) + return retVal; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trap_rmaKeepFormat_get + * Description: + * Get Reserved multicast address action configuration. + * Input: + * type - rma type. + * Output: + * pEnable - keep format status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * Note: + * There are 48 types of Reserved Multicast Address frame for application usage. + * They are as following definition. + * - TRAP_BRG_GROUP, + * - TRAP_FD_PAUSE, + * - TRAP_SP_MCAST, + * - TRAP_1X_PAE, + * - TRAP_UNDEF_BRG_04, + * - TRAP_UNDEF_BRG_05, + * - TRAP_UNDEF_BRG_06, + * - TRAP_UNDEF_BRG_07, + * - TRAP_PROVIDER_BRIDGE_GROUP_ADDRESS, + * - TRAP_UNDEF_BRG_09, + * - TRAP_UNDEF_BRG_0A, + * - TRAP_UNDEF_BRG_0B, + * - TRAP_UNDEF_BRG_0C, + * - TRAP_PROVIDER_BRIDGE_GVRP_ADDRESS, + * - TRAP_8021AB, + * - TRAP_UNDEF_BRG_0F, + * - TRAP_BRG_MNGEMENT, + * - TRAP_UNDEFINED_11, + * - TRAP_UNDEFINED_12, + * - TRAP_UNDEFINED_13, + * - TRAP_UNDEFINED_14, + * - TRAP_UNDEFINED_15, + * - TRAP_UNDEFINED_16, + * - TRAP_UNDEFINED_17, + * - TRAP_UNDEFINED_18, + * - TRAP_UNDEFINED_19, + * - TRAP_UNDEFINED_1A, + * - TRAP_UNDEFINED_1B, + * - TRAP_UNDEFINED_1C, + * - TRAP_UNDEFINED_1D, + * - TRAP_UNDEFINED_1E, + * - TRAP_UNDEFINED_1F, + * - TRAP_GMRP, + * - TRAP_GVRP, + * - TRAP_UNDEF_GARP_22, + * - TRAP_UNDEF_GARP_23, + * - TRAP_UNDEF_GARP_24, + * - TRAP_UNDEF_GARP_25, + * - TRAP_UNDEF_GARP_26, + * - TRAP_UNDEF_GARP_27, + * - TRAP_UNDEF_GARP_28, + * - TRAP_UNDEF_GARP_29, + * - TRAP_UNDEF_GARP_2A, + * - TRAP_UNDEF_GARP_2B, + * - TRAP_UNDEF_GARP_2C, + * - TRAP_UNDEF_GARP_2D, + * - TRAP_UNDEF_GARP_2E, + * - TRAP_UNDEF_GARP_2F, + * - TRAP_CDP. + * - TRAP_CSSTP. + * - TRAP_LLDP. + */ +rtk_api_ret_t rtk_trap_rmaKeepFormat_get(rtk_trap_type_t type, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtl8367c_rma_t rmacfg; + rtk_uint32 tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (type >= TRAP_END) + return RT_ERR_INPUT; + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if (type >= 0 && type <= TRAP_UNDEF_GARP_2F) + { + if ((retVal = rtl8367c_getAsicRma(type, &rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.keep_format; + } + else if (type == TRAP_CDP) + { + if ((retVal = rtl8367c_getAsicRmaCdp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.keep_format; + } + else if (type == TRAP_CSSTP) + { + if ((retVal = rtl8367c_getAsicRmaCsstp(&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.keep_format; + } + else if (type == TRAP_LLDP) + { + if ((retVal = rtl8367c_getAsicRmaLldp(&tmp,&rmacfg)) != RT_ERR_OK) + return retVal; + + *pEnable = rmacfg.keep_format; + } + else + return RT_ERR_INPUT; + + return RT_ERR_OK; +} + + + diff --git a/drivers/net/phy/rtk/rtl8367c/trunk.c b/drivers/net/phy/rtk/rtl8367c/trunk.c new file mode 100644 index 000000000000..8a88dc5ff000 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/trunk.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in Trunk module. + * + */ + +#include +#include +#include +#include + +#include +#include + +/* Function Name: + * rtk_trunk_port_set + * Description: + * Set trunking group available port mask + * Input: + * trk_gid - trunk group id + * pTrunk_member_portmask - Logic trunking member port mask + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API can set port trunking group port mask. Each port trunking group has max 4 ports. + * If enabled port mask has less than 2 ports available setting, then this trunking group function is disabled. + */ +rtk_api_ret_t rtk_trunk_port_set(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + rtk_uint32 regValue, type, tmp; + + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0249)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_getAsicReg(0x1300, ®Value)) != RT_ERR_OK) + return retVal; + + if((retVal = rtl8367c_setAsicReg(0x13C2, 0x0000)) != RT_ERR_OK) + return retVal; + + switch (regValue) + { + case 0x0276: + case 0x0597: + case 0x6367: + type = 0; + break; + case 0x0652: + case 0x6368: + type = 1; + break; + case 0x0801: + case 0x6511: + type = 2; + break; + default: + return RT_ERR_FAILED; + } + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if(NULL == pTrunk_member_portmask) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pTrunk_member_portmask); + + if((retVal = rtk_switch_portmask_L2P_get(pTrunk_member_portmask, &pmsk)) != RT_ERR_OK) + return retVal; + + if((type == 0) || (type == 1)) + { + if ((pmsk | RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) != (rtk_uint32)RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) + return RT_ERR_PORT_MASK; + + pmsk = (pmsk & RTL8367C_PORT_TRUNK_GROUP_MASK_MASK(trk_gid)) >> RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid); + } + else if(type == 2) + { + tmp = 0; + + if(pmsk & 0x2) + tmp |= 1; + if(pmsk & 0x8) + tmp |=2; + if(pmsk & 0x80) + tmp |=8; + + pmsk = tmp; + } + + if ((retVal = rtl8367c_setAsicTrunkingGroup(trk_gid, pmsk)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_port_get + * Description: + * Get trunking group available port mask + * Input: + * trk_gid - trunk group id + * Output: + * pTrunk_member_portmask - Logic trunking member port mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * Note: + * The API can get 2 port trunking group. + */ +rtk_api_ret_t rtk_trunk_port_get(rtk_trunk_group_t trk_gid, rtk_portmask_t *pTrunk_member_portmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmsk; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if ((retVal = rtl8367c_getAsicTrunkingGroup(trk_gid, &pmsk)) != RT_ERR_OK) + return retVal; + + pmsk = pmsk << RTL8367C_PORT_TRUNK_GROUP_MASK_OFFSET(trk_gid); + + if((retVal = rtk_switch_portmask_P2L_get(pmsk, pTrunk_member_portmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_distributionAlgorithm_set + * Description: + * Set port trunking hash select sources + * Input: + * trk_gid - trunk group id + * algo_bitmask - Bitmask of the distribution algorithm + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * RT_ERR_LA_HASHMASK - Hash algorithm selection error. + * RT_ERR_PORT_MASK - Invalid portmask. + * Note: + * The API can set port trunking hash algorithm sources. + * 7 bits mask for link aggregation group0 hash parameter selection {DIP, SIP, DMAC, SMAC, SPA} + * - 0b0000001: SPA + * - 0b0000010: SMAC + * - 0b0000100: DMAC + * - 0b0001000: SIP + * - 0b0010000: DIP + * - 0b0100000: TCP/UDP Source Port + * - 0b1000000: TCP/UDP Destination Port + * Example: + * - 0b0000011: SMAC & SPA + * - Note that it could be an arbitrary combination or independent set + */ +rtk_api_ret_t rtk_trunk_distributionAlgorithm_set(rtk_trunk_group_t trk_gid, rtk_uint32 algo_bitmask) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (trk_gid != RTK_WHOLE_SYSTEM) + return RT_ERR_LA_TRUNK_ID; + + if (algo_bitmask >= 128) + return RT_ERR_LA_HASHMASK; + + if ((retVal = rtl8367c_setAsicTrunkingHashSelect(algo_bitmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_distributionAlgorithm_get + * Description: + * Get port trunking hash select sources + * Input: + * trk_gid - trunk group id + * Output: + * pAlgo_bitmask - Bitmask of the distribution algorithm + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_LA_TRUNK_ID - Invalid trunking group + * Note: + * The API can get port trunking hash algorithm sources. + */ +rtk_api_ret_t rtk_trunk_distributionAlgorithm_get(rtk_trunk_group_t trk_gid, rtk_uint32 *pAlgo_bitmask) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (trk_gid != RTK_WHOLE_SYSTEM) + return RT_ERR_LA_TRUNK_ID; + + if(NULL == pAlgo_bitmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicTrunkingHashSelect((rtk_uint32 *)pAlgo_bitmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_trafficSeparate_set + * Description: + * Set the traffic separation setting of a trunk group from the specified device. + * Input: + * trk_gid - trunk group id + * separateType - traffic separation setting + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_LA_HASHMASK - invalid hash mask + * Note: + * SEPARATE_NONE: disable traffic separation + * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic + */ +rtk_api_ret_t rtk_trunk_trafficSeparate_set(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t separateType) +{ + rtk_api_ret_t retVal; + rtk_uint32 enabled; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (trk_gid != RTK_WHOLE_SYSTEM) + return RT_ERR_LA_TRUNK_ID; + + if(separateType >= SEPARATE_END) + return RT_ERR_INPUT; + + enabled = (separateType == SEPARATE_FLOOD) ? ENABLED : DISABLED; + if ((retVal = rtl8367c_setAsicTrunkingFlood(enabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_trafficSeparate_get + * Description: + * Get the traffic separation setting of a trunk group from the specified device. + * Input: + * trk_gid - trunk group id + * Output: + * pSeparateType - pointer separated traffic type + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * SEPARATE_NONE: disable traffic separation + * SEPARATE_FLOOD: trunk MSB link up port is dedicated to TX flooding (L2 lookup miss) traffic + */ +rtk_api_ret_t rtk_trunk_trafficSeparate_get(rtk_trunk_group_t trk_gid, rtk_trunk_separateType_t *pSeparateType) +{ + rtk_api_ret_t retVal; + rtk_uint32 enabled; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if (trk_gid != RTK_WHOLE_SYSTEM) + return RT_ERR_LA_TRUNK_ID; + + if(NULL == pSeparateType) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicTrunkingFlood(&enabled)) != RT_ERR_OK) + return retVal; + + *pSeparateType = (enabled == ENABLED) ? SEPARATE_FLOOD : SEPARATE_NONE; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_mode_set + * Description: + * Set the trunk mode to the specified device. + * Input: + * mode - trunk mode + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_INPUT - invalid input parameter + * Note: + * The enum of the trunk mode as following + * - TRUNK_MODE_NORMAL + * - TRUNK_MODE_DUMB + */ +rtk_api_ret_t rtk_trunk_mode_set(rtk_trunk_mode_t mode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(mode >= TRUNK_MODE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicTrunkingMode((rtk_uint32)mode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_mode_get + * Description: + * Get the trunk mode from the specified device. + * Input: + * None + * Output: + * pMode - pointer buffer of trunk mode + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * The enum of the trunk mode as following + * - TRUNK_MODE_NORMAL + * - TRUNK_MODE_DUMB + */ +rtk_api_ret_t rtk_trunk_mode_get(rtk_trunk_mode_t *pMode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pMode) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicTrunkingMode((rtk_uint32 *)pMode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_trafficPause_set + * Description: + * Set the traffic pause setting of a trunk group. + * Input: + * trk_gid - trunk group id + * enable - traffic pause state + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * Note: + * None. + */ +rtk_api_ret_t rtk_trunk_trafficPause_set(rtk_trunk_group_t trk_gid, rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if(enable >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32)enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_trafficPause_get + * Description: + * Get the traffic pause setting of a trunk group. + * Input: + * trk_gid - trunk group id + * Output: + * pEnable - pointer of traffic pause state. + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None. + */ +rtk_api_ret_t rtk_trunk_trafficPause_get(rtk_trunk_group_t trk_gid, rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicTrunkingFc((rtk_uint32)trk_gid, (rtk_uint32 *)pEnable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_hashMappingTable_set + * Description: + * Set hash value to port array in the trunk group id from the specified device. + * Input: + * trk_gid - trunk group id + * pHash2Port_array - ports associate with the hash value + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * RT_ERR_LA_TRUNK_NOT_EXIST - the trunk doesn't exist + * RT_ERR_LA_NOT_MEMBER_PORT - the port is not a member port of the trunk + * RT_ERR_LA_CPUPORT - CPU port can not be aggregated port + * Note: + * Trunk group 0 & 1 shares the same hash mapping table. + * Trunk group 2 uses a independent table. + */ +rtk_api_ret_t rtk_trunk_hashMappingTable_set(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array) +{ + rtk_api_ret_t retVal; + rtk_uint32 hashValue; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if(NULL == pHash2Port_array) + return RT_ERR_NULL_POINTER; + + if(trk_gid <= TRUNK_GROUP1) + { + for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) + { + if ((retVal = rtl8367c_setAsicTrunkingHashTable(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK) + return retVal; + } + } + else + { + for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) + { + if ((retVal = rtl8367c_setAsicTrunkingHashTable1(hashValue, pHash2Port_array->value[hashValue])) != RT_ERR_OK) + return retVal; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_hashMappingTable_get + * Description: + * Get hash value to port array in the trunk group id from the specified device. + * Input: + * trk_gid - trunk group id + * Output: + * pHash2Port_array - pointer buffer of ports associate with the hash value + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_UNIT_ID - invalid unit id + * RT_ERR_LA_TRUNK_ID - invalid trunk ID + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * Trunk group 0 & 1 shares the same hash mapping table. + * Trunk group 2 uses a independent table. + */ +rtk_api_ret_t rtk_trunk_hashMappingTable_get(rtk_trunk_group_t trk_gid, rtk_trunk_hashVal2Port_t *pHash2Port_array) +{ + rtk_api_ret_t retVal; + rtk_uint32 hashValue; + rtk_uint32 hashPort; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Trunk Group Valid */ + RTK_CHK_TRUNK_GROUP_VALID(trk_gid); + + if(NULL == pHash2Port_array) + return RT_ERR_NULL_POINTER; + + if(trk_gid <= TRUNK_GROUP1) + { + for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) + { + if ((retVal = rtl8367c_getAsicTrunkingHashTable(hashValue, &hashPort)) != RT_ERR_OK) + return retVal; + + pHash2Port_array->value[hashValue] = hashPort; + } + } + else + { + for(hashValue = 0; hashValue < RTK_MAX_NUM_OF_TRUNK_HASH_VAL; hashValue++) + { + if ((retVal = rtl8367c_getAsicTrunkingHashTable1(hashValue, &hashPort)) != RT_ERR_OK) + return retVal; + + pHash2Port_array->value[hashValue] = hashPort; + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_trunk_portQueueEmpty_get + * Description: + * Get the port mask which all queues are empty. + * Input: + * None. + * Output: + * pEmpty_portmask - pointer empty port mask + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NULL_POINTER - input parameter may be null pointer + * Note: + * None. + */ +rtk_api_ret_t rtk_trunk_portQueueEmpty_get(rtk_portmask_t *pEmpty_portmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEmpty_portmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicQeueuEmptyStatus(&pmask)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtk_switch_portmask_P2L_get(pmask, pEmpty_portmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367c/vlan.c b/drivers/net/phy/rtk/rtl8367c/vlan.c new file mode 100644 index 000000000000..b407c3008cd0 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367c/vlan.c @@ -0,0 +1,2124 @@ +/* + * Copyright (C) 2013 Realtek Semiconductor Corp. + * All Rights Reserved. + * + * Unless you and Realtek execute a separate written software license + * agreement governing use of this software, this software is licensed + * to you under the terms of the GNU General Public License version 2, + * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + * + * $Revision: 76306 $ + * $Date: 2017-03-08 15:13:58 +0800 (週三, 08 三月 2017) $ + * + * Purpose : RTK switch high-level API for RTL8367/RTL8367C + * Feature : Here is a list of all functions and variables in VLAN module. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef enum vlan_mbrCfgType_e +{ + MBRCFG_UNUSED = 0, + MBRCFG_USED_BY_VLAN, + MBRCFG_END +}vlan_mbrCfgType_t; + +static rtk_vlan_t vlan_mbrCfgVid[RTL8367C_CVIDXNO]; +static vlan_mbrCfgType_t vlan_mbrCfgUsage[RTL8367C_CVIDXNO]; + +/* Function Name: + * rtk_vlan_init + * Description: + * Initialize VLAN. + * Input: + * None + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * Note: + * VLAN is disabled by default. User has to call this API to enable VLAN before + * using it. And It will set a default VLAN(vid 1) including all ports and set + * all ports PVID to the default VLAN. + */ +rtk_api_ret_t rtk_vlan_init(void) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtl8367c_user_vlan4kentry vlan4K; + rtl8367c_vlanconfiguser vlanMC; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Clean Database */ + memset(vlan_mbrCfgVid, 0x00, sizeof(rtk_vlan_t) * RTL8367C_CVIDXNO); + memset(vlan_mbrCfgUsage, 0x00, sizeof(vlan_mbrCfgType_t) * RTL8367C_CVIDXNO); + + /* clean 32 VLAN member configuration */ + for (i = 0; i <= RTL8367C_CVIDXMAX; i++) + { + vlanMC.evid = 0; + vlanMC.mbr = 0; + vlanMC.fid_msti = 0; + vlanMC.envlanpol = 0; + vlanMC.meteridx = 0; + vlanMC.vbpen = 0; + vlanMC.vbpri = 0; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(i, &vlanMC)) != RT_ERR_OK) + return retVal; + } + + /* Set a default VLAN with vid 1 to 4K table for all ports */ + memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry)); + vlan4K.vid = 1; + vlan4K.mbr = RTK_PHY_PORTMASK_ALL; + vlan4K.untag = RTK_PHY_PORTMASK_ALL; + vlan4K.fid_msti = 0; + if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + /* Also set the default VLAN to 32 member configuration index 0 */ + memset(&vlanMC, 0, sizeof(rtl8367c_vlanconfiguser)); + vlanMC.evid = 1; + vlanMC.mbr = RTK_PHY_PORTMASK_ALL; + vlanMC.fid_msti = 0; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(0, &vlanMC)) != RT_ERR_OK) + return retVal; + + /* Set all ports PVID to default VLAN and tag-mode to original */ + RTK_SCAN_ALL_PHY_PORTMASK(i) + { + if ((retVal = rtl8367c_setAsicVlanPortBasedVID(i, 0, 0)) != RT_ERR_OK) + return retVal; + if ((retVal = rtl8367c_setAsicVlanEgressTagMode(i, EG_TAG_MODE_ORI)) != RT_ERR_OK) + return retVal; + } + + /* Update Database */ + vlan_mbrCfgUsage[0] = MBRCFG_USED_BY_VLAN; + vlan_mbrCfgVid[0] = 1; + + /* Enable Ingress filter */ + RTK_SCAN_ALL_PHY_PORTMASK(i) + { + if ((retVal = rtl8367c_setAsicVlanIngressFilter(i, ENABLED)) != RT_ERR_OK) + return retVal; + } + + /* enable VLAN */ + if ((retVal = rtl8367c_setAsicVlanFilter(ENABLED)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_set + * Description: + * Set a VLAN entry. + * Input: + * vid - VLAN ID to configure. + * pVlanCfg - VLAN Configuration + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_L2_FID - Invalid FID. + * RT_ERR_VLAN_PORT_MBR_EXIST - Invalid member port mask. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * + */ +rtk_api_ret_t rtk_vlan_set(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyMbrPmask; + rtk_uint32 phyUntagPmask; + rtl8367c_user_vlan4kentry vlan4K; + rtl8367c_vlanconfiguser vlanMC; + rtk_uint32 idx; + rtk_uint32 empty_index = 0xffff; + rtk_uint32 update_evid = 0; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~8191 */ + if (vid > RTL8367C_EVIDMAX) + return RT_ERR_VLAN_VID; + + /* Null pointer check */ + if(NULL == pVlanCfg) + return RT_ERR_NULL_POINTER; + + /* Check port mask valid */ + RTK_CHK_PORTMASK_VALID(&(pVlanCfg->mbr)); + + if (vid <= RTL8367C_VIDMAX) + { + /* Check untag port mask valid */ + RTK_CHK_PORTMASK_VALID(&(pVlanCfg->untag)); + } + + /* IVL_EN */ + if(pVlanCfg->ivl_en >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + /* fid must be 0~15 */ + if(pVlanCfg->fid_msti > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + /* Policing */ + if(pVlanCfg->envlanpol >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + /* Meter ID */ + if(pVlanCfg->meteridx > RTK_MAX_METER_ID) + return RT_ERR_INPUT; + + /* VLAN based priority */ + if(pVlanCfg->vbpen >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + /* Priority */ + if(pVlanCfg->vbpri > RTL8367C_PRIMAX) + return RT_ERR_INPUT; + + /* Get physical port mask */ + if(rtk_switch_portmask_L2P_get(&(pVlanCfg->mbr), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + if(rtk_switch_portmask_L2P_get(&(pVlanCfg->untag), &phyUntagPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + if (vid <= RTL8367C_VIDMAX) + { + /* update 4K table */ + memset(&vlan4K, 0, sizeof(rtl8367c_user_vlan4kentry)); + vlan4K.vid = vid; + + vlan4K.mbr = (phyMbrPmask & 0xFFFF); + vlan4K.untag = (phyUntagPmask & 0xFFFF); + + vlan4K.ivl_svl = pVlanCfg->ivl_en; + vlan4K.fid_msti = pVlanCfg->fid_msti; + vlan4K.envlanpol = pVlanCfg->envlanpol; + vlan4K.meteridx = pVlanCfg->meteridx; + vlan4K.vbpen = pVlanCfg->vbpen; + vlan4K.vbpri = pVlanCfg->vbpri; + + if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + /* Update Member configuration if exist */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) + { + if(vlan_mbrCfgVid[idx] == vid) + { + /* Found! Update */ + if(phyMbrPmask == 0x00) + { + /* Member port = 0x00, delete this VLAN from Member Configuration */ + memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); + if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + + /* Clear Database */ + vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; + vlan_mbrCfgVid[idx] = 0; + } + else + { + /* Normal VLAN config, update to member configuration */ + vlanMC.evid = vid; + vlanMC.mbr = vlan4K.mbr; + vlanMC.fid_msti = vlan4K.fid_msti; + vlanMC.meteridx = vlan4K.meteridx; + vlanMC.envlanpol= vlan4K.envlanpol; + vlanMC.vbpen = vlan4K.vbpen; + vlanMC.vbpri = vlan4K.vbpri; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + } + + break; + } + } + } + } + else + { + /* vid > 4095 */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) + { + if(vlan_mbrCfgVid[idx] == vid) + { + /* Found! Update */ + if(phyMbrPmask == 0x00) + { + /* Member port = 0x00, delete this VLAN from Member Configuration */ + memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); + if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + + /* Clear Database */ + vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; + vlan_mbrCfgVid[idx] = 0; + } + else + { + /* Normal VLAN config, update to member configuration */ + vlanMC.evid = vid; + vlanMC.mbr = phyMbrPmask; + vlanMC.fid_msti = pVlanCfg->fid_msti; + vlanMC.meteridx = pVlanCfg->meteridx; + vlanMC.envlanpol= pVlanCfg->envlanpol; + vlanMC.vbpen = pVlanCfg->vbpen; + vlanMC.vbpri = pVlanCfg->vbpri; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + + break; + } + + update_evid = 1; + } + } + + if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED) + { + if(0xffff == empty_index) + empty_index = idx; + } + } + + /* doesn't find out same EVID entry and there is empty index in member configuration */ + if( (phyMbrPmask != 0x00) && (update_evid == 0) && (empty_index != 0xFFFF) ) + { + vlanMC.evid = vid; + vlanMC.mbr = phyMbrPmask; + vlanMC.fid_msti = pVlanCfg->fid_msti; + vlanMC.meteridx = pVlanCfg->meteridx; + vlanMC.envlanpol= pVlanCfg->envlanpol; + vlanMC.vbpen = pVlanCfg->vbpen; + vlanMC.vbpri = pVlanCfg->vbpri; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_index, &vlanMC)) != RT_ERR_OK) + return retVal; + + vlan_mbrCfgUsage[empty_index] = MBRCFG_USED_BY_VLAN; + vlan_mbrCfgVid[empty_index] = vid; + + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_get + * Description: + * Get a VLAN entry. + * Input: + * vid - VLAN ID to configure. + * Output: + * pVlanCfg - VLAN Configuration + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * + */ +rtk_api_ret_t rtk_vlan_get(rtk_vlan_t vid, rtk_vlan_cfg_t *pVlanCfg) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyMbrPmask; + rtk_uint32 phyUntagPmask; + rtl8367c_user_vlan4kentry vlan4K; + rtl8367c_vlanconfiguser vlanMC; + rtk_uint32 idx; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~8191 */ + if (vid > RTL8367C_EVIDMAX) + return RT_ERR_VLAN_VID; + + /* Null pointer check */ + if(NULL == pVlanCfg) + return RT_ERR_NULL_POINTER; + + if (vid <= RTL8367C_VIDMAX) + { + vlan4K.vid = vid; + + if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + phyMbrPmask = vlan4K.mbr; + phyUntagPmask = vlan4K.untag; + if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK) + return RT_ERR_FAILED; + + if(rtk_switch_portmask_P2L_get(phyUntagPmask, &(pVlanCfg->untag)) != RT_ERR_OK) + return RT_ERR_FAILED; + + pVlanCfg->ivl_en = vlan4K.ivl_svl; + pVlanCfg->fid_msti = vlan4K.fid_msti; + pVlanCfg->envlanpol = vlan4K.envlanpol; + pVlanCfg->meteridx = vlan4K.meteridx; + pVlanCfg->vbpen = vlan4K.vbpen; + pVlanCfg->vbpri = vlan4K.vbpri; + } + else + { + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) + { + if(vlan_mbrCfgVid[idx] == vid) + { + if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + + phyMbrPmask = vlanMC.mbr; + if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pVlanCfg->mbr)) != RT_ERR_OK) + return RT_ERR_FAILED; + + pVlanCfg->untag.bits[0] = 0; + pVlanCfg->ivl_en = 0; + pVlanCfg->fid_msti = vlanMC.fid_msti; + pVlanCfg->envlanpol = vlanMC.envlanpol; + pVlanCfg->meteridx = vlanMC.meteridx; + pVlanCfg->vbpen = vlanMC.vbpen; + pVlanCfg->vbpri = vlanMC.vbpri; + } + } + } + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_egrFilterEnable_set + * Description: + * Set VLAN egress filter. + * Input: + * egrFilter - Egress filtering + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_vlan_egrFilterEnable_set(rtk_enable_t egrFilter) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(egrFilter >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + /* enable VLAN */ + if ((retVal = rtl8367c_setAsicVlanFilter((rtk_uint32)egrFilter)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_egrFilterEnable_get + * Description: + * Get VLAN egress filter. + * Input: + * pEgrFilter - Egress filtering + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - NULL Pointer. + * Note: + * + */ +rtk_api_ret_t rtk_vlan_egrFilterEnable_get(rtk_enable_t *pEgrFilter) +{ + rtk_api_ret_t retVal; + rtk_uint32 state; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEgrFilter) + return RT_ERR_NULL_POINTER; + + /* enable VLAN */ + if ((retVal = rtl8367c_getAsicVlanFilter(&state)) != RT_ERR_OK) + return retVal; + + *pEgrFilter = (rtk_enable_t)state; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_mbrCfg_set + * Description: + * Set a VLAN Member Configuration entry by index. + * Input: + * idx - Index of VLAN Member Configuration. + * pMbrcfg - VLAN member Configuration. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * Set a VLAN Member Configuration entry by index. + */ +rtk_api_ret_t rtk_vlan_mbrCfg_set(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyMbrPmask; + rtl8367c_vlanconfiguser mbrCfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error check */ + if(pMbrcfg == NULL) + return RT_ERR_NULL_POINTER; + + if(idx > RTL8367C_CVIDXMAX) + return RT_ERR_INPUT; + + if(pMbrcfg->evid > RTL8367C_EVIDMAX) + return RT_ERR_INPUT; + + if(pMbrcfg->fid_msti > RTL8367C_FIDMAX) + return RT_ERR_L2_FID; + + if(pMbrcfg->envlanpol >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pMbrcfg->meteridx > RTK_MAX_METER_ID) + return RT_ERR_FILTER_METER_ID; + + if(pMbrcfg->vbpen >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if(pMbrcfg->vbpri > RTL8367C_PRIMAX) + return RT_ERR_QOS_INT_PRIORITY; + + /* Check port mask valid */ + RTK_CHK_PORTMASK_VALID(&(pMbrcfg->mbr)); + + mbrCfg.evid = pMbrcfg->evid; + mbrCfg.fid_msti = pMbrcfg->fid_msti; + mbrCfg.envlanpol = pMbrcfg->envlanpol; + mbrCfg.meteridx = pMbrcfg->meteridx; + mbrCfg.vbpen = pMbrcfg->vbpen; + mbrCfg.vbpri = pMbrcfg->vbpri; + + if(rtk_switch_portmask_L2P_get(&(pMbrcfg->mbr), &phyMbrPmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + mbrCfg.mbr = phyMbrPmask; + + if ((retVal = rtl8367c_setAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK) + return retVal; + + /* Update Database */ + if( (mbrCfg.evid == 0) && (mbrCfg.mbr == 0) ) + { + vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; + vlan_mbrCfgVid[idx] = 0; + } + else + { + vlan_mbrCfgUsage[idx] = MBRCFG_USED_BY_VLAN; + vlan_mbrCfgVid[idx] = mbrCfg.evid; + } + + return RT_ERR_OK; + +} + +/* Function Name: + * rtk_vlan_mbrCfg_get + * Description: + * Get a VLAN Member Configuration entry by index. + * Input: + * idx - Index of VLAN Member Configuration. + * Output: + * pMbrcfg - VLAN member Configuration. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * Get a VLAN Member Configuration entry by index. + */ +rtk_api_ret_t rtk_vlan_mbrCfg_get(rtk_uint32 idx, rtk_vlan_mbrcfg_t *pMbrcfg) +{ + rtk_api_ret_t retVal; + rtk_uint32 phyMbrPmask; + rtl8367c_vlanconfiguser mbrCfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Error check */ + if(pMbrcfg == NULL) + return RT_ERR_NULL_POINTER; + + if(idx > RTL8367C_CVIDXMAX) + return RT_ERR_INPUT; + + memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser)); + if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &mbrCfg)) != RT_ERR_OK) + return retVal; + + pMbrcfg->evid = mbrCfg.evid; + pMbrcfg->fid_msti = mbrCfg.fid_msti; + pMbrcfg->envlanpol = mbrCfg.envlanpol; + pMbrcfg->meteridx = mbrCfg.meteridx; + pMbrcfg->vbpen = mbrCfg.vbpen; + pMbrcfg->vbpri = mbrCfg.vbpri; + + phyMbrPmask = mbrCfg.mbr; + if(rtk_switch_portmask_P2L_get(phyMbrPmask, &(pMbrcfg->mbr)) != RT_ERR_OK) + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portPvid_set + * Description: + * Set port to specified VLAN ID(PVID). + * Input: + * port - Port id. + * pvid - Specified VLAN ID. + * priority - 802.1p priority for the PVID. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN entry not found. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API is used for Port-based VLAN. The untagged frame received from the + * port will be classified to the specified VLAN and assigned to the specified priority. + */ +rtk_api_ret_t rtk_vlan_portPvid_set(rtk_port_t port, rtk_vlan_t pvid, rtk_pri_t priority) +{ + rtk_api_ret_t retVal; + rtk_uint32 index; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + /* vid must be 0~8191 */ + if (pvid > RTL8367C_EVIDMAX) + return RT_ERR_VLAN_VID; + + /* priority must be 0~7 */ + if (priority > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + if((retVal = rtk_vlan_checkAndCreateMbr(pvid, &index)) != RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), index, priority)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portPvid_get + * Description: + * Get VLAN ID(PVID) on specified port. + * Input: + * port - Port id. + * Output: + * pPvid - Specified VLAN ID. + * pPriority - 802.1p priority for the PVID. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get the PVID and 802.1p priority for the PVID of Port-based VLAN. + */ +rtk_api_ret_t rtk_vlan_portPvid_get(rtk_port_t port, rtk_vlan_t *pPvid, rtk_pri_t *pPriority) +{ + rtk_api_ret_t retVal; + rtk_uint32 index, pri; + rtl8367c_vlanconfiguser mbrCfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pPvid) + return RT_ERR_NULL_POINTER; + + if(NULL == pPriority) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanPortBasedVID(rtk_switch_port_L2P_get(port), &index, &pri)) != RT_ERR_OK) + return retVal; + + memset(&mbrCfg, 0x00, sizeof(rtl8367c_vlanconfiguser)); + if ((retVal = rtl8367c_getAsicVlanMemberConfig(index, &mbrCfg)) != RT_ERR_OK) + return retVal; + + *pPvid = mbrCfg.evid; + *pPriority = pri; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portIgrFilterEnable_set + * Description: + * Set VLAN ingress for each port. + * Input: + * port - Port id. + * igr_filter - VLAN ingress function enable status. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number + * RT_ERR_ENABLE - Invalid enable input + * Note: + * The status of vlan ingress filter is as following: + * - DISABLED + * - ENABLED + * While VLAN function is enabled, ASIC will decide VLAN ID for each received frame and get belonged member + * ports from VLAN table. If received port is not belonged to VLAN member ports, ASIC will drop received frame if VLAN ingress function is enabled. + */ +rtk_api_ret_t rtk_vlan_portIgrFilterEnable_set(rtk_port_t port, rtk_enable_t igr_filter) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (igr_filter >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), igr_filter)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portIgrFilterEnable_get + * Description: + * Get VLAN Ingress Filter + * Input: + * port - Port id. + * Output: + * pIgr_filter - VLAN ingress function enable status. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can Get the VLAN ingress filter status. + * The status of vlan ingress filter is as following: + * - DISABLED + * - ENABLED + */ +rtk_api_ret_t rtk_vlan_portIgrFilterEnable_get(rtk_port_t port, rtk_enable_t *pIgr_filter) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pIgr_filter) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanIngressFilter(rtk_switch_port_L2P_get(port), pIgr_filter)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portAcceptFrameType_set + * Description: + * Set VLAN accept_frame_type + * Input: + * port - Port id. + * accept_frame_type - accept frame type + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_ACCEPT_FRAME_TYPE - Invalid frame type. + * Note: + * The API is used for checking 802.1Q tagged frames. + * The accept frame type as following: + * - ACCEPT_FRAME_TYPE_ALL + * - ACCEPT_FRAME_TYPE_TAG_ONLY + * - ACCEPT_FRAME_TYPE_UNTAG_ONLY + */ +rtk_api_ret_t rtk_vlan_portAcceptFrameType_set(rtk_port_t port, rtk_vlan_acceptFrameType_t accept_frame_type) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (accept_frame_type >= ACCEPT_FRAME_TYPE_END) + return RT_ERR_VLAN_ACCEPT_FRAME_TYPE; + + if ((retVal = rtl8367c_setAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), (rtl8367c_accframetype)accept_frame_type)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portAcceptFrameType_get + * Description: + * Get VLAN accept_frame_type + * Input: + * port - Port id. + * Output: + * pAccept_frame_type - accept frame type + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can Get the VLAN ingress filter. + * The accept frame type as following: + * - ACCEPT_FRAME_TYPE_ALL + * - ACCEPT_FRAME_TYPE_TAG_ONLY + * - ACCEPT_FRAME_TYPE_UNTAG_ONLY + */ +rtk_api_ret_t rtk_vlan_portAcceptFrameType_get(rtk_port_t port, rtk_vlan_acceptFrameType_t *pAccept_frame_type) +{ + rtk_api_ret_t retVal; + rtl8367c_accframetype acc_frm_type; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pAccept_frame_type) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanAccpetFrameType(rtk_switch_port_L2P_get(port), &acc_frm_type)) != RT_ERR_OK) + return retVal; + + *pAccept_frame_type = (rtk_vlan_acceptFrameType_t)acc_frm_type; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_add + * Description: + * Add the protocol-and-port-based vlan to the specified port of device. + * Input: + * port - Port id. + * pInfo - Protocol and port based VLAN configuration information. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * RT_ERR_VLAN_PRIORITY - Invalid priority. + * RT_ERR_TBL_FULL - Table is full. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_add(rtk_port_t port, rtk_vlan_protoAndPortInfo_t *pInfo) +{ + rtk_api_ret_t retVal, i; + rtk_uint32 exist, empty, used, index; + rtl8367c_protocolgdatacfg ppb_data_cfg; + rtl8367c_protocolvlancfg ppb_vlan_cfg; + rtl8367c_provlan_frametype tmp; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pInfo) + return RT_ERR_NULL_POINTER; + + if (pInfo->proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) + return RT_ERR_OUT_OF_RANGE; + + if (pInfo->frame_type >= FRAME_TYPE_END) + return RT_ERR_OUT_OF_RANGE; + + if (pInfo->cvid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if (pInfo->cpri > RTL8367C_PRIMAX) + return RT_ERR_VLAN_PRIORITY; + + exist = 0xFF; + empty = 0xFF; + for (i = RTL8367C_PROTOVLAN_GIDX_MAX; i >= 0; i--) + { + if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + tmp = (rtl8367c_provlan_frametype)pInfo->frame_type; + if (ppb_data_cfg.etherType == pInfo->proto_type && ppb_data_cfg.frameType == tmp) + { + /*Already exist*/ + exist = i; + break; + } + else if (ppb_data_cfg.etherType == 0 && ppb_data_cfg.frameType == 0) + { + /*find empty index*/ + empty = i; + } + } + + used = 0xFF; + /*No empty and exist index*/ + if (0xFF == exist && 0xFF == empty) + return RT_ERR_TBL_FULL; + else if (existframe_type; + ppb_data_cfg.etherType = pInfo->proto_type; + if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(empty, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + used = empty; + } + else + return RT_ERR_FAILED; + + if((retVal = rtk_vlan_checkAndCreateMbr(pInfo->cvid, &index)) != RT_ERR_OK) + return retVal; + + ppb_vlan_cfg.vlan_idx = index; + ppb_vlan_cfg.valid = TRUE; + ppb_vlan_cfg.priority = pInfo->cpri; + if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), used, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_get + * Description: + * Get the protocol-and-port-based vlan to the specified port of device. + * Input: + * port - Port id. + * proto_type - protocol-and-port-based vlan protocol type. + * frame_type - protocol-and-port-based vlan frame type. + * Output: + * pInfo - Protocol and port based VLAN configuration information. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_TBL_FULL - Table is full. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_get(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type, rtk_vlan_protoAndPortInfo_t *pInfo) +{ + rtk_api_ret_t retVal; + rtk_uint32 i; + rtk_uint32 ppb_idx; + rtl8367c_protocolgdatacfg ppb_data_cfg; + rtl8367c_protocolvlancfg ppb_vlan_cfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) + return RT_ERR_OUT_OF_RANGE; + + if (frame_type >= FRAME_TYPE_END) + return RT_ERR_OUT_OF_RANGE; + + ppb_idx = 0; + + for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) + { + if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + + if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) ) + { + ppb_idx = i; + break; + } + else if (RTL8367C_PROTOVLAN_GIDX_MAX == i) + return RT_ERR_TBL_FULL; + } + + if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + + if (FALSE == ppb_vlan_cfg.valid) + return RT_ERR_FAILED; + + pInfo->frame_type = frame_type; + pInfo->proto_type = proto_type; + pInfo->cvid = vlan_mbrCfgVid[ppb_vlan_cfg.vlan_idx]; + pInfo->cpri = ppb_vlan_cfg.priority; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_del + * Description: + * Delete the protocol-and-port-based vlan from the specified port of device. + * Input: + * port - Port id. + * proto_type - protocol-and-port-based vlan protocol type. + * frame_type - protocol-and-port-based vlan frame type. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * RT_ERR_TBL_FULL - Table is full. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * The frame type is shown in the following: + * - FRAME_TYPE_ETHERNET + * - FRAME_TYPE_RFC1042 + * - FRAME_TYPE_LLCOTHER + */ +rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_del(rtk_port_t port, rtk_vlan_proto_type_t proto_type, rtk_vlan_protoVlan_frameType_t frame_type) +{ + rtk_api_ret_t retVal; + rtk_uint32 i, bUsed; + rtk_uint32 ppb_idx; + rtl8367c_protocolgdatacfg ppb_data_cfg; + rtl8367c_protocolvlancfg ppb_vlan_cfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (proto_type > RTK_MAX_NUM_OF_PROTO_TYPE) + return RT_ERR_OUT_OF_RANGE; + + if (frame_type >= FRAME_TYPE_END) + return RT_ERR_OUT_OF_RANGE; + + ppb_idx = 0; + + for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) + { + if ((retVal = rtl8367c_getAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + + if ( (ppb_data_cfg.frameType == (rtl8367c_provlan_frametype)frame_type) && (ppb_data_cfg.etherType == proto_type) ) + { + ppb_idx = i; + ppb_vlan_cfg.valid = FALSE; + ppb_vlan_cfg.vlan_idx = 0; + ppb_vlan_cfg.priority = 0; + if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + } + } + + bUsed = FALSE; + RTK_SCAN_ALL_PHY_PORTMASK(i) + { + if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i, ppb_idx, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + + if (TRUE == ppb_vlan_cfg.valid) + { + bUsed = TRUE; + break; + } + } + + if (FALSE == bUsed) /*No Port use this PPB Index, Delete it*/ + { + ppb_data_cfg.etherType=0; + ppb_data_cfg.frameType=0; + if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(ppb_idx, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + } + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_protoAndPortBasedVlan_delAll + * Description: + * Delete all protocol-and-port-based vlans from the specified port of device. + * Input: + * port - Port id. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_OUT_OF_RANGE - input out of range. + * Note: + * The incoming packet which match the protocol-and-port-based vlan will use the configure vid for ingress pipeline + * Delete all flow table protocol-and-port-based vlan entries. + */ +rtk_api_ret_t rtk_vlan_protoAndPortBasedVlan_delAll(rtk_port_t port) +{ + rtk_api_ret_t retVal; + rtk_uint32 i, j, bUsed[4]; + rtl8367c_protocolgdatacfg ppb_data_cfg; + rtl8367c_protocolvlancfg ppb_vlan_cfg; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) + { + ppb_vlan_cfg.valid = FALSE; + ppb_vlan_cfg.vlan_idx = 0; + ppb_vlan_cfg.priority = 0; + if ((retVal = rtl8367c_setAsicVlanPortAndProtocolBased(rtk_switch_port_L2P_get(port), i, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + } + + bUsed[0] = FALSE; + bUsed[1] = FALSE; + bUsed[2] = FALSE; + bUsed[3] = FALSE; + RTK_SCAN_ALL_PHY_PORTMASK(i) + { + for (j = 0; j <= RTL8367C_PROTOVLAN_GIDX_MAX; j++) + { + if ((retVal = rtl8367c_getAsicVlanPortAndProtocolBased(i,j, &ppb_vlan_cfg)) != RT_ERR_OK) + return retVal; + + if (TRUE == ppb_vlan_cfg.valid) + { + bUsed[j] = TRUE; + } + } + } + + for (i = 0; i<= RTL8367C_PROTOVLAN_GIDX_MAX; i++) + { + if (FALSE == bUsed[i]) /*No Port use this PPB Index, Delete it*/ + { + ppb_data_cfg.etherType=0; + ppb_data_cfg.frameType=0; + if ((retVal = rtl8367c_setAsicVlanProtocolBasedGroupData(i, &ppb_data_cfg)) != RT_ERR_OK) + return retVal; + } + } + + + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_tagMode_set + * Description: + * Set CVLAN egress tag mode + * Input: + * port - Port id. + * tag_mode - The egress tag mode. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_ENABLE - Invalid enable input. + * Note: + * The API can set Egress tag mode. There are 4 mode for egress tag: + * - VLAN_TAG_MODE_ORIGINAL, + * - VLAN_TAG_MODE_KEEP_FORMAT, + * - VLAN_TAG_MODE_PRI. + * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, + */ +rtk_api_ret_t rtk_vlan_tagMode_set(rtk_port_t port, rtk_vlan_tagMode_t tag_mode) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (tag_mode >= VLAN_TAG_MODE_END) + return RT_ERR_PORT_ID; + + if ((retVal = rtl8367c_setAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), (rtl8367c_egtagmode)tag_mode)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_tagMode_get + * Description: + * Get CVLAN egress tag mode + * Input: + * port - Port id. + * Output: + * pTag_mode - The egress tag mode. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * The API can get Egress tag mode. There are 4 mode for egress tag: + * - VLAN_TAG_MODE_ORIGINAL, + * - VLAN_TAG_MODE_KEEP_FORMAT, + * - VLAN_TAG_MODE_PRI. + * - VLAN_TAG_MODE_REAL_KEEP_FORMAT, + */ +rtk_api_ret_t rtk_vlan_tagMode_get(rtk_port_t port, rtk_vlan_tagMode_t *pTag_mode) +{ + rtk_api_ret_t retVal; + rtl8367c_egtagmode mode; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pTag_mode) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanEgressTagMode(rtk_switch_port_L2P_get(port), &mode)) != RT_ERR_OK) + return retVal; + + *pTag_mode = (rtk_vlan_tagMode_t)mode; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_transparent_set + * Description: + * Set VLAN transparent mode + * Input: + * egr_port - Egress Port id. + * pIgr_pmask - Ingress Port Mask. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +rtk_api_ret_t rtk_vlan_transparent_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(egr_port); + + if(NULL == pIgr_pmask) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pIgr_pmask); + + if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + if ((retVal = rtl8367c_setAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_transparent_get + * Description: + * Get VLAN transparent mode + * Input: + * egr_port - Egress Port id. + * Output: + * pIgr_pmask - Ingress Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +rtk_api_ret_t rtk_vlan_transparent_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(egr_port); + + if(NULL == pIgr_pmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanTransparent(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK) + return retVal; + + if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_keep_set + * Description: + * Set VLAN egress keep mode + * Input: + * egr_port - Egress Port id. + * pIgr_pmask - Ingress Port Mask. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +rtk_api_ret_t rtk_vlan_keep_set(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(egr_port); + + if(NULL == pIgr_pmask) + return RT_ERR_NULL_POINTER; + + RTK_CHK_PORTMASK_VALID(pIgr_pmask); + + if(rtk_switch_portmask_L2P_get(pIgr_pmask, &pmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + if ((retVal = rtl8367c_setAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), pmask)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_keep_get + * Description: + * Get VLAN egress keep mode + * Input: + * egr_port - Egress Port id. + * Output: + * pIgr_pmask - Ingress Port Mask + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port number. + * Note: + * None. + */ +rtk_api_ret_t rtk_vlan_keep_get(rtk_port_t egr_port, rtk_portmask_t *pIgr_pmask) +{ + rtk_api_ret_t retVal; + rtk_uint32 pmask; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(egr_port); + + if(NULL == pIgr_pmask) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanEgressKeep(rtk_switch_port_L2P_get(egr_port), &pmask)) != RT_ERR_OK) + return retVal; + + if(rtk_switch_portmask_P2L_get(pmask, pIgr_pmask) != RT_ERR_OK) + return RT_ERR_FAILED; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_stg_set + * Description: + * Set spanning tree group instance of the vlan to the specified device + * Input: + * vid - Specified VLAN ID. + * stg - spanning tree group instance. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_MSTI - Invalid msti parameter + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API can set spanning tree group instance of the vlan to the specified device. + */ +rtk_api_ret_t rtk_vlan_stg_set(rtk_vlan_t vid, rtk_stp_msti_id_t stg) +{ + rtk_api_ret_t retVal; + rtl8367c_user_vlan4kentry vlan4K; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~4095 */ + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + /* priority must be 0~15 */ + if (stg > RTL8367C_MSTIMAX) + return RT_ERR_MSTI; + + /* update 4K table */ + vlan4K.vid = vid; + if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + vlan4K.fid_msti= stg; + if ((retVal = rtl8367c_setAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_stg_get + * Description: + * Get spanning tree group instance of the vlan to the specified device + * Input: + * vid - Specified VLAN ID. + * Output: + * pStg - spanning tree group instance. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_VLAN_VID - Invalid VID parameter. + * Note: + * The API can get spanning tree group instance of the vlan to the specified device. + */ +rtk_api_ret_t rtk_vlan_stg_get(rtk_vlan_t vid, rtk_stp_msti_id_t *pStg) +{ + rtk_api_ret_t retVal; + rtl8367c_user_vlan4kentry vlan4K; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~4095 */ + if (vid > RTL8367C_VIDMAX) + return RT_ERR_VLAN_VID; + + if(NULL == pStg) + return RT_ERR_NULL_POINTER; + + /* update 4K table */ + vlan4K.vid = vid; + if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + + *pStg = vlan4K.fid_msti; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portFid_set + * Description: + * Set port-based filtering database + * Input: + * port - Port id. + * enable - enable port-based FID + * fid - Specified filtering database. + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_L2_FID - Invalid fid. + * RT_ERR_INPUT - Invalid input parameter. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can set port-based filtering database. If the function is enabled, all input + * packets will be assigned to the port-based fid regardless vlan tag. + */ +rtk_api_ret_t rtk_vlan_portFid_set(rtk_port_t port, rtk_enable_t enable, rtk_fid_t fid) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (enable>=RTK_ENABLE_END) + return RT_ERR_ENABLE; + + /* fid must be 0~4095 */ + if (fid > RTK_FID_MAX) + return RT_ERR_L2_FID; + + if ((retVal = rtl8367c_setAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), enable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_setAsicPortBasedFid(rtk_switch_port_L2P_get(port), fid))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_portFid_get + * Description: + * Get port-based filtering database + * Input: + * port - Port id. + * Output: + * pEnable - enable port-based FID + * pFid - Specified filtering database. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Invalid input parameters. + * RT_ERR_PORT_ID - Invalid port ID. + * Note: + * The API can get port-based filtering database status. If the function is enabled, all input + * packets will be assigned to the port-based fid regardless vlan tag. + */ +rtk_api_ret_t rtk_vlan_portFid_get(rtk_port_t port, rtk_enable_t *pEnable, rtk_fid_t *pFid) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if(NULL == pFid) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicPortBasedFidEn(rtk_switch_port_L2P_get(port), pEnable))!=RT_ERR_OK) + return retVal; + + if ((retVal = rtl8367c_getAsicPortBasedFid(rtk_switch_port_L2P_get(port), pFid))!=RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_UntagDscpPriorityEnable_set + * Description: + * Set Untag DSCP priority assign + * Input: + * enable - state of Untag DSCP priority assign + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_ENABLE - Invalid input parameters. + * Note: + * + */ +rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_set(rtk_enable_t enable) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(enable >= RTK_ENABLE_END) + return RT_ERR_ENABLE; + + if ((retVal = rtl8367c_setAsicVlanUntagDscpPriorityEn((rtk_uint32)enable)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_UntagDscpPriorityEnable_get + * Description: + * Get Untag DSCP priority assign + * Input: + * None + * Output: + * pEnable - state of Untag DSCP priority assign + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - Null pointer + * Note: + * + */ +rtk_api_ret_t rtk_vlan_UntagDscpPriorityEnable_get(rtk_enable_t *pEnable) +{ + rtk_api_ret_t retVal; + rtk_uint32 value; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnable) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicVlanUntagDscpPriorityEn(&value)) != RT_ERR_OK) + return retVal; + + *pEnable = (rtk_enable_t)value; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stp_mstpState_set + * Description: + * Configure spanning tree state per each port. + * Input: + * port - Port id + * msti - Multiple spanning tree instance. + * stp_state - Spanning tree state for msti + * Output: + * None + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MSTI - Invalid msti parameter. + * RT_ERR_MSTP_STATE - Invalid STP state. + * Note: + * System supports per-port multiple spanning tree state for each msti. + * There are four states supported by ASIC. + * - STP_STATE_DISABLED + * - STP_STATE_BLOCKING + * - STP_STATE_LEARNING + * - STP_STATE_FORWARDING + */ +rtk_api_ret_t rtk_stp_mstpState_set(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t stp_state) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (msti > RTK_MAX_NUM_OF_MSTI) + return RT_ERR_MSTI; + + if (stp_state >= STP_STATE_END) + return RT_ERR_MSTP_STATE; + + if ((retVal = rtl8367c_setAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, stp_state)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_stp_mstpState_get + * Description: + * Get spanning tree state per each port. + * Input: + * port - Port id. + * msti - Multiple spanning tree instance. + * Output: + * pStp_state - Spanning tree state for msti + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_PORT_ID - Invalid port number. + * RT_ERR_MSTI - Invalid msti parameter. + * Note: + * System supports per-port multiple spanning tree state for each msti. + * There are four states supported by ASIC. + * - STP_STATE_DISABLED + * - STP_STATE_BLOCKING + * - STP_STATE_LEARNING + * - STP_STATE_FORWARDING + */ +rtk_api_ret_t rtk_stp_mstpState_get(rtk_stp_msti_id_t msti, rtk_port_t port, rtk_stp_state_t *pStp_state) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* Check Port Valid */ + RTK_CHK_PORT_VALID(port); + + if (msti > RTK_MAX_NUM_OF_MSTI) + return RT_ERR_MSTI; + + if(NULL == pStp_state) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getAsicSpanningTreeStatus(rtk_switch_port_L2P_get(port), msti, pStp_state)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_checkAndCreateMbr + * Description: + * Check and create Member configuration and return index + * Input: + * vid - VLAN id. + * Output: + * pIndex - Member configuration index + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_VLAN_VID - Invalid VLAN ID. + * RT_ERR_VLAN_ENTRY_NOT_FOUND - VLAN not found + * RT_ERR_TBL_FULL - Member Configuration table full + * Note: + * + */ +rtk_api_ret_t rtk_vlan_checkAndCreateMbr(rtk_vlan_t vid, rtk_uint32 *pIndex) +{ + rtk_api_ret_t retVal; + rtl8367c_user_vlan4kentry vlan4K; + rtl8367c_vlanconfiguser vlanMC; + rtk_uint32 idx; + rtk_uint32 empty_idx = 0xFFFF; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + /* vid must be 0~8191 */ + if (vid > RTL8367C_EVIDMAX) + return RT_ERR_VLAN_VID; + + /* Null pointer check */ + if(NULL == pIndex) + return RT_ERR_NULL_POINTER; + + /* Get 4K VLAN */ + if (vid <= RTL8367C_VIDMAX) + { + memset(&vlan4K, 0x00, sizeof(rtl8367c_user_vlan4kentry)); + vlan4K.vid = vid; + if ((retVal = rtl8367c_getAsicVlan4kEntry(&vlan4K)) != RT_ERR_OK) + return retVal; + } + + /* Search exist entry */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) + { + if(vlan_mbrCfgVid[idx] == vid) + { + /* Found! return index */ + *pIndex = idx; + return RT_ERR_OK; + } + } + } + + /* Not found, Read H/W Member Configuration table to update database */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if ((retVal = rtl8367c_getAsicVlanMemberConfig(idx, &vlanMC)) != RT_ERR_OK) + return retVal; + + if( (vlanMC.evid == 0) && (vlanMC.mbr == 0x00)) + { + vlan_mbrCfgUsage[idx] = MBRCFG_UNUSED; + vlan_mbrCfgVid[idx] = 0; + } + else + { + vlan_mbrCfgUsage[idx] = MBRCFG_USED_BY_VLAN; + vlan_mbrCfgVid[idx] = vlanMC.evid; + } + } + + /* Search exist entry again */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_USED_BY_VLAN) + { + if(vlan_mbrCfgVid[idx] == vid) + { + /* Found! return index */ + *pIndex = idx; + return RT_ERR_OK; + } + } + } + + /* try to look up an empty index */ + for (idx = 0; idx <= RTL8367C_CVIDXMAX; idx++) + { + if(vlan_mbrCfgUsage[idx] == MBRCFG_UNUSED) + { + empty_idx = idx; + break; + } + } + + if(empty_idx == 0xFFFF) + { + /* No empty index */ + return RT_ERR_TBL_FULL; + } + + if (vid > RTL8367C_VIDMAX) + { + /* > 4K, there is no 4K entry, create on member configuration directly */ + memset(&vlanMC, 0x00, sizeof(rtl8367c_vlanconfiguser)); + vlanMC.evid = vid; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK) + return retVal; + } + else + { + /* Copy from 4K table */ + vlanMC.evid = vid; + vlanMC.mbr = vlan4K.mbr; + vlanMC.fid_msti = vlan4K.fid_msti; + vlanMC.meteridx= vlan4K.meteridx; + vlanMC.envlanpol= vlan4K.envlanpol; + vlanMC.vbpen = vlan4K.vbpen; + vlanMC.vbpri = vlan4K.vbpri; + if ((retVal = rtl8367c_setAsicVlanMemberConfig(empty_idx, &vlanMC)) != RT_ERR_OK) + return retVal; + } + + /* Update Database */ + vlan_mbrCfgUsage[empty_idx] = MBRCFG_USED_BY_VLAN; + vlan_mbrCfgVid[empty_idx] = vid; + + *pIndex = empty_idx; + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_reservedVidAction_set + * Description: + * Set Action of VLAN ID = 0 & 4095 tagged packet + * Input: + * action_vid0 - Action for VID 0. + * action_vid4095 - Action for VID 4095. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_vlan_reservedVidAction_set(rtk_vlan_resVidAction_t action_vid0, rtk_vlan_resVidAction_t action_vid4095) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(action_vid0 >= RESVID_ACTION_END) + return RT_ERR_INPUT; + + if(action_vid4095 >= RESVID_ACTION_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setReservedVidAction((rtk_uint32)action_vid0, (rtk_uint32)action_vid4095)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_reservedVidAction_get + * Description: + * Get Action of VLAN ID = 0 & 4095 tagged packet + * Input: + * pAction_vid0 - Action for VID 0. + * pAction_vid4095 - Action for VID 4095. + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_NULL_POINTER - NULL Pointer + * Note: + * + */ +rtk_api_ret_t rtk_vlan_reservedVidAction_get(rtk_vlan_resVidAction_t *pAction_vid0, rtk_vlan_resVidAction_t *pAction_vid4095) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(pAction_vid0 == NULL) + return RT_ERR_NULL_POINTER; + + if(pAction_vid4095 == NULL) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getReservedVidAction((rtk_uint32 *)pAction_vid0, (rtk_uint32 *)pAction_vid4095)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_realKeepRemarkEnable_set + * Description: + * Set Real keep 1p remarking feature + * Input: + * enabled - State of 1p remarking at real keep packet + * Output: + * None. + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_set(rtk_enable_t enabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(enabled >= RTK_ENABLE_END) + return RT_ERR_INPUT; + + if ((retVal = rtl8367c_setRealKeepRemarkEn((rtk_uint32)enabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_realKeepRemarkEnable_get + * Description: + * Get Real keep 1p remarking feature + * Input: + * None. + * Output: + * pEnabled - State of 1p remarking at real keep packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_vlan_realKeepRemarkEnable_get(rtk_enable_t *pEnabled) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if(NULL == pEnabled) + return RT_ERR_NULL_POINTER; + + if ((retVal = rtl8367c_getRealKeepRemarkEn((rtk_uint32 *)pEnabled)) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + +/* Function Name: + * rtk_vlan_reset + * Description: + * Reset VLAN + * Input: + * None. + * Output: + * pEnabled - State of 1p remarking at real keep packet + * Return: + * RT_ERR_OK - OK + * RT_ERR_FAILED - Failed + * RT_ERR_SMI - SMI access error + * RT_ERR_INPUT - Error Input + * Note: + * + */ +rtk_api_ret_t rtk_vlan_reset(void) +{ + rtk_api_ret_t retVal; + + /* Check initialization state */ + RTK_CHK_INIT_STATE(); + + if ((retVal = rtl8367c_resetVlan()) != RT_ERR_OK) + return retVal; + + return RT_ERR_OK; +} + diff --git a/drivers/net/phy/rtk/rtl8367s.c b/drivers/net/phy/rtk/rtl8367s.c new file mode 100644 index 000000000000..2988c8af56db --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367s.c @@ -0,0 +1,580 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +//include from rtl8367c dir +#include "./rtl8367c/include/rtk_switch.h" +#include "./rtl8367c/include/vlan.h" +#include "./rtl8367c/include/stat.h" +#include "./rtl8367c/include/port.h" + +#define RTL8367C_SW_CPU_PORT 6 + + //RTL8367C_PHY_PORT_NUM + ext0 + ext1 +#define RTL8367C_NUM_PORTS 7 +#define RTL8367C_NUM_VIDS 4096 + +struct rtl8367_priv { + struct switch_dev swdev; + bool global_vlan_enable; +}; + +struct rtl8367_mib_counter { + const char *name; +}; + +struct rtl8367_vlan_info { + unsigned short vid; + unsigned int untag; + unsigned int member; + unsigned char fid; +}; + +struct rtl8367_priv rtl8367_priv_data; + +unsigned int rtl8367c_port_id[RTL8367C_NUM_PORTS]={0,1,2,3,4,EXT_PORT1,EXT_PORT0}; + +void (*rtl8367_switch_reset_func)(void)=NULL; + +static struct rtl8367_mib_counter rtl8367c_mib_counters[] = { + {"ifInOctets"}, + {"dot3StatsFCSErrors"}, + {"dot3StatsSymbolErrors"}, + {"dot3InPauseFrames"}, + {"dot3ControlInUnknownOpcodes"}, + {"etherStatsFragments"}, + {"etherStatsJabbers"}, + {"ifInUcastPkts"}, + {"etherStatsDropEvents"}, + {"etherStatsOctets"}, + {"etherStatsUndersizePkts"}, + {"etherStatsOversizePkts"}, + {"etherStatsPkts64Octets"}, + {"etherStatsPkts65to127Octets"}, + {"etherStatsPkts128to255Octets"}, + {"etherStatsPkts256to511Octets"}, + {"etherStatsPkts512to1023Octets"}, + {"etherStatsPkts1024toMaxOctets"}, + {"etherStatsMcastPkts"}, + {"etherStatsBcastPkts"}, + {"ifOutOctets"}, + {"dot3StatsSingleCollisionFrames"}, + {"dot3StatsMultipleCollisionFrames"}, + {"dot3StatsDeferredTransmissions"}, + {"dot3StatsLateCollisions"}, + {"etherStatsCollisions"}, + {"dot3StatsExcessiveCollisions"}, + {"dot3OutPauseFrames"}, + {"dot1dBasePortDelayExceededDiscards"}, + {"dot1dTpPortInDiscards"}, + {"ifOutUcastPkts"}, + {"ifOutMulticastPkts"}, + {"ifOutBrocastPkts"}, + {"outOampduPkts"}, + {"inOampduPkts"}, + {"pktgenPkts"}, + {"inMldChecksumError"}, + {"inIgmpChecksumError"}, + {"inMldSpecificQuery"}, + {"inMldGeneralQuery"}, + {"inIgmpSpecificQuery"}, + {"inIgmpGeneralQuery"}, + {"inMldLeaves"}, + {"inIgmpLeaves"}, + {"inIgmpJoinsSuccess"}, + {"inIgmpJoinsFail"}, + {"inMldJoinsSuccess"}, + {"inMldJoinsFail"}, + {"inReportSuppressionDrop"}, + {"inLeaveSuppressionDrop"}, + {"outIgmpReports"}, + {"outIgmpLeaves"}, + {"outIgmpGeneralQuery"}, + {"outIgmpSpecificQuery"}, + {"outMldReports"}, + {"outMldLeaves"}, + {"outMldGeneralQuery"}, + {"outMldSpecificQuery"}, + {"inKnownMulticastPkts"}, + {"ifInMulticastPkts"}, + {"ifInBroadcastPkts"}, + {"ifOutDiscards"} +}; + +/*rtl8367c proprietary switch API wrapper */ +static inline unsigned int rtl8367c_sw_to_phy_port(int port) +{ + return rtl8367c_port_id[port]; +} + +static inline unsigned int rtl8367c_portmask_phy_to_sw(rtk_portmask_t phy_portmask) +{ + int i; + for (i = 0; i < RTL8367C_NUM_PORTS; i++) { + if(RTK_PORTMASK_IS_PORT_SET(phy_portmask,rtl8367c_sw_to_phy_port(i))) { + RTK_PORTMASK_PORT_CLEAR(phy_portmask,rtl8367c_sw_to_phy_port(i)); + RTK_PORTMASK_PORT_SET(phy_portmask,i); + } + + } + return (unsigned int)phy_portmask.bits[0]; +} + +static int rtl8367c_reset_mibs(void) +{ + return rtk_stat_global_reset(); +} + +static int rtl8367c_reset_port_mibs(int port) +{ + + return rtk_stat_port_reset(rtl8367c_sw_to_phy_port(port)); +} + +static int rtl8367c_get_mibs_num(void) +{ + return ARRAY_SIZE(rtl8367c_mib_counters); +} + +static const char *rtl8367c_get_mib_name(int idx) +{ + + return rtl8367c_mib_counters[idx].name; +} + +static int rtl8367c_get_port_mib_counter(int idx, int port, unsigned long long *counter) +{ + return rtk_stat_port_get(rtl8367c_sw_to_phy_port(port), idx, counter); +} + +static int rtl8367c_is_vlan_valid(unsigned int vlan) +{ + unsigned max = RTL8367C_NUM_VIDS; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367c_get_vlan( unsigned short vid, struct rtl8367_vlan_info *vlan) +{ + rtk_vlan_cfg_t vlan_cfg; + + memset(vlan, '\0', sizeof(struct rtl8367_vlan_info)); + + if (vid >= RTL8367C_NUM_VIDS) + return -EINVAL; + + if(rtk_vlan_get(vid,&vlan_cfg)) + return -EINVAL; + + vlan->vid = vid; + vlan->member = rtl8367c_portmask_phy_to_sw(vlan_cfg.mbr); + vlan->untag = rtl8367c_portmask_phy_to_sw(vlan_cfg.untag); + vlan->fid = vlan_cfg.fid_msti; + + return 0; +} + +static int rtl8367c_set_vlan( unsigned short vid, u32 mbr, u32 untag, u8 fid) +{ + rtk_vlan_cfg_t vlan_cfg; + int i; + + memset(&vlan_cfg, 0x00, sizeof(rtk_vlan_cfg_t)); + + for (i = 0; i < RTL8367C_NUM_PORTS; i++) { + if (mbr & (1 << i)) { + RTK_PORTMASK_PORT_SET(vlan_cfg.mbr, rtl8367c_sw_to_phy_port(i)); + if(untag & (1 << i)) + RTK_PORTMASK_PORT_SET(vlan_cfg.untag, rtl8367c_sw_to_phy_port(i)); + } + } + vlan_cfg.fid_msti=fid; + vlan_cfg.ivl_en = 1; + return rtk_vlan_set(vid, &vlan_cfg); +} + + +static int rtl8367c_get_pvid( int port, int *pvid) +{ + u32 prio=0; + + if (port >= RTL8367C_NUM_PORTS) + return -EINVAL; + + return rtk_vlan_portPvid_get(rtl8367c_sw_to_phy_port(port),pvid,&prio); +} + + +static int rtl8367c_set_pvid( int port, int pvid) +{ + u32 prio=0; + + if (port >= RTL8367C_NUM_PORTS) + return -EINVAL; + + return rtk_vlan_portPvid_set(rtl8367c_sw_to_phy_port(port),pvid,prio); +} + +static int rtl8367c_get_port_link(int port, int *link, int *speed, int *duplex) +{ + + if(rtk_port_phyStatus_get(rtl8367c_sw_to_phy_port(port),(rtk_port_linkStatus_t *)link, + (rtk_port_speed_t *)speed,(rtk_port_duplex_t *)duplex)) + return -EINVAL; + + return 0; +} + +/*common rtl8367 swconfig entry API*/ + +static int +rtl8367_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev); + + priv->global_vlan_enable = val->value.i ; + + return 0; +} + +static int +rtl8367_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8367_priv *priv = container_of(dev, struct rtl8367_priv, swdev); + + val->value.i = priv->global_vlan_enable; + + return 0; +} + +static int rtl8367_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + return rtl8367c_reset_mibs(); +} + + +static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int port; + + port = val->port_vlan; + if (port >= RTL8367C_NUM_PORTS) + return -EINVAL; + + return rtl8367c_reset_port_mibs(port); +} + +static int rtl8367_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i, len = 0; + unsigned long long counter = 0; + static char mib_buf[4096]; + + if (val->port_vlan >= RTL8367C_NUM_PORTS) + return -EINVAL; + + len += snprintf(mib_buf + len, sizeof(mib_buf) - len, + "Port %d MIB counters\n", + val->port_vlan); + + for (i = 0; i port_vlan, + &counter)) + len += snprintf(mib_buf + len, sizeof(mib_buf) - len, + "%llu\n", counter); + else + len += snprintf(mib_buf + len, sizeof(mib_buf) - len, + "%s\n", "N/A"); + } + + val->value.s = mib_buf; + val->len = len; + return 0; +} + + +static int rtl8367_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i; + u32 len = 0; + struct rtl8367_vlan_info vlan; + static char vlan_buf[256]; + int err; + + if (!rtl8367c_is_vlan_valid(val->port_vlan)) + return -EINVAL; + + memset(vlan_buf, '\0', sizeof(vlan_buf)); + + err = rtl8367c_get_vlan(val->port_vlan, &vlan); + if (err) + return err; + + len += snprintf(vlan_buf + len, sizeof(vlan_buf) - len, + "VLAN %d: Ports: '", vlan.vid); + + for (i = 0; i value.s = vlan_buf; + val->len = len; + + return 0; +} + + +static int rtl8367_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct switch_port *port; + struct rtl8367_vlan_info vlan; + int i; + + if (!rtl8367c_is_vlan_valid(val->port_vlan)) + return -EINVAL; + + if(rtl8367c_get_vlan(val->port_vlan, &vlan)) + return -EINVAL; + + port = &val->value.ports[0]; + val->len = 0; + for (i = 0; i id = i; + port->flags = (vlan.untag & BIT(i)) ? + 0 : BIT(SWITCH_PORT_FLAG_TAGGED); + val->len++; + port++; + } + return 0; +} + + +static int rtl8367_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct switch_port *port; + u32 member = 0; + u32 untag = 0; + u8 fid=0; + int err; + int i; + + if (!rtl8367c_is_vlan_valid(val->port_vlan)) + return -EINVAL; + + port = &val->value.ports[0]; + for (i = 0; i < val->len; i++, port++) { + int pvid = 0; + member |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) + untag |= BIT(port->id); + + /* + * To ensure that we have a valid MC entry for this VLAN, + * initialize the port VLAN ID here. + */ + err = rtl8367c_get_pvid(port->id, &pvid); + if (err < 0) + return err; + if (pvid == 0) { + err = rtl8367c_set_pvid(port->id, val->port_vlan); + if (err < 0) + return err; + } + } + + //pr_info("[%s] vid=%d , mem=%x,untag=%x,fid=%d \n",__func__,val->port_vlan,member,untag,fid); + + return rtl8367c_set_vlan(val->port_vlan, member, untag, fid); + +} + + +static int rtl8367_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + return rtl8367c_get_pvid(port, val); +} + + +static int rtl8367_sw_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + return rtl8367c_set_pvid(port, val); +} + + +static int rtl8367_sw_reset_switch(struct switch_dev *dev) +{ + if(rtl8367_switch_reset_func) + (*rtl8367_switch_reset_func)(); + else + printk("rest switch is not supported\n"); + + return 0; +} + +static int rtl8367_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + int speed; + + if (port >= RTL8367C_NUM_PORTS) + return -EINVAL; + + if(rtl8367c_get_port_link(port,(int *)&link->link,(int *)&speed,(int *)&link->duplex)) + return -EINVAL; + + if (!link->link) + return 0; + + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + + +static struct switch_attr rtl8367_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8367_sw_set_vlan_enable, + .get = rtl8367_sw_get_vlan_enable, + .max = 1, + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367_sw_reset_mibs, + } +}; + +static struct switch_attr rtl8367_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + //.max = 33, + .set = NULL, + .get = rtl8367_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8367_sw_get_vlan_info, + }, +}; + +static const struct switch_dev_ops rtl8367_sw_ops = { + .attr_global = { + .attr = rtl8367_globals, + .n_attr = ARRAY_SIZE(rtl8367_globals), + }, + .attr_port = { + .attr = rtl8367_port, + .n_attr = ARRAY_SIZE(rtl8367_port), + }, + .attr_vlan = { + .attr = rtl8367_vlan, + .n_attr = ARRAY_SIZE(rtl8367_vlan), + }, + + .get_vlan_ports = rtl8367_sw_get_vlan_ports, + .set_vlan_ports = rtl8367_sw_set_vlan_ports, + .get_port_pvid = rtl8367_sw_get_port_pvid, + .set_port_pvid = rtl8367_sw_set_port_pvid, + .reset_switch = rtl8367_sw_reset_switch, + .get_port_link = rtl8367_sw_get_port_link, +}; + +int rtl8367s_swconfig_init(void (*reset_func)(void)) +{ + struct rtl8367_priv *priv = &rtl8367_priv_data; + struct switch_dev *dev=&priv->swdev; + int err=0; + + rtl8367_switch_reset_func = reset_func ; + + memset(priv, 0, sizeof(struct rtl8367_priv)); + priv->global_vlan_enable =0; + + dev->name = "RTL8367C"; + dev->cpu_port = RTL8367C_SW_CPU_PORT; + dev->ports = RTL8367C_NUM_PORTS; + dev->vlans = RTL8367C_NUM_VIDS; + dev->ops = &rtl8367_sw_ops; + dev->alias = "RTL8367C"; + err = register_switch(dev, NULL); + + pr_info("[%s]\n",__func__); + + return err; +} diff --git a/drivers/net/phy/rtk/rtl8367s_dbg.c b/drivers/net/phy/rtk/rtl8367s_dbg.c new file mode 100644 index 000000000000..6bc9cbbf0638 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367s_dbg.c @@ -0,0 +1,648 @@ +#include +#include +#include +#include +#include + +#include "./rtl8367c/include/rtk_switch.h" +#include "./rtl8367c/include/port.h" +#include "./rtl8367c/include/vlan.h" +#include "./rtl8367c/include/rtl8367c_asicdrv_port.h" +#include "./rtl8367c/include/stat.h" +#include "./rtl8367c/include/l2.h" +#include "./rtl8367c/include/smi.h" +#include "./rtl8367c/include/mirror.h" +#include "./rtl8367c/include/igmp.h" +#include "./rtl8367c/include/leaky.h" + +static struct proc_dir_entry *proc_reg_dir; +static struct proc_dir_entry *proc_esw_cnt; +static struct proc_dir_entry *proc_vlan_cnt; +static struct proc_dir_entry *proc_mac_tbl; +static struct proc_dir_entry *proc_reg; +static struct proc_dir_entry *proc_phyreg; +static struct proc_dir_entry *proc_mirror; +static struct proc_dir_entry *proc_igmp; + +#define PROCREG_ESW_CNT "esw_cnt" +#define PROCREG_VLAN "vlan" +#define PROCREG_MAC_TBL "mac_tbl" +#define PROCREG_REG "reg" +#define PROCREG_PHYREG "phyreg" +#define PROCREG_MIRROR "mirror" +#define PROCREG_IGMP "igmp" +#define PROCREG_DIR "rtk_gsw" + +#define RTK_SW_VID_RANGE 16 + +static void rtk_dump_mib_type(rtk_stat_port_type_t cntr_idx) +{ + rtk_port_t port; + rtk_stat_counter_t Cntr; + + for (port = UTP_PORT0; port < (UTP_PORT0 + 5); port++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu", Cntr); + } + + for (port = EXT_PORT0; port < (EXT_PORT0 + 2); port++) { + rtk_stat_port_get(port, cntr_idx, &Cntr); + printk("%8llu", Cntr); + } + + printk("\n"); +} +static void rtk_hal_dump_mib(void) +{ + + printk("==================%8s%8s%8s%8s%8s%8s%8s\n", "Port0", "Port1", + "Port2", "Port3", "Port4", "Port16", "Port17"); + /* Get TX Unicast Pkts */ + printk("TX Unicast Pkts :"); + rtk_dump_mib_type(STAT_IfOutUcastPkts); + /* Get TX Multicast Pkts */ + printk("TX Multicast Pkts:"); + rtk_dump_mib_type(STAT_IfOutMulticastPkts); + /* Get TX BroadCast Pkts */ + printk("TX BroadCast Pkts:"); + rtk_dump_mib_type(STAT_IfOutBroadcastPkts); + /* Get TX Collisions */ + /* Get TX Puase Frames */ + printk("TX Pause Frames :"); + rtk_dump_mib_type(STAT_Dot3OutPauseFrames); + /* Get TX Drop Events */ + /* Get RX Unicast Pkts */ + printk("RX Unicast Pkts :"); + rtk_dump_mib_type(STAT_IfInUcastPkts); + /* Get RX Multicast Pkts */ + printk("RX Multicast Pkts:"); + rtk_dump_mib_type(STAT_IfInMulticastPkts); + /* Get RX Broadcast Pkts */ + printk("RX Broadcast Pkts:"); + rtk_dump_mib_type(STAT_IfInBroadcastPkts); + /* Get RX FCS Erros */ + printk("RX FCS Errors :"); + rtk_dump_mib_type(STAT_Dot3StatsFCSErrors); + /* Get RX Undersize Pkts */ + printk("RX Undersize Pkts:"); + rtk_dump_mib_type(STAT_EtherStatsUnderSizePkts); + /* Get RX Discard Pkts */ + printk("RX Discard Pkts :"); + rtk_dump_mib_type(STAT_Dot1dTpPortInDiscards); + /* Get RX Fragments */ + printk("RX Fragments :"); + rtk_dump_mib_type(STAT_EtherStatsFragments); + /* Get RX Oversize Pkts */ + printk("RX Oversize Pkts :"); + rtk_dump_mib_type(STAT_EtherOversizeStats); + /* Get RX Jabbers */ + printk("RX Jabbers :"); + rtk_dump_mib_type(STAT_EtherStatsJabbers); + /* Get RX Pause Frames */ + printk("RX Pause Frames :"); + rtk_dump_mib_type(STAT_Dot3InPauseFrames); + /* clear MIB */ + rtk_stat_global_reset(); + +} + +static int rtk_hal_dump_vlan(void) +{ + rtk_vlan_cfg_t vlan; + int i; + + printk("vid portmap\n"); + for (i = 0; i < RTK_SW_VID_RANGE; i++) { + rtk_vlan_get(i, &vlan); + printk("%3d ", i); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT0) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT1) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT2) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT3) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + UTP_PORT4) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + EXT_PORT0) ? '1' : '-'); + printk("%c", + RTK_PORTMASK_IS_PORT_SET(vlan.mbr, + EXT_PORT1) ? '1' : '-'); + printk("\n"); + } + + return 0; +} + +static void rtk_hal_dump_table(void) +{ + rtk_uint32 i; + rtk_uint32 address = 0; + rtk_l2_ucastAddr_t l2_data; + rtk_l2_ipMcastAddr_t ipMcastAddr; + rtk_l2_age_time_t age_timout; + + rtk_l2_aging_get(&age_timout); + printk("Mac table age timeout =%d\n",(unsigned int)age_timout); + + printk("hash port(0:17) fid vid mac-address\n"); + while (1) { + if (rtk_l2_addr_next_get(READMETHOD_NEXT_L2UC, UTP_PORT0, &address, &l2_data) != RT_ERR_OK) { + break; + } else { + printk("%03x ", l2_data.address); + for (i = 0; i < 5; i++) + if ( l2_data.port == i) + printk("1"); + else + printk("-"); + for (i = 16; i < 18; i++) + if ( l2_data.port == i) + printk("1"); + else + printk("-"); + + printk(" %2d", l2_data.fid); + printk(" %4d", l2_data.cvid); + printk(" %02x%02x%02x%02x%02x%02x\n", l2_data.mac.octet[0], + l2_data.mac.octet[1], l2_data.mac.octet[2], l2_data.mac.octet[3], + l2_data.mac.octet[4], l2_data.mac.octet[5]); + address ++; + } + } + + address = 0; + while (1) { + if (rtk_l2_ipMcastAddr_next_get(&address, &ipMcastAddr) != RT_ERR_OK) { + break; + } else { + printk("%03x ", ipMcastAddr.address); + for (i = 0; i < 5; i++) + printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); + for (i = 16; i < 18; i++) + printk("%c", RTK_PORTMASK_IS_PORT_SET(ipMcastAddr.portmask, i) ? '1' : '-'); + printk(" "); + printk("01005E%06x\n", (ipMcastAddr.dip & 0xefffff)); + address ++; + } + } +} + +static void rtk_hal_clear_table(void) +{ + rtk_api_ret_t ret; + + ret = rtk_l2_table_clear(); + if (ret != RT_ERR_OK) + printk("rtk_l2_table_clear failed\n"); +} + +static void rtk_hal_read_reg(unsigned int reg_addr) +{ + ret_t retVal; + unsigned int reg_val; + + retVal = smi_read(reg_addr, ®_val); + + if(retVal != RT_ERR_OK) + printk("switch reg read failed\n"); + else + printk("reg0x%x = 0x%x\n", reg_addr, reg_val); +} + +static void rtk_hal_write_reg(unsigned int reg_addr , unsigned int reg_val) +{ + ret_t retVal; + + retVal = smi_write(reg_addr, reg_val); + + if(retVal != RT_ERR_OK) + printk("switch reg write failed\n"); + else + printk("write switch reg0x%x 0x%x success\n", reg_addr, reg_val); +} + +static void rtk_hal_get_phy_reg(unsigned int port ,unsigned int reg_addr ) +{ + ret_t retVal; + rtk_port_phy_data_t Data; + + retVal = rtk_port_phyReg_get(port, reg_addr, &Data); + if (retVal == RT_ERR_OK) + printk("Get: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, Data); + else + printk("read phy reg failed\n"); +} + +static void rtk_hal_set_phy_reg(unsigned int port ,unsigned int reg_addr,unsigned int reg_val) +{ + ret_t retVal; + + retVal = rtk_port_phyReg_set(port, reg_addr, reg_val); + if (retVal == RT_ERR_OK) + printk("Set: phy[%d].reg[%d] = 0x%04x\n", port, reg_addr, reg_val); + else + printk("write phy reg failed\n"); +} + +static void rtk_hal_set_port_mirror(unsigned int port ,unsigned int rx_port_map,unsigned int tx_port_map) +{ + rtk_portmask_t rx_portmask; + rtk_portmask_t tx_portmask; + rtk_api_ret_t ret; + int i; + + rtk_mirror_portIso_set(ENABLED); + RTK_PORTMASK_CLEAR(rx_portmask); + RTK_PORTMASK_CLEAR(tx_portmask); + + for (i = 0; i < 5; i++) + if (rx_port_map & (1 << i)) + RTK_PORTMASK_PORT_SET(rx_portmask, i); + + for (i = 0; i < 2; i++) + if (rx_port_map & (1 << (i + 5))) + RTK_PORTMASK_PORT_SET(rx_portmask, (i + EXT_PORT0)); + + RTK_PORTMASK_CLEAR(tx_portmask); + + for (i = 0; i < 5; i++) + if (tx_port_map & (1 << i)) + RTK_PORTMASK_PORT_SET(tx_portmask, i); + + for (i = 0; i < 2; i++) + if (tx_port_map & (1 << (i + 5))) + RTK_PORTMASK_PORT_SET(tx_portmask, (i + EXT_PORT0)); + + ret = rtk_mirror_portBased_set(port, &rx_portmask, &tx_portmask); + + if (!ret) + printk("rtk_mirror_portBased_set success\n"); + +} + +static void rtk_hal_enable_igmpsnoop(int hw_on) +{ + rtk_api_ret_t ret; + rtk_portmask_t pmask; + + ret = rtk_igmp_init(); + if (hw_on == 1) { + RTK_PORTMASK_CLEAR(pmask); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); + ret |= rtk_igmp_static_router_port_set(&pmask); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT4, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_IGMPv2, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(EXT_PORT1, PROTOCOL_MLDv1, IGMP_ACTION_FORWARD); + ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + + ret |= rtk_leaky_vlan_set(LEAKY_IPMULTICAST, ENABLED); + ret |= rtk_l2_ipMcastForwardRouterPort_set(DISABLED); + /* drop unknown multicast packets*/ + /* ret |= rtk_trap_unknownMcastPktAction_set(UTP_PORT4, MCAST_IPV4, MCAST_ACTION_DROP);*/ + } else { + RTK_PORTMASK_CLEAR(pmask); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT0); + RTK_PORTMASK_PORT_SET(pmask, EXT_PORT1); + ret |= rtk_igmp_protocol_set(UTP_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT1, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT2, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(UTP_PORT3, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + ret |= rtk_igmp_protocol_set(EXT_PORT0, PROTOCOL_IGMPv3, IGMP_ACTION_ASIC); + + ret |= rtk_igmp_static_router_port_set(&pmask); + } + + if(ret != RT_ERR_OK) + printk("enable switch igmpsnoop failed\n"); + +} + +static void rtk_hal_disable_igmpsnoop(void) +{ + if (rtk_igmp_state_set(DISABLED) != RT_ERR_OK) + printk("Disable IGMP SNOOPING failed\n"); +} + +static ssize_t mac_tbl_write(struct file *file, + const char __user *buffer, size_t count, + loff_t *data) +{ + rtk_hal_clear_table(); + + return count; +} + + +static ssize_t phyreg_ops(struct file *file, + const char __user *buffer, size_t count, + loff_t *data) +{ + char buf[64]; + unsigned int port; + unsigned int offset; + unsigned int val; + + memset(buf, 0, 64); + + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + + if(buf[0] == 'w') { + + if(sscanf(buf, "w %d %x %x", &port,&offset,&val) == -1) + return -EFAULT; + else + rtk_hal_set_phy_reg(port,offset,val); + + } else { + + if(sscanf(buf, "r %d %x",&port, &offset) == -1) + return -EFAULT; + else + rtk_hal_get_phy_reg(port,offset); + } + + return count; +} + +static ssize_t reg_ops(struct file *file, + const char __user *buffer, size_t count, + loff_t *data) +{ + char buf[64]; + unsigned int offset; + unsigned int val; + + memset(buf, 0, 64); + + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + + if(buf[0] == 'w') { + + if(sscanf(buf, "w %x %x", &offset,&val) == -1) + return -EFAULT; + else + rtk_hal_write_reg(offset,val); + + } else { + + if(sscanf(buf, "r %x", &offset) == -1) + return -EFAULT; + else + rtk_hal_read_reg(offset); + } + + return count; +} + +static ssize_t mirror_ops(struct file *file, + const char __user *buffer, size_t count, + loff_t *data) +{ + char buf[64]; + unsigned int port; + unsigned int tx_map,rx_map; + + memset(buf, 0, 64); + + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + if(sscanf(buf, "%d %x %x", &port,&rx_map,&tx_map) == -1) + return -EFAULT; + else + rtk_hal_set_port_mirror(port,rx_map,tx_map); + + return count; +} + + +static ssize_t igmp_ops(struct file *file, + const char __user *buffer, size_t count, + loff_t *data) +{ + char buf[8]; + unsigned int ops; + + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + if(sscanf(buf, "%d", &ops) == -1) + return -EFAULT; + + if(ops == 0) + rtk_hal_disable_igmpsnoop(); + else if (ops == 1) + rtk_hal_enable_igmpsnoop(0); + else //hw igmp + rtk_hal_enable_igmpsnoop(1); + + return count; +} + + +static int esw_cnt_read(struct seq_file *seq, void *v) +{ + rtk_hal_dump_mib(); + return 0; +} + +static int vlan_read(struct seq_file *seq, void *v) +{ + rtk_hal_dump_vlan(); + return 0; +} + +static int mac_tbl_read(struct seq_file *seq, void *v) +{ + rtk_hal_dump_table(); + return 0; +} + +static int reg_show(struct seq_file *seq, void *v) +{ + return 0; +} + +static int phyreg_show(struct seq_file *seq, void *v) +{ + return 0; +} + +static int mirror_show(struct seq_file *seq, void *v) +{ + return 0; +} + +static int igmp_show(struct seq_file *seq, void *v) +{ + return 0; +} + +static int switch_count_open(struct inode *inode, struct file *file) +{ + return single_open(file, esw_cnt_read, 0); +} + +static int switch_vlan_open(struct inode *inode, struct file *file) +{ + return single_open(file, vlan_read, 0); +} + +static int mac_tbl_open(struct inode *inode, struct file *file) +{ + return single_open(file, mac_tbl_read, 0); +} + +static int reg_open(struct inode *inode, struct file *file) +{ + return single_open(file, reg_show, 0); +} + +static int phyreg_open(struct inode *inode, struct file *file) +{ + return single_open(file, phyreg_show, 0); +} + +static int mirror_open(struct inode *inode, struct file *file) +{ + return single_open(file, mirror_show, 0); +} + +static int igmp_open(struct inode *inode, struct file *file) +{ + return single_open(file, igmp_show, 0); +} + + +static const struct proc_ops switch_count_fops = { + .proc_open = switch_count_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release +}; + +static const struct proc_ops switch_vlan_fops = { + .proc_open = switch_vlan_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release +}; + +static const struct proc_ops mac_tbl_fops = { + .proc_open = mac_tbl_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = mac_tbl_write, + .proc_release = single_release +}; + +static const struct proc_ops reg_fops = { + .proc_open = reg_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = reg_ops, + .proc_release = single_release +}; + +static const struct proc_ops phyreg_fops = { + .proc_open = phyreg_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = phyreg_ops, + .proc_release = single_release +}; + +static const struct proc_ops mirror_fops = { + .proc_open = mirror_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = mirror_ops, + .proc_release = single_release +}; + +static const struct proc_ops igmp_fops = { + .proc_open = igmp_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_write = igmp_ops, + .proc_release = single_release +}; + +int gsw_debug_proc_init(void) +{ + + if (!proc_reg_dir) + proc_reg_dir = proc_mkdir(PROCREG_DIR, NULL); + + proc_esw_cnt = + proc_create(PROCREG_ESW_CNT, 0, proc_reg_dir, &switch_count_fops); + + if (!proc_esw_cnt) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_ESW_CNT); + + proc_vlan_cnt = + proc_create(PROCREG_VLAN, 0, proc_reg_dir, &switch_vlan_fops); + + if (!proc_vlan_cnt) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_VLAN); + + proc_mac_tbl = + proc_create(PROCREG_MAC_TBL, 0, proc_reg_dir, &mac_tbl_fops); + + if (!proc_mac_tbl) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MAC_TBL); + + proc_reg = + proc_create(PROCREG_REG, 0, proc_reg_dir, ®_fops); + + if (!proc_reg) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_REG); + + proc_phyreg = + proc_create(PROCREG_PHYREG, 0, proc_reg_dir, &phyreg_fops); + + if (!proc_phyreg) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_PHYREG); + + proc_mirror = + proc_create(PROCREG_MIRROR, 0, proc_reg_dir, &mirror_fops); + + if (!proc_mirror) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_MIRROR); + + proc_igmp = + proc_create(PROCREG_IGMP, 0, proc_reg_dir, &igmp_fops); + + if (!proc_igmp) + pr_err("!! FAIL to create %s PROC !!\n", PROCREG_IGMP); + + return 0; +} + +void gsw_debug_proc_exit(void) +{ + if (proc_esw_cnt) + remove_proc_entry(PROCREG_ESW_CNT, proc_reg_dir); +} + + diff --git a/drivers/net/phy/rtk/rtl8367s_mdio.c b/drivers/net/phy/rtk/rtl8367s_mdio.c new file mode 100644 index 000000000000..2f9dc0da6bc1 --- /dev/null +++ b/drivers/net/phy/rtk/rtl8367s_mdio.c @@ -0,0 +1,301 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "./rtl8367c/include/rtk_switch.h" +#include "./rtl8367c/include/port.h" +#include "./rtl8367c/include/vlan.h" +#include "./rtl8367c/include/rtl8367c_asicdrv_port.h" +#include "./rtl8367c/include/rtl8367c_asicdrv_mii_mgr.h" + +struct rtk_gsw { + struct device *dev; + struct mii_bus *bus; + int reset_pin; +}; + +static struct rtk_gsw *_gsw; + +/*mii_mgr_read/mii_mgr_write is the callback API for rtl8367 driver*/ +unsigned int mii_mgr_read(unsigned int phy_addr,unsigned int phy_register,unsigned int *read_data) +{ + struct mii_bus *bus = _gsw->bus; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + + *read_data = bus->read(bus, phy_addr, phy_register); + + mutex_unlock(&bus->mdio_lock); + + return 0; +} + +unsigned int mii_mgr_write(unsigned int phy_addr,unsigned int phy_register,unsigned int write_data) +{ + struct mii_bus *bus = _gsw->bus; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + + bus->write(bus, phy_addr, phy_register, write_data); + + mutex_unlock(&bus->mdio_lock); + + return 0; +} + +static int rtl8367s_hw_reset(void) +{ + struct rtk_gsw *gsw = _gsw; + + if (gsw->reset_pin < 0) + return 0; + + gpio_direction_output(gsw->reset_pin, 0); + + usleep_range(1000, 1100); + + gpio_set_value(gsw->reset_pin, 1); + + mdelay(500); + + return 0; +} + +static int rtl8367s_vlan_config(int want_at_p0) +{ + rtk_vlan_cfg_t vlan1, vlan2; + + /* Set LAN/WAN VLAN partition */ + memset(&vlan1, 0x00, sizeof(rtk_vlan_cfg_t)); + + RTK_PORTMASK_PORT_SET(vlan1.mbr, EXT_PORT0); + RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT1); + RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT2); + RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT3); + RTK_PORTMASK_PORT_SET(vlan1.untag, EXT_PORT0); + RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT1); + RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT2); + RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT3); + + if (want_at_p0) { + RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT4); + RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT4); + } else { + RTK_PORTMASK_PORT_SET(vlan1.mbr, UTP_PORT0); + RTK_PORTMASK_PORT_SET(vlan1.untag, UTP_PORT0); + } + + vlan1.ivl_en = 1; + + rtk_vlan_set(1, &vlan1); + + memset(&vlan2, 0x00, sizeof(rtk_vlan_cfg_t)); + + RTK_PORTMASK_PORT_SET(vlan2.mbr, EXT_PORT1); + RTK_PORTMASK_PORT_SET(vlan2.untag, EXT_PORT1); + + if (want_at_p0) { + RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT0); + RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT0); + } else { + RTK_PORTMASK_PORT_SET(vlan2.mbr, UTP_PORT4); + RTK_PORTMASK_PORT_SET(vlan2.untag, UTP_PORT4); + } + + vlan2.ivl_en = 1; + rtk_vlan_set(2, &vlan2); + + rtk_vlan_portPvid_set(EXT_PORT0, 1, 0); + rtk_vlan_portPvid_set(UTP_PORT1, 1, 0); + rtk_vlan_portPvid_set(UTP_PORT2, 1, 0); + rtk_vlan_portPvid_set(UTP_PORT3, 1, 0); + rtk_vlan_portPvid_set(EXT_PORT1, 2, 0); + + if (want_at_p0) { + rtk_vlan_portPvid_set(UTP_PORT0, 2, 0); + rtk_vlan_portPvid_set(UTP_PORT4, 1, 0); + } else { + rtk_vlan_portPvid_set(UTP_PORT0, 1, 0); + rtk_vlan_portPvid_set(UTP_PORT4, 2, 0); + } + + return 0; +} + +static int rtl8367s_hw_init(void) +{ + + rtl8367s_hw_reset(); + + if(rtk_switch_init()) + return -1; + + mdelay(500); + + if (rtk_vlan_reset()) + return -1; + + if (rtk_vlan_init()) + return -1; + + return 0; +} + +static void set_rtl8367s_sgmii(void) +{ + rtk_port_mac_ability_t mac_cfg; + rtk_mode_ext_t mode; + + mode = MODE_EXT_HSGMII; + mac_cfg.forcemode = MAC_FORCE; + mac_cfg.speed = PORT_SPEED_2500M; + mac_cfg.duplex = PORT_FULL_DUPLEX; + mac_cfg.link = PORT_LINKUP; + mac_cfg.nway = DISABLED; + mac_cfg.txpause = ENABLED; + mac_cfg.rxpause = ENABLED; + rtk_port_macForceLinkExt_set(EXT_PORT0, mode, &mac_cfg); + rtk_port_sgmiiNway_set(EXT_PORT0, DISABLED); + rtk_port_phyEnableAll_set(ENABLED); + +} + +static void set_rtl8367s_rgmii(void) +{ + rtk_port_mac_ability_t mac_cfg; + rtk_mode_ext_t mode; + + mode = MODE_EXT_RGMII; + mac_cfg.forcemode = MAC_FORCE; + mac_cfg.speed = PORT_SPEED_1000M; + mac_cfg.duplex = PORT_FULL_DUPLEX; + mac_cfg.link = PORT_LINKUP; + mac_cfg.nway = DISABLED; + mac_cfg.txpause = ENABLED; + mac_cfg.rxpause = ENABLED; + rtk_port_macForceLinkExt_set(EXT_PORT1, mode, &mac_cfg); + rtk_port_rgmiiDelayExt_set(EXT_PORT1, 1, 3); + rtk_port_phyEnableAll_set(ENABLED); + +} + +static void init_gsw(void) +{ + rtl8367s_hw_init(); + set_rtl8367s_sgmii(); + set_rtl8367s_rgmii(); +} + +// below are platform driver +static const struct of_device_id rtk_gsw_match[] = { + { .compatible = "mediatek,rtk-gsw" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rtk_gsw_match); + +static int rtk_gsw_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *mdio; + struct mii_bus *mdio_bus; + struct rtk_gsw *gsw; + const char *pm; + int ret; + + mdio = of_parse_phandle(np, "mediatek,mdio", 0); + + if (!mdio) + return -EINVAL; + + mdio_bus = of_mdio_find_bus(mdio); + + if (!mdio_bus) + return -EPROBE_DEFER; + + gsw = devm_kzalloc(&pdev->dev, sizeof(struct rtk_gsw), GFP_KERNEL); + + if (!gsw) + return -ENOMEM; + + gsw->dev = &pdev->dev; + + gsw->bus = mdio_bus; + + gsw->reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0); + if (gsw->reset_pin >= 0) { + ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mediatek,reset-pin"); + if (ret) + printk("fail to devm_gpio_request\n"); + } + + _gsw = gsw; + + init_gsw(); + + //init default vlan or init swconfig + if(!of_property_read_string(pdev->dev.of_node, + "mediatek,port_map", &pm)) { + + if (!strcasecmp(pm, "wllll")) + rtl8367s_vlan_config(1); + else + rtl8367s_vlan_config(0); + + } else { +#ifdef CONFIG_SWCONFIG + rtl8367s_swconfig_init(&init_gsw); +#else + rtl8367s_vlan_config(0); +#endif + } + + gsw_debug_proc_init(); + + platform_set_drvdata(pdev, gsw); + + return 0; + +} + +static void rtk_gsw_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + gsw_debug_proc_exit(); +} + +static struct platform_driver gsw_driver = { + .probe = rtk_gsw_probe, + .remove_new = rtk_gsw_remove, + .driver = { + .name = "rtk-gsw", + .of_match_table = rtk_gsw_match, + }, +}; + +module_platform_driver(gsw_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Lee "); +MODULE_DESCRIPTION("rtl8367c switch driver for MT7622"); + diff --git a/drivers/net/phy/rtl8261n/Kconfig b/drivers/net/phy/rtl8261n/Kconfig new file mode 100644 index 000000000000..cdb5cb74882a --- /dev/null +++ b/drivers/net/phy/rtl8261n/Kconfig @@ -0,0 +1,5 @@ + +config RTL8261N_PHY + tristate "Driver for Realtek RTL8261N PHYs" + help + Currently supports the RTL8261N,RTL8264B PHYs. diff --git a/drivers/net/phy/rtl8261n/Makefile b/drivers/net/phy/rtl8261n/Makefile new file mode 100644 index 000000000000..fd4afb43b509 --- /dev/null +++ b/drivers/net/phy/rtl8261n/Makefile @@ -0,0 +1,11 @@ + +obj-$(CONFIG_RTL8261N_PHY) += rtl8261n.o + +rtl8261n-objs += phy_patch.o +rtl8261n-objs += phy_rtl826xb_patch.o +rtl8261n-objs += rtk_osal.o +rtl8261n-objs += rtk_phy.o +rtl8261n-objs += rtk_phylib.o +rtl8261n-objs += rtk_phylib_rtl826xb.o + +ccflags-y += -Werror -DRTK_PHYDRV_IN_LINUX diff --git a/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c b/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c new file mode 100644 index 000000000000..8e7c714fc401 --- /dev/null +++ b/drivers/net/phy/rtl8261n/construct/conf_rtl8261n_c.c @@ -0,0 +1,1465 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +//Date: Tue Nov 15 19:53:03 2022 + +rtk_hwpatch_t rtl8261n_c_top_conf[] = { + {RTK_PATCH_OP_TOP , 0xf , 2 , 20 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 21 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 22 , 15, 0 , 0x280 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 23 , 15, 0 , 0x0014, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 16 , 15, 0 , 0x0300, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 17 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 18 , 15, 0 , 0x000c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 19 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 20 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 21 , 15, 0 , 0x0015, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 22 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 23 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 4 , 16 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 13 , 23 , 8 , 5 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 18 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 19 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 15, 8 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_sds_conf[] = { + {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x881F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0D , 15, 0 , 0x0F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0E , 15, 0 , 0x3F5A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 15, 12, 0x8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 7 , 0 , 0x3 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x1D , 15, 0 , 0x0600, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x00 , 15, 0 , 0x4902, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x08 , 15, 0 , 0x0FC0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x09 , 15, 0 , 0x33F0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x0C , 15, 0 , 0x08BF, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x12 , 15, 0 , 0x8000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x07 , 15, 0 , 0x04C0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x08 , 15, 0 , 0x2000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0C , 15, 0 , 0xAA17, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0D , 15, 0 , 0xFE40, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x00 , 15, 0 , 0x1F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x01 , 15, 0 , 0x2800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x11 , 15, 0 , 0x3000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x1E , 15, 0 , 0x0500, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x880D, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x0024, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x0036, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x0035, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x001B, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 7 , 0 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_afe_conf[] = { +}; + +rtk_hwpatch_t rtl8261n_c_uc_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8a, 5 , 3 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8c, 6 , 4 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8060, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 10, 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8061, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa466, 1 , 1 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8491, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x3D , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_uc2_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87c, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8af6, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b41, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4faf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b5b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b00}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b02}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb4af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b04}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b06}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b08}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdaaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf70, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b20}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5ee2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b22}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b24}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b26}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b28}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b30}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b32}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe087, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b34}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ef6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b36}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x27e4, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b38}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x871e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfcef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x94fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04a1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b40}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0103, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b42}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b44}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfee0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b46}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a09, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b48}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5bac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b50}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf62, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b52}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b54}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b56}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf62, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b58}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb0bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x68e0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x72ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b60}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b62}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x68dd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b64}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b66}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x721e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b68}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3819, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf68, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe902, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b70}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b72}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b74}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf68, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b76}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b78}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1e31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac38, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b80}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b82}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x02ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b84}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b86}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b88}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04ee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8933, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b90}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ff9, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b92}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe189, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b94}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x331a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b96}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x91db, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b98}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4c02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f00, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f22, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1b45, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad27, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x870d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8baa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae03, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe187, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d1a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0248, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf702, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0222, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4faf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4176, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70eb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd300, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0241, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7caf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46b2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bda}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bde}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d63, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x72e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe58f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdfc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c00}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c02}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c04}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c06}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c08}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6753, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c20}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c22}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c24}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c26}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c28}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ffc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c30}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c32}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c34}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6753, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c36}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c38}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c40}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c42}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c44}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8fa, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c46}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c48}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6772, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c50}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c52}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c93, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c54}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c56}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c58}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c90, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ad1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c60}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0fbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c62}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c96, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c64}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c66}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c68}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c99, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xebd1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c70}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c9c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c72}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c74}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c76}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c9f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c78}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4d1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ca2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c80}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0267, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c82}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x53bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c84}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8ca5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c86}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c88}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf4ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c90}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6c66, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c92}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd6c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c94}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c96}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5444, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c98}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa7bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cbb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb85e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x62ba, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb860, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e56, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb862, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6287, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb864, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d07, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb886, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4170, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb888, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46ad, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb838, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x003f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_nctl0_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd719, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bb7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12db, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1301, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA026, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA024, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA022, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA020, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA006, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA004, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA002, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA000, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12d7, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA008, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_nctl1_conf[] = { +}; + +rtk_hwpatch_t rtl8261n_c_nctl2_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8029, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8217, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82d0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8322, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcb0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d18, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f73, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8034, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8031, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1bf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1dd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x70}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x71}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x72}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x73}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x74}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x75}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x76}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x77}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x78}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x79}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x80}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x81}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x82}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x83}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x84}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x85}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd33, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x86}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x87}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x88}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x89}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x90}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffee, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x91}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x92}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x93}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x94}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x95}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x96}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x97}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x98}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x99}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd34, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80bb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd19f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4368, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80d7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x80d4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xda}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6074, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xde}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfff9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4070, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xeb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x100}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x101}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x102}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x103}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x104}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x105}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x106}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x107}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x108}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x109}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x110}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x111}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x112}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x113}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x114}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x115}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x116}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x117}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x118}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x119}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x120}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x121}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x122}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x123}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x124}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd35, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x125}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x126}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x127}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x128}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x129}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x130}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x131}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x132}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x133}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x134}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x135}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x136}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x137}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x138}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x139}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbb80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x140}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x141}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x142}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd36, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x143}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x144}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x145}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x146}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x147}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x148}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x149}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffe8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x150}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x151}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x152}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x153}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x154}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x155}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x156}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x157}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x158}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x147c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x159}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1435, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1485, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x160}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x161}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x162}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x163}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x164}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd37, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x165}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x166}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x167}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x168}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x169}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x170}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x171}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x172}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x173}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x174}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x817e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x175}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x176}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x817b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x177}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x178}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x179}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x180}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x181}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x182}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x183}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x184}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x185}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x186}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x187}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x188}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x189}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x190}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x819a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x191}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x192}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8197, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x193}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x194}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x195}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x196}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x197}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x198}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x199}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd189, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1aa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa180, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1be}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81d4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81cc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1da}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd055, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1de}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c12, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8206, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81fe, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x200}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x201}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x202}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x203}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd040, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x204}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x205}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x206}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x207}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x208}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x209}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x210}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x211}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x212}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x213}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x214}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x215}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x087a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x216}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x217}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x646d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x218}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x219}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8231, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8227, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x220}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x221}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x222}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x223}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x224}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x225}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x226}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x227}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x228}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x229}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x230}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x231}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x232}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x233}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x234}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x235}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x236}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x237}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x238}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x239}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x240}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x241}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x242}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x243}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f29, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x244}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x245}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x246}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x247}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x248}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x249}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x250}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x251}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x252}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x253}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x254}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x255}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x256}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x257}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x142d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x258}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x259}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x260}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa420, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x261}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x262}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x263}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65ad, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x264}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x265}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x266}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x267}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x827b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x268}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x269}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8273, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x270}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x271}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf021, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x272}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x273}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x274}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x275}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x276}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x277}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x278}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x279}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x280}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x281}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x282}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x283}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x284}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x828e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x285}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x286}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x828b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x287}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x288}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x289}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd191, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x290}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x291}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x292}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x293}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1418, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x294}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x295}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1463, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x296}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x297}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x298}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x299}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40e7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x644d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2aa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82b9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf016, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2be}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0956, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2969, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82eb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82e1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2da}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2de}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x09a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2969, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x831e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8314, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x830a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x300}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x301}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x302}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x303}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x304}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x305}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x306}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x307}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x308}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x309}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x310}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x311}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x312}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x313}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x314}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x315}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x316}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x317}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x318}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x319}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x320}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a39, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x321}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA108, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a12, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA106, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0979, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA104, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x089f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA102, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0692, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA100, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f60, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA164, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0baa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c19, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1293, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA162, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0007, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_algxg_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8165, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x22 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x68 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8013, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x39 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffa, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82D9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82DA, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x00 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x816E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8159, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x99 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8139, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8125, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x67 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8126, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x89 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x42 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_alg_giga_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8367, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x5d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_normal_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x817d, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb516, 6 , 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffe, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x04 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fff, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80ca, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8062, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8064, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x801E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0005, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_dataram_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb892, 15, 8 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC149, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC169, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x09 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0D , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x11 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC171, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x10 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC173, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC128, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC129, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC130, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC131, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC133, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC135, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x1 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8261n_c_rtct_conf[] = { +}; + diff --git a/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c b/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c new file mode 100644 index 000000000000..d5cae3fd3bac --- /dev/null +++ b/drivers/net/phy/rtl8261n/construct/conf_rtl8264b.c @@ -0,0 +1,2177 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +//Date: Thu Dec 15 16:01:01 2022 + +rtk_hwpatch_t rtl8264b_top_conf[] = { + {RTK_PATCH_OP_TOP , 0xf , 2 , 20 , 15, 0 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 21 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 22 , 15, 0 , 0x280 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 2 , 23 , 15, 0 , 0x0014, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 16 , 15, 0 , 0x0300, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 17 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 18 , 15, 0 , 0x000c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 19 , 15, 0 , 0x01ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 20 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 21 , 15, 0 , 0x0015, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 22 , 15, 0 , 0x0200, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 3 , 23 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 4 , 16 , 15, 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 13 , 23 , 8 , 5 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 18 , 15, 0 , 0xc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 19 , 15, 0 , 0xc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 15, 8 , 0x01 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_sds_conf[] = { + {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x881F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x003F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001F, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0D , 15, 0 , 0x0F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x0E , 15, 0 , 0x3F5A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 15, 12, 0x8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x07 , 0x10 , 7 , 0 , 0x3 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x06 , 0x1D , 15, 0 , 0x0600, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x00 , 15, 0 , 0x4902, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x08 , 15, 0 , 0x0FC0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x09 , 15, 0 , 0x33F0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x0C , 15, 0 , 0x08BF, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x21 , 0x12 , 15, 0 , 0x8000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x07 , 15, 0 , 0x04C0, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x36 , 0x08 , 15, 0 , 0x2000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0C , 15, 0 , 0xAA17, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0D , 15, 0 , 0xFE40, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2E , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x00 , 15, 0 , 0x1F00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x01 , 15, 0 , 0x2800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x11 , 15, 0 , 0x3000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2F , 0x1E , 15, 0 , 0x0500, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x34 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x35 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0C , 15, 0 , 0xA517, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0D , 15, 0 , 0xFE41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2C , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x2D , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x15 , 15, 0 , 0x7A61, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x28 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x29 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x26 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x27 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0B , 15, 0 , 0x2390, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0C , 15, 0 , 0xA514, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0D , 15, 0 , 0xFE43, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x0E , 15, 0 , 0x12F4, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x11 , 15, 0 , 0xF2AD, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x15 , 15, 0 , 0x7A41, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x24 , 0x16 , 15, 0 , 0x0041, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x00 , 15, 0 , 0x1F80, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x01 , 15, 0 , 0x0800, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x02 , 15, 0 , 0x0FC8, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x11 , 15, 0 , 0x3001, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x13 , 15, 0 , 0xF400, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x25 , 0x1E , 15, 0 , 0x0100, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 18 , 15, 0 , 0x880D, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 19 , 15, 0 , 0x0024, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 20 , 15, 0 , 0x0036, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 21 , 15, 0 , 0x0035, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 24 , 22 , 15, 0 , 0x001A, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x001B, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xf , 0x1F , 0x00 , 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 20 , 7 , 0 , 0x03 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_afe_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf92, 15, 11, 0x1C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfaa, 10, 8 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfae, 8 , 6 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbfaa, 12, 11, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf1c, 4 , 4 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0e, 5 , 4 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf1c, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf16, 12, 12, 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbc24, 3 , 2 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbc24, 1 , 0 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf08, 2 , 0 , 0x6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 5 , 3 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 8 , 6 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 11, 9 , 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbf0c, 14, 12, 0x7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_TOP , 0xf , 90 , 21 , 15, 8 , 0x03 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_uc_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8a, 5 , 3 , 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd8c, 6 , 4 , 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8060, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 10, 0x3 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8061, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 13, 0x5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa466, 1 , 1 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8491, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x1D , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8018, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 12, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x85af, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf85, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc7af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85df, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1baf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8674, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7daf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x875b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf87, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8774, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf85, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdc02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6957, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe48f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ce5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f2d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe084, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x11e1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8412, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x73f6, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb01a, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe08f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ce1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8f2d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6802, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6e02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x85ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8601}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8603}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7702, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8605}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8607}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8609}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7a02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x860f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7d02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8611}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8613}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd784, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8615}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8617}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5eed, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8619}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0286, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x21af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x07ad, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x861f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8f9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8621}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfaef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8623}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x69e0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8625}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8018, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8627}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad24, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8629}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x39d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x002e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x862f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8631}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8633}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd480, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8635}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8637}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x866e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8639}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x000f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x863f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8641}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8643}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8645}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8647}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8649}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd480, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0bbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x864f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x866e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8651}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8653}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38d4, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8655}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x000f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8657}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8659}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x865f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8661}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8663}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0208, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8665}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1eef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8667}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8669}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfdfc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04f0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd94, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x866f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8671}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9602, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8673}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8621, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8675}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0254, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8677}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcaf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8679}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03c1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0286, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x867f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8686, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8681}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf04, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8683}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x41f8, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8685}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfbef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8687}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x79e0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8689}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8018, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac20, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x868f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8756, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8691}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8693}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8695}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8697}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8699}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3102, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x869f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4902, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86a9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4f02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3702, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3402, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1f00, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe183, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd4bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bcd, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd0, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd3, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd6, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0269, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x38bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be2, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f46, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdce1, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x83d3, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x86ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8701}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3a02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8703}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8705}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d14, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8707}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8709}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4002, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d12, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x870f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8711}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3d02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8713}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6938, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8715}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8717}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4302, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8719}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70dc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0238, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x871f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bd9, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8721}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8723}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8725}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdc, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8727}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8729}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bdf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x872f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8731}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be2, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8733}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8735}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8737}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b34, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8739}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b37, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x873f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8741}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe5bf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8743}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f4f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8745}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8747}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8749}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b31, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcbf, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x874f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f4c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8751}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0270, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8753}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdcef, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8755}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x97ff, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8757}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8759}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac2f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b2a, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x875f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x020e, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8761}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x95af, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8763}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b3f, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8765}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee84, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8767}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3c00, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8769}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6c, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c02, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x70e5, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x876f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf01, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8771}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0300, RTK_PATCH_CMP_SWC , 0, 0xa438, 0xa436, 0x8773}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb818, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5d6d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5eea, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x07aa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb81e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03be, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb850, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x043e, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb852, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b26, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb878, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fd, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb884, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb832, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x007f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_uc2_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87c, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8acf, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb87e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8acf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe7af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4caf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b6a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ad9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8adb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb5af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8add}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bd1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8adf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf8c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c12, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf67, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ae9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aeb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf67, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1e31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac38, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x19bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8af9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x676c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8afd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8aff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b01}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6769, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b03}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b05}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b07}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x31ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b09}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x380c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b0f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c00, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee89, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2c01, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd5e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x892c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a91, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67cf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x221b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x45ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2705, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe187, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x06ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x03e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8707, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf2d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c1e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7b02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x224f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b49}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb8ac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2f0f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0210, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b4f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x62bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b51}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d36, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b53}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b55}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b57}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fde, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b59}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf10, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4ae1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fde, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b5f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b61}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b63}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b65}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf10, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b67}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x59e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b69}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa100, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0dbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b6f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6d36, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b71}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b73}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b75}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b77}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xee8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b79}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdd01, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b7f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6f77, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b81}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b83}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc7e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b85}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x892c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b87}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4903, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b89}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a91, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b8f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x67cf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b91}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b93}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf51f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b95}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x001f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b97}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x22ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b99}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x741b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x45ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2711, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8b9f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf86, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd0d0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ba9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf35, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8baf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x46af, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3527, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6eee, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fdd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bb9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bbf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bc9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6eaf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x36a9, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bcf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bd9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a4e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bdf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0502, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5d65, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8be9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8beb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8cc5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x025b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf302, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d0d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe087, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x17f6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bf9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x27e4, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8717, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bfd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfcef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8bff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x94fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c01}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x04a1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c03}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0103, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c05}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x028c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c07}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe9e0, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c09}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8a02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c0f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdeac, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf61, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d0d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaf61, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfafb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef79, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6766, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5ad, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2810, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad30, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0002, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae16, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad32, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x24d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0003, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae0e, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae06, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad33, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x14d7, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0001, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c49}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf8f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdf4f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0008, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c4f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a97, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c51}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd78c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c53}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c55}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c7b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c57}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c59}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bff, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef97, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfffe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c5f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c61}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c63}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0e20, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c65}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b11, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c67}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c69}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1420, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b17, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c6f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2020, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c71}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b23, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c73}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x206b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c75}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2600, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c77}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6b29, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c79}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8fa, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef69, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c7f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c81}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c83}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xad28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c85}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ebf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c87}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d34, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c89}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d31, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c8f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c91}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77ae, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c93}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2ad1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c95}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0fbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c97}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d37, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c99}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d3a, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8c9f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6ed1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d3d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ca9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d40, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8caf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77d1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d43, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cb9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d46, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x026f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cbf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x96fe, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cc9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ccf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6be6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf5e5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fd8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cd9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf202, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cdf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe58f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd9fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ce9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ceb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8ced}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fda, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cf9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cfb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cfd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8cff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xdbbf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d01}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bf2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d03}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d05}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d07}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d09}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf8ef, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x49f8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d0f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6d, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd02, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65f5, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac28, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e1, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8fd8, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf6b, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe602, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65d6, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xe18f, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd9bf, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6bf2, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0265, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd6fc, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xef94, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfc04, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x77bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6c66, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd6c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x30bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5444, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x85bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5e55, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd54, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa7bd, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cbb, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbd5c, RTK_PATCH_CMP_SWC , 0, 0xb87e, 0xb87c, 0x8d47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb85e, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d07, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb860, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40b5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb862, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1047, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb864, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3504, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb886, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x36A6, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb888, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x613d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88a, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5cd9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb88c, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x610a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xb838, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_nctl0_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8015, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8020, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x802a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8030, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8035, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8046, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x806b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x606f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x606f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcf01, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcf02, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd719, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3bb7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12bd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12e3, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xab80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc402, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x004a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x090f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x401c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce00, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x801a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce01, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aa9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd500, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2a69, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f48, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8058, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f4b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x618c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3f43, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x805e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x616b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6187, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc8b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc89, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc87, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcc91, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b9a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xca80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ba0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xca00, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd504, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1658, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa208, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a88, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d91, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA026, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d90, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA024, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1657, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA022, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0aa1, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA020, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0047, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA006, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0049, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA004, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12b9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA002, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0be5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA000, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1811, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA008, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xff00, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc483, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0ff8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xc483, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xffe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA152, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1a83, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA154, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1d29, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA156, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA158, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA15E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA160, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA150, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0003, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_nctl1_conf[] = { +}; + +rtk_hwpatch_t rtl8264b_nctl2_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x1 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8022, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8029, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8085, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x808c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8093, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8281, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x829a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x416f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd701, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fbd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0427, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x040b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8501, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd707, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x406f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01d8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01cb, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fa7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8030, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd75f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x699c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4066, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x35}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61b4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x36}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd704, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x37}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x609f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x38}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6150, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x39}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x2d71, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8043, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cf0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x05a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x3f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x40}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x41}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x42}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x43}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x44}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8220, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x45}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c30, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x46}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0410, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x47}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x48}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x49}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8684, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x4f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8203, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x50}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x51}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x52}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xaa10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x53}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8b07, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x54}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x55}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x56}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x57}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x58}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x59}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x5f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x60}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x61}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x62}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x63}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x64}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x65}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x66}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x67}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x68}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa204, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x69}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xab08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcda0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd705, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x6f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40de, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x70}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x71}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x72}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbf10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x73}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x74}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x75}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x76}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x77}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x78}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x79}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x607a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13b1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9f10, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x7f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8210, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x80}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa210, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x81}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x82}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x83}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x84}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x85}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x86}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8df8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x87}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x88}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x89}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01c1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8df8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8370, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x8f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x90}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x91}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x009e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x92}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x93}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x94}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x809e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x95}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x96}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x809b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x97}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1bf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x98}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x99}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1dd, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd06e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x9f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xa9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xaf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xb9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xbf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xc9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xcf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xd9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xda}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xde}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xdf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xe9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xeb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd33, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xf9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffee, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xfe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0xff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x100}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x101}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x102}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x103}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x104}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x105}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x106}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x107}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x108}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x109}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x10f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x110}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd34, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x111}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x112}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x113}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x114}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x115}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x116}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x117}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x118}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x119}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x11f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x120}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8125, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x121}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x122}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x123}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x124}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd19f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x125}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x126}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x127}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x128}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x129}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x63f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4368, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x12f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x130}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x131}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x132}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x133}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x134}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x135}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x136}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x137}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8141, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x138}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x139}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x813e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1f4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x13f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x140}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x141}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x142}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x143}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x144}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x145}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6074, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x146}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x147}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x148}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x149}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4056, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x61fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x14f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xfff9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x150}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x151}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x152}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x153}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x154}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4070, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x155}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x156}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x820e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x157}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x158}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x159}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xae80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x820e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd05a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x15f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x160}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x161}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x162}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x163}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x164}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x165}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x166}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x167}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x168}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x169}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x16f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x170}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x171}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x172}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x173}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x174}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x175}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ccf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x176}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x177}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x178}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c24, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x179}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa340, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x17f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x180}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8110, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x181}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x182}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x183}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x184}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa8c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x185}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x186}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x187}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x188}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x189}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cfc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0224, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0ca0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd35, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x18f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd162, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x190}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x191}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x192}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x193}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x194}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x195}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8840, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x196}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x197}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd045, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x198}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x199}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fba, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x19f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x88c0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8350, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x84a0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffb8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xbb80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1a9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1aa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd36, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fb4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9920, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6065, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f94, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xffe8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xb820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd71f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x7fa5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1be}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9820, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x800a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1433, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13ec, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8108, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x143c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa2fc, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa304, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8880, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0440, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd37, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b80, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xac3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa810, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1da}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa480, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa604, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1de}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81e8, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x81e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b40, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8d38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8204, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8201, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x200}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x201}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x202}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x203}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd189, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x204}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x205}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x206}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x207}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x208}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x209}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x20f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x210}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x211}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x212}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x213}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x214}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x215}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x216}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x217}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x218}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x219}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x21f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x220}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x221}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x222}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x223}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce08, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x224}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x225}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x226}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa180, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x227}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x228}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x229}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x823e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8236, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x22f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x230}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x231}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x232}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x233}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x234}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x235}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x236}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x237}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1b7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x238}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x239}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x23f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x240}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x241}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x242}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x243}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x244}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x245}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd055, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x246}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x247}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x248}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x249}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa302, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x24f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x250}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x251}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x252}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x253}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x254}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x255}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x256}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x257}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x258}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c12, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x259}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8270, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8268, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x25f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x260}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x261}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x262}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x263}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf013, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x264}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x265}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x266}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x267}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x268}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x269}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd040, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x26f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x270}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x271}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x272}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x273}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x274}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x275}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x276}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x277}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x278}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x279}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x27f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x085e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x280}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x281}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x282}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcb0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x283}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0cc7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x284}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x285}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x286}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x287}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4127, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x288}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x289}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d28, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x28f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x290}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x291}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x292}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x293}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x294}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c38, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x295}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0d18, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x296}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x297}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x298}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f45, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x299}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x646d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82b4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82aa, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x29f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf017, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2a9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2aa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ab}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ac}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ad}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd100, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ae}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2af}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf010, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2b9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ba}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2be}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2bf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f29, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2c9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x60f1, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ca}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6113, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6135, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x6157, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ce}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2cf}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf008, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf004, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf002, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xce06, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2d9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2da}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13e4, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2db}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2dd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8bc0, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2de}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c3f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2df}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c09, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa120, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa310, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xa420, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x65ad, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2e9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ea}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82fe, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2eb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ec}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x82f6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ed}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ee}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ef}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f1}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf024, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f2}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f3}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f4}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf021, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f5}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f6}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f7}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1c6, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2f9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf01c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2fe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x2ff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd199, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x300}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x301}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf014, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x302}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x303}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x304}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x305}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x306}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x307}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8311, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x308}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x309}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x830e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd1e5, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd191, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x30f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x310}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x311}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x312}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x313}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x314}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x315}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x316}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x13cf, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x317}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x318}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x141a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x319}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f7a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd706, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x5f2c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x40e7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x31f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x320}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x321}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x322}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b05, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x323}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x324}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x325}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c03, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x326}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1502, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x327}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0c0f, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x328}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x329}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x9503, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xcd3c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x644d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x43c7, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd700, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x32f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x37c9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x330}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x8344, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x331}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x33a9, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x332}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x833c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x333}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x334}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x335}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x336}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x337}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf019, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x338}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x339}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf016, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x33f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf011, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x340}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x341}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x342}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf00e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x343}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd702, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x344}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x4098, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x345}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x346}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x347}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf009, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x348}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x349}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd049, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34a}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf006, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34b}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34c}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd04b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34d}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf003, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34e}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd17a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x34f}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd048, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x350}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1800, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x351}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x093a, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x352}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0883, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0f32, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA10A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0676, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA108, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA106, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x021d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA104, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x12fe, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA102, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x01ca, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA100, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x047f, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00ff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA016, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0020, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA012, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x1ff8, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA014, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd13e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff8}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15c, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ff9}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd16b, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffa}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xd15d, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffb}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffc}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffd}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b0e, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1ffe}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_SWC , 0, 0xa014, 0xa012, 0x1fff}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA164, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0972, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0968, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a0b, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0a01, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0b8a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0bf9, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x125c, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x3fff, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0xA162, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x007F, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_algxg_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x75 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80CD, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8065, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8175, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xa2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8176, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xc5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8077, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x40 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8078, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xcc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8969, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x0f , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8957, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x2C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8959, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x895A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x3E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x895F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8165, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x22 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x68 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8013, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x39 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fd5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x1e , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82D9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x82DA, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x00 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x816E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8159, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x815A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x99 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8139, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8125, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x67 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8126, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x89 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x827D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x42 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_alg_giga_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80b8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x4d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80b9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xcc , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ba, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x37 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0c , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80be, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xBB , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80bf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xca , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80c0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x45 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80c2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x3b , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x16 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 10, 8 , 0x4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ce, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80cf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x53 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0a , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xB9 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xd0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x4a , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80d6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x35 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x0d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xa4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x59 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 13, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xab , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80a9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 8 , 0x0b , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80aa, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xef , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ab, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xae , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ac, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0xdf , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x80ae, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x28 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8367, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x5d , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_normal_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd92, 15, 0 , 0x002e, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd94, 15, 0 , 0x8003, RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0xf , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd94, 15, 0 , 0x800b, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0xf , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xbd96, 3 , 0 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x817D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8426, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x46 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8428, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x46 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84de, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e6, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84e8, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ea, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ec, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84ee, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0000, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f0, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x00fc, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f2, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0xf61a, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x84f4, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 8 , 0x58 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xae32, 5 , 5 , 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x8018, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 12, 12, 0x1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fdf, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fe9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8feb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fed, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fef, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff1, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff3, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff5, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff7, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x0496, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ff9, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x03a5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x02e5, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8ffd, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 0 , 0x020d, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb516, 6 , 0 , 0x0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fda, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x04 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8fdb, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x05 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80ca, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x80cc, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8062, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x77 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87c, 15, 0 , 0x8064, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb87e, 15, 8 , 0x88 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa436, 15, 0 , 0x801E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xa438, 15, 0 , 0x0012, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_dataram_conf[] = { + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb820, 7 , 7 , 0x0 , RTK_PATCH_CMP_WS , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb892, 15, 8 , 0x0 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC037, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x33 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC038, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x2A , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC039, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x25 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x20 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x1C , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC03D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC075, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xA1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC076, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xB1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC077, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x2E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC078, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x55 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC079, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x19 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC07A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xDC , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC07B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xA0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC10F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC110, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xD5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC149, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC14E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x08 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC166, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC167, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xEE , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC168, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x07 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC169, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x09 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0D , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x13 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0E , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x11 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC16F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x14 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC170, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x17 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC171, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x15 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC172, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0x10 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC173, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0x0B , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC128, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC129, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12A, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF8 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12B, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12C, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF6 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12D, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12E, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC12F, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC130, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF5 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC131, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF2 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC132, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF0 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC133, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF1 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC134, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 15, 8 , 0xF4 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb88e, 15, 0 , 0xC135, RTK_PATCH_CMP_W , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb890, 7 , 0 , 0xF7 , RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PHYOCP , 0xf , 0 , 0xb896, 0 , 0 , 0x1 , RTK_PATCH_CMP_W , 0, 0, 0, 0}, +}; + +rtk_hwpatch_t rtl8264b_rtct_conf[] = { +}; + diff --git a/drivers/net/phy/rtl8261n/error.h b/drivers/net/phy/rtl8261n/error.h new file mode 100644 index 000000000000..d99a996f8c05 --- /dev/null +++ b/drivers/net/phy/rtl8261n/error.h @@ -0,0 +1,165 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __COMMON_ERROR_H__ +#define __COMMON_ERROR_H__ + +/* + * Include Files + */ +#if defined(RTK_PHYDRV_IN_LINUX) + #include "type.h" +#else + #include +#endif +/* + * Data Type Declaration + */ +typedef enum rt_error_common_e +{ + RT_ERR_FAILED = -1, /* General Error */ + + /* 0x0000xxxx for common error code */ + RT_ERR_OK = 0, /* 0x00000000, OK */ + RT_ERR_INPUT = 0xF001, /* 0x0000F001, invalid input parameter */ + RT_ERR_UNIT_ID, /* 0x0000F002, invalid unit id */ + RT_ERR_PORT_ID, /* 0x0000F003, invalid port id */ + RT_ERR_PORT_MASK, /* 0x0000F004, invalid port mask */ + RT_ERR_PORT_LINKDOWN, /* 0x0000F005, link down port status */ + RT_ERR_ENTRY_INDEX, /* 0x0000F006, invalid entry index */ + RT_ERR_NULL_POINTER, /* 0x0000F007, input parameter is null pointer */ + RT_ERR_QUEUE_ID, /* 0x0000F008, invalid queue id */ + RT_ERR_QUEUE_NUM, /* 0x0000F009, invalid queue number */ + RT_ERR_BUSYWAIT_TIMEOUT, /* 0x0000F00a, busy watting time out */ + RT_ERR_MAC, /* 0x0000F00b, invalid mac address */ + RT_ERR_OUT_OF_RANGE, /* 0x0000F00c, input parameter out of range */ + RT_ERR_CHIP_NOT_SUPPORTED, /* 0x0000F00d, functions not supported by this chip model */ + RT_ERR_SMI, /* 0x0000F00e, SMI error */ + RT_ERR_NOT_INIT, /* 0x0000F00f, The module is not initial */ + RT_ERR_CHIP_NOT_FOUND, /* 0x0000F010, The chip can not found */ + RT_ERR_NOT_ALLOWED, /* 0x0000F011, actions not allowed by the function */ + RT_ERR_DRIVER_NOT_FOUND, /* 0x0000F012, The driver can not found */ + RT_ERR_SEM_LOCK_FAILED, /* 0x0000F013, Failed to lock semaphore */ + RT_ERR_SEM_UNLOCK_FAILED, /* 0x0000F014, Failed to unlock semaphore */ + RT_ERR_THREAD_EXIST, /* 0x0000F015, Thread exist */ + RT_ERR_THREAD_CREATE_FAILED, /* 0x0000F016, Thread create fail */ + RT_ERR_FWD_ACTION, /* 0x0000F017, Invalid forwarding Action */ + RT_ERR_IPV4_ADDRESS, /* 0x0000F018, Invalid IPv4 address */ + RT_ERR_IPV6_ADDRESS, /* 0x0000F019, Invalid IPv6 address */ + RT_ERR_PRIORITY, /* 0x0000F01a, Invalid Priority value */ + RT_ERR_FID, /* 0x0000F01b, invalid fid */ + RT_ERR_ENTRY_NOTFOUND, /* 0x0000F01c, specified entry not found */ + RT_ERR_DROP_PRECEDENCE, /* 0x0000F01d, invalid drop precedence */ + RT_ERR_NOT_FINISH, /* 0x0000F01e, Action not finish, still need to wait */ + RT_ERR_TIMEOUT, /* 0x0000F01f, Time out */ + RT_ERR_REG_ARRAY_INDEX_1, /* 0x0000F020, invalid index 1 of register array */ + RT_ERR_REG_ARRAY_INDEX_2, /* 0x0000F021, invalid index 2 of register array */ + RT_ERR_ETHER_TYPE, /* 0x0000F022, invalid ether type */ + RT_ERR_MBUF_PKT_NOT_AVAILABLE, /* 0x0000F023, mbuf->packet is not available */ + RT_ERR_QOS_INVLD_RSN, /* 0x0000F024, invalid pkt to CPU reason */ + RT_ERR_CB_FUNCTION_EXIST, /* 0x0000F025, Callback function exist */ + RT_ERR_CB_FUNCTION_FULL, /* 0x0000F026, Callback function number is full */ + RT_ERR_CB_FUNCTION_NOT_FOUND, /* 0x0000F027, Callback function can not found */ + RT_ERR_TBL_FULL, /* 0x0000F028, The table is full */ + RT_ERR_TRUNK_ID, /* 0x0000F029, invalid trunk id */ + RT_ERR_TYPE, /* 0x0000F02a, invalid type */ + RT_ERR_ENTRY_EXIST, /* 0x0000F02b, entry exists */ + RT_ERR_CHIP_UNDEFINED_VALUE, /* 0x0000F02c, chip returned an undefined value */ + RT_ERR_EXCEEDS_CAPACITY, /* 0x0000F02d, exceeds the capacity of hardware */ + RT_ERR_ENTRY_REFERRED, /* 0x0000F02e, entry is still being referred */ + RT_ERR_OPER_DENIED, /* 0x0000F02f, operation denied */ + RT_ERR_PORT_NOT_SUPPORTED, /* 0x0000F030, functions not supported by this port */ + RT_ERR_SOCKET, /* 0x0000F031, socket error */ + RT_ERR_MEM_ALLOC, /* 0x0000F032, insufficient memory resource */ + RT_ERR_ABORT, /* 0x0000F033, operation aborted */ + RT_ERR_DEV_ID, /* 0x0000F034, invalid device id */ + RT_ERR_DRIVER_NOT_SUPPORTED, /* 0x0000F035, functions not supported by this driver */ + RT_ERR_NOT_SUPPORTED, /* 0x0000F036, functions not supported */ + RT_ERR_SER, /* 0x0000F037, ECC or parity error */ + RT_ERR_MEM_NOT_ALIGN, /* 0x0000F038, memory address is not aligned */ + RT_ERR_SEM_FAKELOCK_OK, /* 0x0000F039, attach thread lock a semaphore which was already locked */ + RT_ERR_CHECK_FAILED, /* 0x0000F03a, check result is failed */ + + RT_ERR_COMMON_END = 0xFFFF /* The symbol is the latest symbol of common error */ +} rt_error_common_t; + +/* + * Macro Definition + */ +#define RT_PARAM_CHK(expr, errCode)\ +do {\ + if ((int32)(expr)) {\ + return errCode; \ + }\ +} while (0) + +#define RT_PARAM_CHK_EHDL(expr, errCode, err_hdl)\ +do {\ + if ((int32)(expr)) {\ + {err_hdl}\ + return errCode; \ + }\ +} while (0) + +#define RT_INIT_CHK(state)\ +do {\ + if (INIT_COMPLETED != (state)) {\ + return RT_ERR_NOT_INIT;\ + }\ +} while (0) + +#define RT_INIT_REENTRY_CHK(state)\ +do {\ + if (INIT_COMPLETED == (state)) {\ + osal_printf(" %s had already been initialized!\n", __FUNCTION__);\ + return RT_ERR_OK;\ + }\ +} while (0) + +#define RT_INIT_REENTRY_CHK_NO_WARNING(state)\ + do {\ + if (INIT_COMPLETED == (state)) {\ + return RT_ERR_OK;\ + }\ + } while (0) + +#define RT_ERR_CHK(op, ret)\ +do {\ + if ((ret = (op)) != RT_ERR_OK)\ + return ret;\ +} while(0) + +#define RT_ERR_HDL(op, errHandle, ret)\ +do {\ + if ((ret = (op)) != RT_ERR_OK)\ + goto errHandle;\ +} while(0) + +#define RT_ERR_CHK_EHDL(op, ret, err_hdl)\ +do {\ + if ((ret = (op)) != RT_ERR_OK)\ + {\ + {err_hdl}\ + return ret;\ + }\ +} while(0) + +#define RT_NULL_HDL(pointer, err_label)\ +do {\ + if (NULL == (pointer)) {\ + goto err_label;\ + }\ +} while (0) + +#define RT_ERR_VOID_CHK(op, ret)\ +do {\ + if ((ret = (op)) != RT_ERR_OK) {\ + osal_printf("Fail in %s %d, ret %x!\n", __FUNCTION__, __LINE__, ret);\ + return ;}\ +} while(0) + +#endif /* __COMMON_ERROR_H__ */ + diff --git a/drivers/net/phy/rtl8261n/phy_patch.c b/drivers/net/phy/rtl8261n/phy_patch.c new file mode 100644 index 000000000000..7563f6705333 --- /dev/null +++ b/drivers/net/phy/rtl8261n/phy_patch.c @@ -0,0 +1,188 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +/* + * Include Files + */ +#if defined(RTK_PHYDRV_IN_LINUX) + #include "rtk_osal.h" +#else + #include + #include + #include + #include + #include +#endif + +/* + * Function Declaration + */ +uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op) +{ + if (patch_mode != PHY_PATCH_MODE_CMP) + { + return patch_op; + } + else + { + switch (compare_op) + { + case RTK_PATCH_CMP_WS: + return RTK_PATCH_OP_SKIP; + case RTK_PATCH_CMP_W: + case RTK_PATCH_CMP_WC: + case RTK_PATCH_CMP_SWC: + default: + return RTK_PATCH_OP_TO_CMP(patch_op, compare_op); + } + } +} + +int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data, uint8 patch_mode) +{ + rtk_hwpatch_t op; + + op.patch_op = patch_op; + op.portmask = portmask; + op.pagemmd = pagemmd; + op.addr = addr; + op.msb = msb; + op.lsb = lsb; + op.data = data; + op.compare_op = RTK_PATCH_CMP_W; + + return pPhy_patchDb->fPatch_op(unit, port, portOffset, &op, patch_mode); +} + +static int32 _phy_patch_process(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch, int32 size, uint8 patch_mode) +{ + int32 i = 0; + int32 ret = 0; + int32 chk_ret = RT_ERR_OK; + int32 n; + rtk_hwpatch_t *patch = pPatch; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + if (size <= 0) + { + return RT_ERR_OK; + } + n = size / sizeof(rtk_hwpatch_t); + + for (i = 0; i < n; i++) + { + ret = pPatchDb->fPatch_op(unit, port, portOffset, &patch[i], patch_mode); + if ((ret != RT_ERR_ABORT) && (ret != RT_ERR_OK)) + { + if ((ret == RT_ERR_CHECK_FAILED) && (patch_mode == PHY_PATCH_MODE_CMP)) + { + osal_printf("PATCH CHECK: Failed entry:%u|%u|0x%X|0x%X|%u|%u|0x%X\n", + i + 1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].msb, patch[i].lsb, patch[i].data); + chk_ret = RT_ERR_CHECK_FAILED; + continue; + } + else + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u %s failed! %u[%u][0x%X][0x%X][0x%X] ret=0x%X\n", unit, port, __FUNCTION__, + i+1, patch[i].patch_op, patch[i].pagemmd, patch[i].addr, patch[i].data, ret); + return ret; + } + } + + } + return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK; +} + +rtk_hwpatch_t rtl826XB_patch_rtk_conf[] = { + {RTK_PATCH_OP_PSDS0 , 0xff , 0x07 , 0x10 , 15, 0, 0x80aa, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, + {RTK_PATCH_OP_PSDS0 , 0xff , 0x06 , 0x12 , 15, 0, 0x5078, RTK_PATCH_CMP_WC , 0, 0, 0, 0}, +}; + +/* Function Name: + * phy_patch + * Description: + * apply initial patch data to PHY + * Input: + * unit - unit id + * port - port id + * portOffset - the index offset of port based the base port in the PHY chip + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_CHECK_FAILED + * RT_ERR_NOT_SUPPORTED + * Note: + * None + */ +int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + int32 chk_ret = RT_ERR_OK; + uint32 i = 0; + uint8 patch_type = 0; + rt_phy_patch_db_t *pPatchDb = NULL; + rtk_hwpatch_seq_t *table = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + if ((pPatchDb == NULL) || (pPatchDb->fPatch_op == NULL) || (pPatchDb->fPatch_flow == NULL)) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u phy_patch, db is NULL\n", unit, port); + return RT_ERR_DRIVER_NOT_SUPPORTED; + } + + if (patch_mode == PHY_PATCH_MODE_CMP) + { + table = pPatchDb->cmp_table; + } + else + { + table = pPatchDb->seq_table; + } + RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: U%u P%u portOffset:%u patch_mode:%u\n", unit, port, portOffset, patch_mode); + + for (i = 0; i < RTK_PATCH_SEQ_MAX; i++) + { + patch_type = table[i].patch_type; + RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "phy_patch: table[%u] patch_type:%u\n", i, patch_type); + + if (RTK_PATCH_TYPE_IS_DATA(patch_type)) + { + ret = _phy_patch_process(unit, port, portOffset, table[i].patch.data.conf, table[i].patch.data.size, patch_mode); + + if (ret == RT_ERR_CHECK_FAILED) + chk_ret = ret; + else if (ret != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret); + return ret; + } + } + else if (RTK_PATCH_TYPE_IS_FLOW(patch_type)) + { + RT_ERR_CHK_EHDL(pPatchDb->fPatch_flow(unit, port, portOffset, table[i].patch.flow_id, patch_mode), + ret, RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret);); + } + else + { + break; + } + } + ret = _phy_patch_process(unit, port, portOffset, rtl826XB_patch_rtk_conf, sizeof(rtl826XB_patch_rtk_conf), patch_mode); + if (ret == RT_ERR_CHECK_FAILED) + chk_ret = ret; + else if (ret != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_mode:%u id:%u patch-%u failed. ret:0x%X\n", unit, port, patch_mode, i, patch_type, ret); + return ret; + } + + return (chk_ret == RT_ERR_CHECK_FAILED) ? chk_ret : RT_ERR_OK; +} diff --git a/drivers/net/phy/rtl8261n/phy_patch.h b/drivers/net/phy/rtl8261n/phy_patch.h new file mode 100644 index 000000000000..c2b7b1279c7e --- /dev/null +++ b/drivers/net/phy/rtl8261n/phy_patch.h @@ -0,0 +1,174 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __HAL_PHY_PATCH_H__ +#define __HAL_PHY_PATCH_H__ + +/* + * Include Files + */ +#if defined(RTK_PHYDRV_IN_LINUX) + #include "rtk_phylib_def.h" +#else + #include + #include +#endif + +/* + * Symbol Definition + */ +#define PHYPATCH_PHYCTRL_IN_HALCTRL 0 /* 3.6.x: 1 ,4.0.x: 1, 4.1.x+: 0 */ +#define PHYPATCH_FMAILY_IN_HWP 0 /* 3.6.x: 1 ,4.0.x: 0, 4.1.x+: 0 */ +#define PHY_PATCH_MODE_BCAST_DEFAULT PHY_PATCH_MODE_BCAST /* 3.6.x: PHY_PATCH_MODE_BCAST_BUS ,4.0.x+: PHY_PATCH_MODE_BCAST */ + +#define PHY_PATCH_MODE_NORMAL 0 +#define PHY_PATCH_MODE_CMP 1 +#define PHY_PATCH_MODE_BCAST 2 +#define PHY_PATCH_MODE_BCAST_BUS 3 + +#define RTK_PATCH_CMP_W 0 /* write */ +#define RTK_PATCH_CMP_WC 1 /* compare */ +#define RTK_PATCH_CMP_SWC 2 /* sram compare */ +#define RTK_PATCH_CMP_WS 3 /* skip */ + +#define RTK_PATCH_OP_SECTION_SIZE 50 +#define RTK_PATCH_OP_TO_CMP(_op, _cmp) (_op + (RTK_PATCH_OP_SECTION_SIZE * _cmp)) +/* 0~49 normal op */ +#define RTK_PATCH_OP_PHY 0 +#define RTK_PATCH_OP_PHYOCP 1 +#define RTK_PATCH_OP_TOP 2 +#define RTK_PATCH_OP_TOPOCP 3 +#define RTK_PATCH_OP_PSDS0 4 +#define RTK_PATCH_OP_PSDS1 5 +#define RTK_PATCH_OP_MSDS 6 +#define RTK_PATCH_OP_MAC 7 + +/* 50~99 normal op for compare */ +#define RTK_PATCH_OP_CMP_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_WC) +#define RTK_PATCH_OP_CMP_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_WC) + +/* 100~149 normal op for sram compare */ +#define RTK_PATCH_OP_CMP_SRAM_PHY RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHY , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_PHYOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PHYOCP , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_TOP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOP , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_TOPOCP RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_TOPOCP , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_PSDS0 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS0 , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_PSDS1 RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_PSDS1 , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_MSDS RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MSDS , RTK_PATCH_CMP_SWC) +#define RTK_PATCH_OP_CMP_SRAM_MAC RTK_PATCH_OP_TO_CMP(RTK_PATCH_OP_MAC , RTK_PATCH_CMP_SWC) + +/* 200~255 control op */ +#define RTK_PATCH_OP_DELAY_MS 200 +#define RTK_PATCH_OP_SKIP 255 + + +/* + patch type PHY_PATCH_TYPE_NONE => empty + patch type: PHY_PATCH_TYPE_TOP ~ (PHY_PATCH_TYPE_END-1) => data array + patch type: PHY_PATCH_TYPE_END ~ (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOW_MAX) => flow +*/ +#define RTK_PATCH_TYPE_IS_DATA(_patch_type) (_patch_type > PHY_PATCH_TYPE_NONE && _patch_type < PHY_PATCH_TYPE_END) +#define RTK_PATCH_TYPE_IS_FLOW(_patch_type) (_patch_type >= PHY_PATCH_TYPE_END && _patch_type <= (PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX)) + + +/* + * Macro Definition + */ +#if PHYPATCH_PHYCTRL_IN_HALCTRL + #define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \ + do {\ + hal_control_t *pHalCtrl = NULL;\ + if ((pHalCtrl = hal_ctrlInfo_get(_unit)) == NULL)\ + return RT_ERR_FAILED;\ + _pPatchDb = (pHalCtrl->pPhy_ctrl[_port]->pPhy_patchDb);\ + } while(0) +#else + #if defined(RTK_PHYDRV_IN_LINUX) + #else + #include + #include + #endif + #define PHYPATCH_DB_GET(_unit, _port, _pPatchDb) \ + do {\ + rt_phyctrl_t *pPhyCtrl = NULL;\ + if ((pPhyCtrl = phy_phyctrl_get(_unit, _port)) == NULL)\ + return RT_ERR_FAILED;\ + _pPatchDb = (pPhyCtrl->pPhy_patchDb);\ + } while(0) +#endif + +#if PHYPATCH_FMAILY_IN_HWP + #define PHYPATCH_IS_RTKSDS(_unit) (HWP_9300_FAMILY_ID(_unit) || HWP_9310_FAMILY_ID(_unit)) +#else + #define PHYPATCH_IS_RTKSDS(_unit) (RTK_9300_FAMILY_ID(_unit) || RTK_9310_FAMILY_ID(_unit) || RTK_9311B_FAMILY_ID(_unit) || RTK_9330_FAMILY_ID(_unit)) +#endif + +#define PHYPATCH_TABLE_ASSIGN(_pPatchDb, _table, _idx, _patch_type, _para) \ + do {\ + if (RTK_PATCH_TYPE_IS_DATA(_patch_type)) {\ + _pPatchDb->_table[_idx].patch_type = _patch_type;\ + _pPatchDb->_table[_idx].patch.data.conf = _para;\ + _pPatchDb->_table[_idx].patch.data.size = sizeof(_para);\ + }\ + else if (RTK_PATCH_TYPE_IS_FLOW(_patch_type)) {\ + _pPatchDb->_table[_idx].patch_type = _patch_type;\ + _pPatchDb->_table[_idx].patch.flow_id = _patch_type;\ + }\ + else {\ + _pPatchDb->_table[_idx].patch_type = PHY_PATCH_TYPE_NONE;\ + }\ + } while(0) +#define PHYPATCH_SEQ_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, seq_table, _idx, _patch_type, _para) +#define PHYPATCH_CMP_TABLE_ASSIGN(_pPatchDb, _idx, _patch_type, _para) PHYPATCH_TABLE_ASSIGN(_pPatchDb, cmp_table, _idx, _patch_type, _para) + +#define PHYPATCH_COMPARE(_mmdpage, _reg, _msb, _lsb, _exp, _real, _mask) \ + do {\ + uint32 _rData = REG32_FIELD_GET(_real, _lsb, _mask);\ + if (_exp != _rData) {\ + osal_printf("PATCH CHECK: %u(0x%X).%u(0x%X)[%u:%u] = 0x%X (!= 0x%X)\n", _mmdpage, _mmdpage, _reg, _reg, _msb, _lsb, _rData, _exp);\ + return RT_ERR_CHECK_FAILED;\ + }\ + } while (0) + +/* + * Function Declaration + */ + +extern uint8 phy_patch_op_translate(uint8 patch_mode, uint8 patch_op, uint8 compare_op); +extern int32 phy_patch_op(rt_phy_patch_db_t *pPhy_patchDb, uint32 unit, rtk_port_t port, uint8 portOffset, + uint8 patch_op, uint16 portmask, uint16 pagemmd, uint16 addr, uint8 msb, uint8 lsb, uint16 data, + uint8 patch_mode); + + +/* Function Name: + * phy_patch + * Description: + * apply initial patch data to PHY + * Input: + * unit - unit id + * port - port id + * portOffset - the index offset of port based the base port in the PHY chip + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_CHECK_FAILED + * RT_ERR_NOT_SUPPORTED + * Note: + * None + */ +extern int32 phy_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode); + + + +#endif /* __HAL_PHY_PATCH_H__ */ diff --git a/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c new file mode 100644 index 000000000000..0bfd93033f83 --- /dev/null +++ b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.c @@ -0,0 +1,1031 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +/* + * Include Files + */ +#if defined(RTK_PHYDRV_IN_LINUX) + #include "phy_rtl826xb_patch.h" + #include "construct/conf_rtl8264b.c" + #include "construct/conf_rtl8261n_c.c" +#else + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #if defined(CONFIG_SDK_RTL826XB) + #include + #include + #include + #endif +#endif +/* + * Symbol Definition + */ +#define PHY_PATCH_WAIT_TIMEOUT 10000000 + +#define PHY_PATCH_LOG LOG_INFO + +/* + * Data Declaration + */ + +/* + * Macro Declaration + */ + +/* + * Function Declaration + */ +static uint16 _phy_rtl826xb_mmd_convert(uint16 page, uint16 addr) +{ + uint16 reg = 0; + if (addr < 16) + { + reg = 0xA400 + (page * 2); + } + else if (addr < 24) + { + reg = (16*page) + ((addr - 16) * 2); + } + else + { + reg = 0xA430 + ((addr - 24) * 2); + } + return reg; +} + +static int32 +_phy_rtl826xb_patch_wait(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data, uint32 mask, uint8 patch_mode) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 cnt = 0; + WAIT_COMPLETE_VAR() + + rtk_port_t p = 0; + uint8 smiBus = HWP_PORT_SMI(unit, port); + uint32 phyChip = HWP_PHY_MODEL_BY_PORT(unit, port); + uint8 bcast_phyad = HWP_PHY_ADDR(unit, port);; + + + if (patch_mode == PHY_PATCH_MODE_BCAST_BUS) + { + if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait disable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + { + return ret; + } + ++cnt; + + if ((rData & mask) == data) + break; + + //osal_time_udelay(10); + } + + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + } + } + + osal_time_mdelay(1); + //for port in same SMI bus, set mdio broadcast ENABLE + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) + { + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); + return ret; + } + + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + } + } + } + else if (patch_mode == PHY_PATCH_MODE_BCAST) + { + if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait disable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + { + return ret; + } + ++cnt; + + if ((rData & mask) == data) + break; + //osal_time_udelay(10); + } + + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + } + } + + osal_time_mdelay(1); + //for port in same PHY, set mdio broadcast ENABLE + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) + { + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); + return ret; + } + + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + } + } + } + else + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, port, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + return ret; + + ++cnt; + if ((rData & mask) == data) + break; + + osal_time_mdelay(1); + } + + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, port, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + } + + return RT_ERR_OK; +} + +static int32 +_phy_rtl826xb_patch_wait_not_equal(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data, uint32 mask, uint8 patch_mode) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 cnt = 0; + WAIT_COMPLETE_VAR() + + rtk_port_t p = 0; + uint8 smiBus = HWP_PORT_SMI(unit, port); + uint32 phyChip = HWP_PHY_MODEL_BY_PORT(unit, port); + uint8 bcast_phyad = HWP_PHY_ADDR(unit, port); + + if (patch_mode == PHY_PATCH_MODE_BCAST_BUS) + { + if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait disable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + { + return ret; + } + ++cnt; + + if ((rData & mask) != data) + break; + + //osal_time_udelay(10); + } + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + } + } + + osal_time_mdelay(1); + //for port in same SMI bus, set mdio broadcast ENABLE + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if ((HWP_PORT_SMI(unit, p) == smiBus) && (HWP_PHY_MODEL_BY_PORT(unit, p) == phyChip)) + { + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); + return ret; + } + + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + } + } + } + else if (patch_mode == PHY_PATCH_MODE_BCAST) + { + if ((ret = phy_826xb_ctrl_set(unit, port, RTK_PHY_CTRL_MIIM_BCAST, 0)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826x patch wait disable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, p, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + { + return ret; + } + ++cnt; + + if (((rData & mask) != data)) + break; + + //osal_time_udelay(10); + } + + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, p, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + } + } + + osal_time_mdelay(1); + //for port in same PHY, set mdio broadcast ENABLE + HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) + { + if (HWP_PHY_BASE_MACID(unit, p) == HWP_PHY_BASE_MACID(unit, port)) + { + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, (uint32)bcast_phyad)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait set broadcast PHYAD failed! 0x%X\n", unit, p, ret); + return ret; + } + + if ((ret = phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST, 1)) != RT_ERR_OK) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826XB patch wait enable broadcast failed! 0x%X\n", unit, p, ret); + return ret; + } + } + } + } + else + { + WAIT_COMPLETE(PHY_PATCH_WAIT_TIMEOUT) + { + if ((ret = phy_common_general_reg_mmd_get(unit, port, mmdAddr, mmdReg, &rData)) != RT_ERR_OK) + return ret; + + ++cnt; + if ((rData & mask) != data) + break; + + osal_time_mdelay(1); + } + if (WAIT_COMPLETE_IS_TIMEOUT()) + { + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u 826xb patch wait[%u,0x%X,0x%X,0x%X]:0x%X cnt:%u\n", unit, port, mmdAddr, mmdReg, data, mask, rData, cnt); + return RT_ERR_TIMEOUT; + } + + } + + return RT_ERR_OK; +} + +static int32 +_phy_rtl826xb_patch_top_get(uint32 unit, rtk_port_t port, uint32 topPage, uint32 topReg, uint32 *pData) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 topAddr = (topPage * 8) + (topReg - 16); + + if ((ret = phy_common_general_reg_mmd_get(unit, port, PHY_MMD_VEND1, topAddr, &rData)) != RT_ERR_OK) + return ret; + *pData = rData; + return RT_ERR_OK; +} + +static int32 +_phy_rtl826xb_patch_top_set(uint32 unit, rtk_port_t port, uint32 topPage, uint32 topReg, uint32 wData) +{ + int32 ret = 0; + uint32 topAddr = (topPage * 8) + (topReg - 16); + if ((ret = phy_common_general_reg_mmd_set(unit, port, PHY_MMD_VEND1, topAddr, wData)) != RT_ERR_OK) + return ret; + return RT_ERR_OK; +} + +static int32 +_phy_rtl826xb_patch_sds_get(uint32 unit, rtk_port_t port, uint32 sdsPage, uint32 sdsReg, uint32 *pData) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 sdsAddr = 0x8000 + (sdsReg << 6) + sdsPage; + + if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 19, sdsAddr)) != RT_ERR_OK) + return ret; + if ((ret = _phy_rtl826xb_patch_top_get(unit, port, 40, 18, &rData)) != RT_ERR_OK) + return ret; + *pData = rData; + return _phy_rtl826xb_patch_wait(unit, port, PHY_MMD_VEND1, 0x143, 0, BIT_15, PHY_PATCH_MODE_NORMAL); +} + +static int32 +_phy_rtl826xb_patch_sds_set(uint32 unit, rtk_port_t port, uint32 sdsPage, uint32 sdsReg, uint32 wData, uint8 patch_mode) +{ + int32 ret = 0; + uint32 sdsAddr = 0x8800 + (sdsReg << 6) + sdsPage; + + if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 17, wData)) != RT_ERR_OK) + return ret; + if ((ret = _phy_rtl826xb_patch_top_set(unit, port, 40, 19, sdsAddr)) != RT_ERR_OK) + return ret; + return _phy_rtl826xb_patch_wait(unit, port, PHY_MMD_VEND1, 0x143, 0, BIT_15, patch_mode); +} + +static int32 _phy_rtl826xb_flow_r1(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); + + //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready = 1 + RT_ERR_CHK(_phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); + + //PHYReg w $PHYID 0xa43 27 $0x8023 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 $0x3802 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x3802, patch_mode), ret); + //PHYReg w $PHYID 0xa43 27 0xB82E + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0xB82E, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x1, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_r12(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xb82 16 4 4 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x1, patch_mode), ret); + + //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready = 1 + RT_ERR_CHK(_phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); + + //PHYReg w $PHYID 0xa43 27 $0x8023 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 $0x3800 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x3800, patch_mode), ret); + //PHYReg w $PHYID 0xa43 27 0xB82E + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0xB82E, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x1, patch_mode), ret); + + return RT_ERR_OK; +} + + +static int32 _phy_rtl826xb_flow_r2(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg w $PHYID 0xa43 27 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x0000, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x0000, patch_mode), ret); + //PHYReg_bit w $PHYID 0xB82 23 0 0 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xB82, 23, 0, 0, 0x0, patch_mode), ret); + //PHYReg w $PHYID 0xa43 27 $0x8023 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 27, 15, 0, 0x8023, patch_mode), ret); + //PHYReg w $PHYID 0xa43 28 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa43, 28, 15, 0, 0x0000, patch_mode), ret); + + //PHYReg_bit w $PHYID 0xb82 16 4 4 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xb82, 16, 4, 4, 0x0, patch_mode), ret); + //set patch_rdy [PHYReg_bit r $PHYID 0xb80 16 6 6] ; Wait for patch ready != 1 + RT_ERR_CHK( _phy_rtl826xb_patch_wait_not_equal(unit, port, 31, _phy_rtl826xb_mmd_convert(0xb80, 16), BIT_6, BIT_6, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_l1(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x1, patch_mode), ret); + + //set pcs_state [PHYReg_bit r $PHYID 0xa60 16 7 0] ; Wait for pcs state = 1 + RT_ERR_CHK( _phy_rtl826xb_patch_wait(unit, port, 31, _phy_rtl826xb_mmd_convert(0xa60, 16), 0x1, 0xFF, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_l2(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa4a 16 10 10 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa4a, 16, 10, 10, 0x0, patch_mode), ret); + + //set pcs_state [PHYReg_bit r $PHYID 0xa60 16 7 0] ; Wait for pcs state != 1 + RT_ERR_CHK( _phy_rtl826xb_patch_wait_not_equal(unit, port, 31, _phy_rtl826xb_mmd_convert(0xa60, 16), 0x1, 0xFF, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_pi(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + uint32 rData = 0, cnt = 0; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + _phy_rtl826xb_flow_l1(unit, port, portOffset, patch_mode); + + // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x1; #SS_EN_XG = 1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 8 8 0x0; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 8, 8, 0x0, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x1; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x1; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 5 5 0x1; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 5, 5, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 4 4 0x1; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 4, 4, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x0; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x0, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x0; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x0, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x0; + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x0, patch_mode), ret); + + //PP_PHYReg_bit r $PHYID 0xbc62 12 8 + if ((ret = phy_common_general_reg_mmd_get(unit, port, PHY_MMD_VEND2, 0xbc62, &rData)) != RT_ERR_OK) + return ret; + rData = REG32_FIELD_GET(rData, 8, 0x1F00); + for (cnt = 0; cnt <= rData; cnt++) + { + //PP_PHYReg_bit w $PHYID 0xbc62 12 8 $t + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc62, 12, 8, cnt, patch_mode), ret); + } + + // PP_PHYReg_bit w $PHYID 0xbc02 2 2 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc02, 2, 2, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbc02 3 3 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc02, 3, 3, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 6 6 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 6, 6, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 9 9 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 9, 9, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbf86 7 7 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbf86, 7, 7, 0x1, patch_mode), ret); + // PP_PHYReg_bit w $PHYID 0xbc04 9 2 0xff + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHYOCP, 0xFF, 31, 0xbc04, 9, 2, 0xff, patch_mode), ret); + + _phy_rtl826xb_flow_l2(unit, port, portOffset, patch_mode); + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n01(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0000, patch_mode), ret); + //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n02(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0000, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n11(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0010 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0010, patch_mode), ret); + //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n12(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0010 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0010, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n21(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x1 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x1, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0020 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0020, patch_mode), ret); + //# PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + //RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_n22(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + PHYPATCH_DB_GET(unit, port, pPatchDb); + + //PHYReg_bit w $PHYID 0xa01 21 15 0 0x0 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 21, 15, 0, 0x0, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 19 15 0 0x0020 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 19, 15, 0, 0x0020, patch_mode), ret); + //PHYReg_bit w $PHYID 0xa01 17 15 0 0x0000 + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PHY, 0xFF, 0xa01, 17, 15, 0, 0x0000, patch_mode), ret); + + return RT_ERR_OK; +} + +static int32 _phy_rtl826xb_flow_s(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *pPatchDb = NULL; + + if (PHYPATCH_IS_RTKSDS(unit)) + { + PHYPATCH_DB_GET(unit, port, pPatchDb); + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PSDS0, 0xff, 0x07, 0x10, 15, 0, 0x80aa, patch_mode), ret); + RT_ERR_CHK(phy_patch_op(pPatchDb, unit, port, portOffset, RTK_PATCH_OP_PSDS0, 0xff, 0x06, 0x12, 15, 0, 0x5078, patch_mode), ret); + } + + return RT_ERR_OK; +} + +static int32 phy_rtl826xb_patch_op(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch_data, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + uint32 rData = 0, wData = 0; + uint16 reg = 0; + uint8 patch_op = 0; + uint32 mask = 0; + + if ((pPatch_data->portmask & (1 << portOffset)) == 0) + { + return RT_ERR_ABORT; + } + mask = UINT32_BITS_MASK(pPatch_data->msb, pPatch_data->lsb); + patch_op = phy_patch_op_translate(patch_mode, pPatch_data->patch_op, pPatch_data->compare_op); + + #if 0 + osal_printf("[%s,%d]u%up%u, patch_mode:%u/patch_op:%u/compare_op:%u => op: %u\n", __FUNCTION__, __LINE__, unit, port, + patch_mode, pPatch_data->patch_op, pPatch_data->compare_op, + patch_op); + #endif + + switch (patch_op) + { + case RTK_PATCH_OP_PHY: + reg = _phy_rtl826xb_mmd_convert(pPatch_data->pagemmd, pPatch_data->addr); + if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) + { + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); + } + wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); + RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, reg, wData), ret); + break; + case RTK_PATCH_OP_CMP_PHY: + reg = _phy_rtl826xb_mmd_convert(pPatch_data->pagemmd, pPatch_data->addr); + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + case RTK_PATCH_OP_CMP_SRAM_PHY: + reg = _phy_rtl826xb_mmd_convert(pPatch_data->sram_p, pPatch_data->sram_rw); + RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, reg, pPatch_data->sram_a), ret); + reg = _phy_rtl826xb_mmd_convert(pPatch_data->sram_p, pPatch_data->sram_rr); + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, reg, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + + case RTK_PATCH_OP_PHYOCP: + if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) + { + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->addr, &rData), ret); + } + wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); + RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, pPatch_data->addr, wData), ret); + break; + case RTK_PATCH_OP_CMP_PHYOCP: + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->addr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + case RTK_PATCH_OP_CMP_SRAM_PHYOCP: + RT_ERR_CHK(phy_common_general_reg_mmd_set(unit, port, 31, pPatch_data->sram_rw, pPatch_data->sram_a), ret); + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 31, pPatch_data->sram_rr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + + case RTK_PATCH_OP_TOP: + if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) + { + RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); + } + wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); + RT_ERR_CHK(_phy_rtl826xb_patch_top_set(unit, port, pPatch_data->pagemmd, pPatch_data->addr, wData), ret); + break; + case RTK_PATCH_OP_CMP_TOP: + RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + case RTK_PATCH_OP_CMP_SRAM_TOP: + RT_ERR_CHK(_phy_rtl826xb_patch_top_set(unit, port, pPatch_data->sram_p, pPatch_data->sram_rw, pPatch_data->sram_a), ret); + RT_ERR_CHK(_phy_rtl826xb_patch_top_get(unit, port, pPatch_data->sram_p, pPatch_data->sram_rr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + + case RTK_PATCH_OP_PSDS0: + if ((pPatch_data->msb != 15) || (pPatch_data->lsb != 0)) + { + RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); + } + wData = REG32_FIELD_SET(rData, pPatch_data->data, pPatch_data->lsb, mask); + RT_ERR_CHK(_phy_rtl826xb_patch_sds_set(unit, port, pPatch_data->pagemmd, pPatch_data->addr, wData, patch_mode), ret); + break; + case RTK_PATCH_OP_CMP_PSDS0: + RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->pagemmd, pPatch_data->addr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + case RTK_PATCH_OP_CMP_SRAM_PSDS0: + RT_ERR_CHK(_phy_rtl826xb_patch_sds_set(unit, port, pPatch_data->sram_p, pPatch_data->sram_rw, pPatch_data->sram_a, patch_mode), ret); + RT_ERR_CHK(_phy_rtl826xb_patch_sds_get(unit, port, pPatch_data->sram_p, pPatch_data->sram_rr, &rData), ret); + PHYPATCH_COMPARE(pPatch_data->pagemmd, pPatch_data->addr, pPatch_data->msb, pPatch_data->lsb, pPatch_data->data, rData, mask); + break; + + case RTK_PATCH_OP_SKIP: + return RT_ERR_ABORT; + + default: + RT_LOG(LOG_MAJOR_ERR, (MOD_HAL | MOD_PHY), "U%u P%u patch_op:%u not implemented yet!\n", unit, port, pPatch_data->patch_op); + return RT_ERR_DRIVER_NOT_SUPPORTED; + } + + return ret; +} + +static int32 phy_rtl826xb_patch_flow(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_flow, uint8 patch_mode) +{ + int32 ret = RT_ERR_OK; + + RT_LOG(LOG_INFO, (MOD_HAL | MOD_PHY), "[%s]U%u,P%u,flow%u\n", __FUNCTION__, unit, port, (patch_flow - PHY_PATCH_TYPE_END)); + switch (patch_flow) + { + case RTK_PATCH_TYPE_FLOW(0): + RT_ERR_CHK(_phy_rtl826xb_flow_r1(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(1): + RT_ERR_CHK(_phy_rtl826xb_flow_r2(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(2): + RT_ERR_CHK(_phy_rtl826xb_flow_l1(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(3): + RT_ERR_CHK(_phy_rtl826xb_flow_l2(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(4): + RT_ERR_CHK(_phy_rtl826xb_flow_n01(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(5): + RT_ERR_CHK(_phy_rtl826xb_flow_n02(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(6): + RT_ERR_CHK(_phy_rtl826xb_flow_n11(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(7): + RT_ERR_CHK(_phy_rtl826xb_flow_n12(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(8): + RT_ERR_CHK(_phy_rtl826xb_flow_n21(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(9): + RT_ERR_CHK(_phy_rtl826xb_flow_n22(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(10): + RT_ERR_CHK(_phy_rtl826xb_flow_s(unit, port, portOffset, patch_mode), ret); + break; + + case RTK_PATCH_TYPE_FLOW(11): + RT_ERR_CHK(_phy_rtl826xb_flow_pi(unit, port, portOffset, patch_mode), ret); + break; + case RTK_PATCH_TYPE_FLOW(12): + RT_ERR_CHK(_phy_rtl826xb_flow_r12(unit, port, portOffset, patch_mode), ret); + break; + + default: + return RT_ERR_INPUT; + } + return RT_ERR_OK; +} + +int32 phy_rtl826xb_patch_db_init(uint32 unit, rtk_port_t port, rt_phy_patch_db_t **pPhy_patchDb) +{ + int32 ret = RT_ERR_OK; + rt_phy_patch_db_t *patch_db = NULL; + uint32 rData = 0; + + patch_db = osal_alloc(sizeof(rt_phy_patch_db_t)); + RT_PARAM_CHK(NULL == patch_db, RT_ERR_MEM_ALLOC); + osal_memset(patch_db, 0x0, sizeof(rt_phy_patch_db_t)); + + /* patch callback */ + patch_db->fPatch_op = phy_rtl826xb_patch_op; + patch_db->fPatch_flow = phy_rtl826xb_patch_flow; + + /* patch table */ + RT_ERR_CHK(phy_common_general_reg_mmd_get(unit, port, 30, 0x104, &rData), ret); + if ((rData & 0x7) == 0x0) + { + /* patch */ + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 0, RTK_PATCH_TYPE_FLOW(12), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_NCTL0, rtl8264b_nctl0_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_NCTL1, rtl8264b_nctl1_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 3, PHY_PATCH_TYPE_NCTL2, rtl8264b_nctl2_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_UC2, rtl8264b_uc2_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 5, PHY_PATCH_TYPE_UC, rtl8264b_uc_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 6, PHY_PATCH_TYPE_DATARAM, rtl8264b_dataram_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 7, RTK_PATCH_TYPE_FLOW(1), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(2), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 9, PHY_PATCH_TYPE_ALGXG, rtl8264b_algxg_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_ALG1G, rtl8264b_alg_giga_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 11, PHY_PATCH_TYPE_NORMAL, rtl8264b_normal_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_TOP, rtl8264b_top_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_SDS, rtl8264b_sds_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 14, PHY_PATCH_TYPE_AFE, rtl8264b_afe_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_RTCT, rtl8264b_rtct_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(3), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 17, RTK_PATCH_TYPE_FLOW(11), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 18, RTK_PATCH_TYPE_FLOW(10), NULL); + + /* compare */ + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 0, PHY_PATCH_TYPE_TOP, rtl8264b_top_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_SDS, rtl8264b_sds_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_AFE, rtl8264b_afe_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 3, RTK_PATCH_TYPE_FLOW(4), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_NCTL0, rtl8264b_nctl0_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 5, RTK_PATCH_TYPE_FLOW(5), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 6, RTK_PATCH_TYPE_FLOW(6), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 7, PHY_PATCH_TYPE_NCTL1, rtl8264b_nctl1_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(7), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 9, RTK_PATCH_TYPE_FLOW(8), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_NCTL2, rtl8264b_nctl2_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 11, RTK_PATCH_TYPE_FLOW(9), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_UC, rtl8264b_uc_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_UC2, rtl8264b_uc2_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 14, RTK_PATCH_TYPE_FLOW(12), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_DATARAM, rtl8264b_dataram_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(1), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 17, PHY_PATCH_TYPE_ALGXG, rtl8264b_algxg_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 18, PHY_PATCH_TYPE_ALG1G, rtl8264b_alg_giga_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 19, PHY_PATCH_TYPE_NORMAL, rtl8264b_normal_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 20, PHY_PATCH_TYPE_RTCT, rtl8264b_rtct_conf); + } + else + { + /* patch */ + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 0, RTK_PATCH_TYPE_FLOW(0), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_NCTL0, rtl8261n_c_nctl0_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_NCTL1, rtl8261n_c_nctl1_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 3, PHY_PATCH_TYPE_NCTL2, rtl8261n_c_nctl2_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_UC2, rtl8261n_c_uc2_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 5, PHY_PATCH_TYPE_UC, rtl8261n_c_uc_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 6, PHY_PATCH_TYPE_DATARAM, rtl8261n_c_dataram_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 7, RTK_PATCH_TYPE_FLOW(1), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(2), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 9, PHY_PATCH_TYPE_ALGXG, rtl8261n_c_algxg_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_ALG1G, rtl8261n_c_alg_giga_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 11, PHY_PATCH_TYPE_NORMAL, rtl8261n_c_normal_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_TOP, rtl8261n_c_top_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_SDS, rtl8261n_c_sds_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 14, PHY_PATCH_TYPE_AFE, rtl8261n_c_afe_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_RTCT, rtl8261n_c_rtct_conf); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(3), NULL); + PHYPATCH_SEQ_TABLE_ASSIGN(patch_db, 17, RTK_PATCH_TYPE_FLOW(10), NULL); + + /* compare */ + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 0, PHY_PATCH_TYPE_TOP, rtl8261n_c_top_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 1, PHY_PATCH_TYPE_SDS, rtl8261n_c_sds_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 2, PHY_PATCH_TYPE_AFE, rtl8261n_c_afe_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 3, RTK_PATCH_TYPE_FLOW(4), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 4, PHY_PATCH_TYPE_NCTL0, rtl8261n_c_nctl0_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 5, RTK_PATCH_TYPE_FLOW(5), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 6, RTK_PATCH_TYPE_FLOW(6), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 7, PHY_PATCH_TYPE_NCTL1, rtl8261n_c_nctl1_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 8, RTK_PATCH_TYPE_FLOW(7), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 9, RTK_PATCH_TYPE_FLOW(8), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 10, PHY_PATCH_TYPE_NCTL2, rtl8261n_c_nctl2_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 11, RTK_PATCH_TYPE_FLOW(9), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 12, PHY_PATCH_TYPE_UC, rtl8261n_c_uc_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 13, PHY_PATCH_TYPE_UC2, rtl8261n_c_uc2_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 14, RTK_PATCH_TYPE_FLOW(0), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 15, PHY_PATCH_TYPE_DATARAM, rtl8261n_c_dataram_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 16, RTK_PATCH_TYPE_FLOW(1), NULL); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 17, PHY_PATCH_TYPE_ALGXG, rtl8261n_c_algxg_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 18, PHY_PATCH_TYPE_ALG1G, rtl8261n_c_alg_giga_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 19, PHY_PATCH_TYPE_NORMAL, rtl8261n_c_normal_conf); + PHYPATCH_CMP_TABLE_ASSIGN(patch_db, 20, PHY_PATCH_TYPE_RTCT, rtl8261n_c_rtct_conf); + } + *pPhy_patchDb = patch_db; + return ret; +} + +/* Function Name: + * phy_rtl826xb_patch + * Description: + * apply initial patch data to PHY + * Input: + * unit - unit id + * baseport - base port id on the PHY chip + * portOffset - the index offset base on baseport for the port to patch + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_SUPPORTED + * RT_ERR_ABORT + * Note: + * None + */ +int32 phy_rtl826xb_patch(uint32 unit, rtk_port_t port, uint8 portOffset) +{ + return phy_patch( unit, port, portOffset, PHY_PATCH_MODE_NORMAL); +} + +/* Function Name: + * phy_rtl826xb_broadcast_patch + * Description: + * apply patch data to PHY + * Input: + * unit - unit id + * baseport - base port id on the PHY chip + * portOffset - the index offset base on baseport for the port to patch + * perChip - 1 for per-chip mode, 0 for per-bus mode + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_SUPPORTED + * RT_ERR_ABORT + * Note: + * None + */ +int32 phy_rtl826xb_broadcast_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 perChip) +{ + int32 ret = 0; + if (perChip == 0) + { + ret = phy_patch(unit, port, portOffset, PHY_PATCH_MODE_BCAST_BUS); + } + else + { + ret = phy_patch(unit, port, portOffset, PHY_PATCH_MODE_BCAST); + } + return ret; +} + diff --git a/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h new file mode 100644 index 000000000000..c2311ef2bf46 --- /dev/null +++ b/drivers/net/phy/rtl8261n/phy_rtl826xb_patch.h @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __HAL_PHY_PHY_RTL826XB_PATCH_H__ +#define __HAL_PHY_PHY_RTL826XB_PATCH_H__ + +/* + * Include Files + */ +#if defined(RTK_PHYDRV_IN_LINUX) + #include "rtk_osal.h" + #include "rtk_phylib_def.h" +#else + #include + #include +#endif + +/* Function Name: + * phy_rtl826xb_patch + * Description: + * apply patch data to PHY + * Input: + * unit - unit id + * baseport - base port id on the PHY chip + * portOffset - the index offset base on baseport for the port to patch + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_SUPPORTED + * RT_ERR_ABORT + * Note: + * None + */ +extern int32 phy_rtl826xb_patch(uint32 unit, rtk_port_t baseport, uint8 portOffset); + +/* Function Name: + * phy_rtl826xb_broadcast_patch + * Description: + * apply patch data to PHY + * Input: + * unit - unit id + * baseport - base port id on the PHY chip + * portOffset - the index offset base on baseport for the port to patch + * perChip - 1 for per-chip mode, 0 for per-bus mode + * Output: + * None + * Return: + * RT_ERR_OK + * RT_ERR_FAILED + * RT_ERR_NOT_SUPPORTED + * RT_ERR_ABORT + * Note: + * None + */ +extern int32 phy_rtl826xb_broadcast_patch(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 perChip); + +extern int32 phy_rtl826xb_patch_db_init(uint32 unit, rtk_port_t port, rt_phy_patch_db_t **pPhy_patchDb); +#endif /* __HAL_PHY_PHY_RTL826XB_PATCH_H__ */ diff --git a/drivers/net/phy/rtl8261n/rtk_osal.c b/drivers/net/phy/rtl8261n/rtk_osal.c new file mode 100644 index 000000000000..35339400d01b --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_osal.c @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#include "type.h" +#include "error.h" +#include "rtk_phylib_def.h" +#include "rtk_osal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +int32 +osal_time_usecs_get(osal_usecs_t *pUsec) +{ + struct timespec64 ts; + + RT_PARAM_CHK((NULL == pUsec), RT_ERR_NULL_POINTER); + + ktime_get_ts64(&ts); + *pUsec = (osal_usecs_t)((ts.tv_sec * USEC_PER_SEC) + (ts.tv_nsec / NSEC_PER_USEC)); + return RT_ERR_OK; +} + +void * +osal_alloc(uint32 size) +{ + void *p; + p = kmalloc((size_t)size, GFP_ATOMIC); + return p; +} + +int32 +phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData) +{ + int32 rData = 0; + rData = phy_read_mmd(port, mmdAddr, mmdReg); + if (rData < 0) + return RT_ERR_FAILED; + *pData = (uint32)rData; + return RT_ERR_OK; +} + +int32 +phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data) +{ + int ret = phy_write_mmd(port, mmdAddr, mmdReg, data); + return (ret < 0) ? RT_ERR_FAILED : RT_ERR_OK; +} diff --git a/drivers/net/phy/rtl8261n/rtk_osal.h b/drivers/net/phy/rtl8261n/rtk_osal.h new file mode 100644 index 000000000000..edf674611efd --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_osal.h @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __RTK_PHY_OSAL_H +#define __RTK_PHY_OSAL_H + +#include +#include +#include "type.h" +#include "error.h" +#include "phy_patch.h" +#include "rtk_phylib.h" + +#ifdef PHYPATCH_DB_GET + #undef PHYPATCH_DB_GET +#endif + +#define PHYPATCH_DB_GET(_unit, _pPhy_device, _pPatchDb) \ + do { \ + struct rtk_phy_priv *_pPriv = (_pPhy_device)->priv; \ + rt_phy_patch_db_t *_pDb = _pPriv->patch; _pPatchDb = _pDb; \ + /*printk("[PHYPATCH_DB_GET] ? [%s]\n", (_pDb != NULL) ? "E":"N");*/ \ + } while(0) + +#define HWP_9300_FAMILY_ID(_unit) 0 +#define HWP_9310_FAMILY_ID(_unit) 0 +#define RTK_9300_FAMILY_ID(_unit) 0 +#define RTK_9310_FAMILY_ID(_unit) 0 +#define RTK_9311B_FAMILY_ID(_unit) 0 +#define RTK_9330_FAMILY_ID(_unit) 0 + +#ifndef WAIT_COMPLETE_VAR +#define WAIT_COMPLETE_VAR() \ + osal_usecs_t _t, _now, _t_wait=0, _timeout; \ + int32 _chkCnt=0; + +#define WAIT_COMPLETE(_timeout_us) \ + _timeout = _timeout_us; \ + for(osal_time_usecs_get(&_t),osal_time_usecs_get(&_now),_t_wait=0,_chkCnt=0 ; \ + (_t_wait <= _timeout); \ + osal_time_usecs_get(&_now), _chkCnt++, _t_wait += ((_now >= _t) ? (_now - _t) : (0xFFFFFFFF - _t + _now)),_t = _now \ + ) + +#define WAIT_COMPLETE_IS_TIMEOUT() (_t_wait > _timeout) +#endif + +/* OSAL */ +#include +int32 osal_time_usecs_get(osal_usecs_t *pUsec); +void *osal_alloc(uint32 size); +#define osal_time_mdelay mdelay + +#include /* for Kernel Space */ +#include +#include +#define osal_strlen strlen +#define osal_strcmp strcmp +#define osal_strcpy strcpy +#define osal_strncpy strncpy +#define osal_strcat strcat +#define osal_strchr strchr +#define osal_memset memset +#define osal_memcpy memcpy +#define osal_memcmp memcmp +#define osal_strdup strdup +#define osal_strncmp strncmp +#define osal_strstr strstr +#define osal_strtok strtok +#define osal_strtok_r strtok_r +#define osal_toupper toupper + +#define osal_printf printk + +/* HWP */ +#define HWP_PORT_SMI(unit, port) 0 +#define HWP_PHY_MODEL_BY_PORT(unit, port) 0 +#define HWP_PHY_ADDR(unit, port) 0 +#define HWP_PHY_BASE_MACID(unit, p) 0 +#define HWP_PORT_TRAVS_EXCEPT_CPU(unit, p) if (bcast_phyad < 0x1F && p != NULL) + + +/* RT_LOG */ +//#define RT_LOG(level, module, fmt, args...) do { printk("RT_LOG:"fmt, ## args); } while(0) +#define RT_LOG(level, module, fmt, args...) do {} while(0) +#define RT_ERR(error_code, module, fmt, args...) do {} while(0) +#define RT_INIT_ERR(error_code, module, fmt, args...) do {} while(0) +#define RT_INIT_MSG(fmt, args...) do {} while(0) + +#define phy_826xb_ctrl_set(unit, p, RTK_PHY_CTRL_MIIM_BCAST_PHYAD, bcast_phyad) 0 + +/* reg access */ +int32 phy_common_general_reg_mmd_get(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 *pData); +int32 phy_common_general_reg_mmd_set(uint32 unit, rtk_port_t port, uint32 mmdAddr, uint32 mmdReg, uint32 data); + + +#endif /* __RTK_PHY_OSAL_H */ diff --git a/drivers/net/phy/rtl8261n/rtk_phy.c b/drivers/net/phy/rtl8261n/rtk_phy.c new file mode 100644 index 000000000000..a1eb2c16149c --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phy.c @@ -0,0 +1,324 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#include +#include +#include + +#include "phy_rtl826xb_patch.h" +#include "rtk_phylib_rtl826xb.h" +#include "rtk_phylib.h" + +#define REALTEK_PHY_ID_RTL8261N 0x001CCAF3 +#define REALTEK_PHY_ID_RTL8264B 0x001CC813 +#define REALTEK_PHY_ID_RTL8264 0x001CCAF2 + +#define REALTEK_SERDES_GLOBAL_CFG 0xC1 +#define REALTEK_HSO_INV BIT(7) +#define REALTEK_HSI_INV BIT(6) + +static int rtl826xb_get_features(struct phy_device *phydev) +{ + int ret; + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + linkmode_or(phydev->supported, phydev->supported, PHY_BASIC_FEATURES); + + + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + phydev->supported); + + /* not support 10M modes */ + linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, + phydev->supported); + linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, + phydev->supported); + + return 0; +} + +static int rtl826xb_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct rtk_phy_priv *priv = NULL; + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct rtk_phy_priv), GFP_KERNEL); + if (!priv) + { + return -ENOMEM; + } + memset(priv, 0, sizeof(struct rtk_phy_priv)); + + if (phy_rtl826xb_patch_db_init(0, phydev, &(priv->patch)) != RT_ERR_OK) + return -ENOMEM; + + priv->phytype = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (RTK_PHYLIB_RTL8261N) : (RTK_PHYLIB_RTL8264B); + priv->isBasePort = (phydev->drv->phy_id == REALTEK_PHY_ID_RTL8261N) ? (1) : (((phydev->mdio.addr % 4) == 0) ? (1) : (0)); + priv->pnswap_rx = device_property_read_bool(dev, "realtek,pnswap-rx"); + priv->pnswap_tx = device_property_read_bool(dev, "realtek,pnswap-tx"); + phydev->priv = priv; + + return 0; +} + +static int rtkphy_config_init(struct phy_device *phydev) +{ + struct rtk_phy_priv *priv = phydev->priv; + int ret = 0; + switch (phydev->drv->phy_id) + { + case REALTEK_PHY_ID_RTL8261N: + case REALTEK_PHY_ID_RTL8264B: + case REALTEK_PHY_ID_RTL8264: + phydev_info(phydev, "%s:%u [RTL8261N/RTL8264/RTL826XB] phy_id: 0x%X PHYAD:%d\n", __FUNCTION__, __LINE__, phydev->drv->phy_id, phydev->mdio.addr); +#ifdef CONFIG_MACH_REALTEK_RTL + return 0; +#endif + + #if 1 /* toggle reset */ + phy_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 1); + phy_modify_mmd_changed(phydev, 30, 0x145, BIT(0) , 0); + mdelay(30); + #endif + + ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_NORMAL); + if (ret) + { + phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret); + return ret; + } + #if 0 /* Debug: patch check */ + ret = phy_patch(0, phydev, 0, PHY_PATCH_MODE_CMP); + if (ret) + { + phydev_err(phydev, "%s:%u [RTL8261N/RTL826XB] phy_patch failed!! 0x%X\n", __FUNCTION__, __LINE__, ret); + return ret; + } + printk("[%s,%u] patch chk %s\n", __FUNCTION__, __LINE__, (ret == 0) ? "PASS" : "FAIL"); + #endif + #if 0 /* Debug: USXGMII*/ + { + uint32 data = 0; + rtk_phylib_826xb_sds_read(phydev, 0x07, 0x10, 15, 0, &data); + printk("[%s,%u] SDS 0x07, 0x10 : 0x%X\n", __FUNCTION__, __LINE__, data); + rtk_phylib_826xb_sds_read(phydev, 0x06, 0x12, 15, 0, &data); + printk("[%s,%u] SDS 0x06, 0x12 : 0x%X\n", __FUNCTION__, __LINE__, data); + } + { + u16 sdspage = 0x5, sdsreg = 0x0; + u16 regData = (sdspage & 0x3f) | ((sdsreg & 0x1f) << 6) | BIT(15); + u16 readData = 0; + phy_write_mmd(phydev, 30, 323, regData); + do + { + udelay(10); + readData = phy_read_mmd(phydev, 30, 323); + } while ((readData & BIT(15)) != 0); + readData = phy_read_mmd(phydev, 30, 322); + printk("[%s,%d] sds link [%s] (0x%X)\n", __FUNCTION__, __LINE__, (readData & BIT(12)) ? "UP" : "DOWN", readData); + } + #endif + + if (priv->pnswap_rx) + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + REALTEK_SERDES_GLOBAL_CFG, + REALTEK_HSI_INV); + + if (priv->pnswap_tx) + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + REALTEK_SERDES_GLOBAL_CFG, + REALTEK_HSO_INV); + + break; + default: + phydev_err(phydev, "%s:%u Unknow phy_id: 0x%X\n", __FUNCTION__, __LINE__, phydev->drv->phy_id); + return -EPERM; + } + + return ret; +} + +static int rtkphy_c45_suspend(struct phy_device *phydev) +{ + int ret = 0; + +#ifndef CONFIG_MACH_REALTEK_RTL + ret = rtk_phylib_c45_power_low(phydev); +#endif + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + return ret; +} + +static int rtkphy_c45_resume(struct phy_device *phydev) +{ +#ifndef CONFIG_MACH_REALTEK_RTL + return rtk_phylib_c45_power_normal(phydev); +#else + return 0; +#endif +} + +static int rtkphy_c45_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u16 reg = 0; + int ret = 0; + + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + if (phydev->autoneg == AUTONEG_DISABLE) + return genphy_c45_pma_setup_forced(phydev); + + ret = genphy_c45_an_config_aneg(phydev); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + reg = 0; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising)) + reg |= BIT(9); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + phydev->advertising)) + reg |= BIT(8); + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xA412, + BIT(9) | BIT(8) , reg); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + return genphy_c45_check_and_restart_aneg(phydev, changed); +} + +static int rtkphy_c45_aneg_done(struct phy_device *phydev) +{ + return genphy_c45_aneg_done(phydev); +} + +static int rtkphy_c45_read_status(struct phy_device *phydev) +{ + int ret = 0, status = 0; + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + ret = genphy_c45_read_link(phydev); + if (ret) + return ret; + + if (phydev->autoneg == AUTONEG_ENABLE) + { + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->lp_advertising); + + ret = genphy_c45_read_lpa(phydev); + if (ret) + return ret; + + status = phy_read_mmd(phydev, 31, 0xA414); + if (status < 0) + return status; + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->lp_advertising, status & BIT(11)); + + phy_resolve_aneg_linkmode(phydev); + } + else + { + ret = genphy_c45_read_pma(phydev); + } + + /* mdix*/ + status = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_SWAPPOL); + if (status < 0) + return status; + + switch (status & 0x3) + { + case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: + phydev->mdix = ETH_TP_MDI; + break; + + case 0: + phydev->mdix = ETH_TP_MDI_X; + break; + + default: + phydev->mdix = ETH_TP_MDI_INVALID; + break; + } + + return ret; +} + + +static struct phy_driver rtk_phy_drivers[] = { + { + PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N), + .name = "Realtek RTL8261N", + .get_features = rtl826xb_get_features, + .config_init = rtkphy_config_init, + .probe = rtl826xb_probe, + .suspend = rtkphy_c45_suspend, + .resume = rtkphy_c45_resume, + .config_aneg = rtkphy_c45_config_aneg, + .aneg_done = rtkphy_c45_aneg_done, + .read_status = rtkphy_c45_read_status, + }, + { + PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B), + .name = "Realtek RTL8264B", + .get_features = rtl826xb_get_features, + .config_init = rtkphy_config_init, + .probe = rtl826xb_probe, + .suspend = rtkphy_c45_suspend, + .resume = rtkphy_c45_resume, + .config_aneg = rtkphy_c45_config_aneg, + .aneg_done = rtkphy_c45_aneg_done, + .read_status = rtkphy_c45_read_status, + }, + { + PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264), + .name = "Realtek RTL8264", + .get_features = rtl826xb_get_features, + .config_init = rtkphy_config_init, + .probe = rtl826xb_probe, + .suspend = rtkphy_c45_suspend, + .resume = rtkphy_c45_resume, + .config_aneg = rtkphy_c45_config_aneg, + .aneg_done = rtkphy_c45_aneg_done, + .read_status = rtkphy_c45_read_status, + }, +}; + +module_phy_driver(rtk_phy_drivers); + + +static struct mdio_device_id __maybe_unused rtk_phy_tbl[] = { + { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8261N) }, + { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264B) }, + { PHY_ID_MATCH_EXACT(REALTEK_PHY_ID_RTL8264) }, + { }, +}; + +MODULE_DEVICE_TABLE(mdio, rtk_phy_tbl); + +MODULE_AUTHOR("Realtek"); +MODULE_DESCRIPTION("Realtek PHY drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/rtl8261n/rtk_phylib.c b/drivers/net/phy/rtl8261n/rtk_phylib.c new file mode 100644 index 000000000000..7dd593ce72df --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phylib.c @@ -0,0 +1,108 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#include "rtk_phylib.h" +#include + + +/* OSAL */ + +void rtk_phylib_mdelay(uint32 msec) +{ +#if defined(RTK_PHYDRV_IN_LINUX) + mdelay(msec); +#else + osal_time_mdelay(msec); +#endif +} + + +void rtk_phylib_udelay(uint32 usec) +{ +#if defined(RTK_PHYDRV_IN_LINUX) + if (1000 <= usec) + { + mdelay(usec/1000); + usec = usec % 1000; + } + udelay(usec); +#else + osal_time_udelay(usec); +#endif +} + + +/* Register Access APIs */ +int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data) +{ + int32 ret = 0; + uint32 mask = 0; + mask = UINT32_BITS_MASK(msb,lsb); + +#if defined(RTK_PHYDRV_IN_LINUX) + ret = phy_modify_mmd(phydev, mmd, reg, mask, data); +#else + { + uint32 rData = 0, wData = 0; + if ((msb != 15) || (lsb != 0)) + { + if ((ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData)) != RT_ERR_OK) + return ret; + } + wData = REG32_FIELD_SET(rData, data, lsb, mask); + ret = phy_common_general_reg_mmd_set(phydev->unit, phydev->port, page, reg, wData); + } +#endif + + return ret; +} + +int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 mask = 0; + mask = UINT32_BITS_MASK(msb,lsb); + +#if defined(RTK_PHYDRV_IN_LINUX) + rData = phy_read_mmd(phydev, mmd, reg); +#else + { + ret = phy_common_general_reg_mmd_get(phydev->unit, phydev->port, page, reg, &rData); + } +#endif + + *pData = REG32_FIELD_GET(rData, lsb, mask); + return ret; +} + +/* Function Driver */ + +int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev) +{ + int32 ret = 0; + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 0)); + + return 0; +} + +int32 rtk_phylib_c45_power_low(rtk_phydev *phydev) +{ + int32 ret = 0; + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 1, 0, 11, 11, 1)); + + return 0; +} + +int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable) +{ + int32 ret = 0; + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 3, 0, 14, 14, (enable == 0) ? 0 : 1)); + + return 0; +} + + diff --git a/drivers/net/phy/rtl8261n/rtk_phylib.h b/drivers/net/phy/rtl8261n/rtk_phylib.h new file mode 100644 index 000000000000..c1253b1ec975 --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phylib.h @@ -0,0 +1,106 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __RTK_PHYLIB_H +#define __RTK_PHYLIB_H + +#if defined(RTK_PHYDRV_IN_LINUX) + #include + + #include "type.h" + #include "rtk_phylib_def.h" +#else + //#include SDK headers +#endif + +#if defined(RTK_PHYDRV_IN_LINUX) + #define PR_INFO(_fmt, _args...) pr_info(_fmt, ##_args) + #define PR_DBG(_fmt, _args...) pr_debug(_fmt, ##_args) + #define PR_ERR(_fmt, _args...) pr_err("ERROR: "_fmt, ##_args) + + #define RTK_PHYLIB_ERR_FAILED (-EPERM) + #define RTK_PHYLIB_ERR_INPUT (-EINVAL) + #define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (-ENOSPC) + #define RTK_PHYLIB_ERR_TIMEOUT (-ETIME) + #define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (-ENODATA) +#else + #define PR_INFO(_fmt, _args...) RT_LOG(LOG_INFO, (MOD_HAL|MOD_PHY), _fmt, ##_args) + #define PR_DBG(_fmt, _args...) RT_LOG(LOG_DEBUG, (MOD_HAL|MOD_PHY), _fmt, ##_args) + #define PR_ERR(_fmt, _args...) RT_LOG(LOG_MAJOR_ERR, (MOD_HAL|MOD_PHY), _fmt, ##_args) + + #define RTK_PHYLIB_ERR_FAILED (RT_ERR_FAILED) + #define RTK_PHYLIB_ERR_INPUT (RT_ERR_INPUT) + #define RTK_PHYLIB_ERR_EXCEEDS_CAPACITY (RT_ERR_EXCEEDS_CAPACITY) + #define RTK_PHYLIB_ERR_TIMEOUT (RT_ERR_BUSYWAIT_TIMEOUT) + #define RTK_PHYLIB_ERR_ENTRY_NOTFOUND (RT_ERR_ENTRY_NOTFOUND) +#endif + +typedef enum rtk_phylib_phy_e +{ + RTK_PHYLIB_NONE, + RTK_PHYLIB_RTL8261N, + RTK_PHYLIB_RTL8264B, + RTK_PHYLIB_END +} rtk_phylib_phy_t; + +struct rtk_phy_priv { + rtk_phylib_phy_t phytype; + uint8 isBasePort; + rt_phy_patch_db_t *patch; + + bool pnswap_rx; + bool pnswap_tx; +}; + +#if defined(RTK_PHYDRV_IN_LINUX) + typedef struct phy_device rtk_phydev; +#else + struct rtk_phy_dev_s + { + uint32 unit; + rtk_port_t port; + + struct rtk_phy_priv *priv; + }; + typedef struct rtk_phy_dev_s rtk_phydev; +#endif + +#define RTK_PHYLIB_ERR_CHK(op)\ +do {\ + if ((ret = (op)) != 0)\ + return ret;\ +} while(0) + +#define RTK_PHYLIB_VAL_TO_BYTE_ARRAY(_val, _valbytes, _array, _start, _bytes)\ +do{\ + uint32 _i = 0;\ + for (_i = 0; _i < _bytes; _i++)\ + _array[_start+_i] = (_val >> (8* (_valbytes - _i - 1)));\ +}while(0) + +#define RTK_PHYLIB_BYTE_ARRAY_TO_VAL(_val, _array, _start, _bytes)\ +do{\ + uint32 _i = 0;\ + for (_i = 0; _i < _bytes; _i++)\ + _val = (_val << 8) | _array[_start + _i];\ +}while(0) + + +/* OSAL */ +void rtk_phylib_mdelay(uint32 msec); +void rtk_phylib_udelay(uint32 usec); + +/* Register Access APIs */ +int32 rtk_phylib_mmd_write(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 data); +int32 rtk_phylib_mmd_read(rtk_phydev *phydev, uint32 mmd, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData); + +/* Function Driver */ +int32 rtk_phylib_c45_power_normal(rtk_phydev *phydev); +int32 rtk_phylib_c45_power_low(rtk_phydev *phydev); +int32 rtk_phylib_c45_pcs_loopback(rtk_phydev *phydev, uint32 enable); + + +#endif /* __RTK_PHYLIB_H */ diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_def.h b/drivers/net/phy/rtl8261n/rtk_phylib_def.h new file mode 100644 index 000000000000..f49f0b547cc3 --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phylib_def.h @@ -0,0 +1,166 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ +#ifndef __RTK_PHYLIB_DEF_H +#define __RTK_PHYLIB_DEF_H + +#include "type.h" + +//#define PHY_C22_MMD_PAGE 0 +#define PHY_C22_MMD_PAGE 0x0A41 +#define PHY_C22_MMD_DEV_REG 13 +#define PHY_C22_MMD_ADD_REG 14 + +/* MDIO Manageable Device(MDD) address*/ +#define PHY_MMD_PMAPMD 1 +#define PHY_MMD_PCS 3 +#define PHY_MMD_AN 7 +#define PHY_MMD_VEND1 30 /* Vendor specific 1 */ +#define PHY_MMD_VEND2 31 /* Vendor specific 2 */ + +#define BIT_0 0x00000001U +#define BIT_1 0x00000002U +#define BIT_2 0x00000004U +#define BIT_3 0x00000008U +#define BIT_4 0x00000010U +#define BIT_5 0x00000020U +#define BIT_6 0x00000040U +#define BIT_7 0x00000080U +#define BIT_8 0x00000100U +#define BIT_9 0x00000200U +#define BIT_10 0x00000400U +#define BIT_11 0x00000800U +#define BIT_12 0x00001000U +#define BIT_13 0x00002000U +#define BIT_14 0x00004000U +#define BIT_15 0x00008000U +#define BIT_16 0x00010000U +#define BIT_17 0x00020000U +#define BIT_18 0x00040000U +#define BIT_19 0x00080000U +#define BIT_20 0x00100000U +#define BIT_21 0x00200000U +#define BIT_22 0x00400000U +#define BIT_23 0x00800000U +#define BIT_24 0x01000000U +#define BIT_25 0x02000000U +#define BIT_26 0x04000000U +#define BIT_27 0x08000000U +#define BIT_28 0x10000000U +#define BIT_29 0x20000000U +#define BIT_30 0x40000000U +#define BIT_31 0x80000000U + +#define MASK_1_BITS (BIT_1 - 1) +#define MASK_2_BITS (BIT_2 - 1) +#define MASK_3_BITS (BIT_3 - 1) +#define MASK_4_BITS (BIT_4 - 1) +#define MASK_5_BITS (BIT_5 - 1) +#define MASK_6_BITS (BIT_6 - 1) +#define MASK_7_BITS (BIT_7 - 1) +#define MASK_8_BITS (BIT_8 - 1) +#define MASK_9_BITS (BIT_9 - 1) +#define MASK_10_BITS (BIT_10 - 1) +#define MASK_11_BITS (BIT_11 - 1) +#define MASK_12_BITS (BIT_12 - 1) +#define MASK_13_BITS (BIT_13 - 1) +#define MASK_14_BITS (BIT_14 - 1) +#define MASK_15_BITS (BIT_15 - 1) +#define MASK_16_BITS (BIT_16 - 1) +#define MASK_17_BITS (BIT_17 - 1) +#define MASK_18_BITS (BIT_18 - 1) +#define MASK_19_BITS (BIT_19 - 1) +#define MASK_20_BITS (BIT_20 - 1) +#define MASK_21_BITS (BIT_21 - 1) +#define MASK_22_BITS (BIT_22 - 1) +#define MASK_23_BITS (BIT_23 - 1) +#define MASK_24_BITS (BIT_24 - 1) +#define MASK_25_BITS (BIT_25 - 1) +#define MASK_26_BITS (BIT_26 - 1) +#define MASK_27_BITS (BIT_27 - 1) +#define MASK_28_BITS (BIT_28 - 1) +#define MASK_29_BITS (BIT_29 - 1) +#define MASK_30_BITS (BIT_30 - 1) +#define MASK_31_BITS (BIT_31 - 1) + +#define REG32_FIELD_SET(_data, _val, _fOffset, _fMask) ((_data & ~(_fMask)) | ((_val << (_fOffset)) & (_fMask))) +#define REG32_FIELD_GET(_data, _fOffset, _fMask) ((_data & (_fMask)) >> (_fOffset)) +#define UINT32_BITS_MASK(_mBit, _lBit) ((0xFFFFFFFF >> (31 - _mBit)) ^ ((1 << _lBit) - 1)) + +typedef struct phy_device * rtk_port_t; + +#if 1 /* ss\sdk\include\hal\phy\phydef.h */ +/* unified patch format */ +typedef enum rtk_phypatch_type_e +{ + PHY_PATCH_TYPE_NONE = 0, + PHY_PATCH_TYPE_TOP = 1, + PHY_PATCH_TYPE_SDS, + PHY_PATCH_TYPE_AFE, + PHY_PATCH_TYPE_UC, + PHY_PATCH_TYPE_UC2, + PHY_PATCH_TYPE_NCTL0, + PHY_PATCH_TYPE_NCTL1, + PHY_PATCH_TYPE_NCTL2, + PHY_PATCH_TYPE_ALGXG, + PHY_PATCH_TYPE_ALG1G, + PHY_PATCH_TYPE_NORMAL, + PHY_PATCH_TYPE_DATARAM, + PHY_PATCH_TYPE_RTCT, + PHY_PATCH_TYPE_END +} rtk_phypatch_type_t; + +#define RTK_PATCH_TYPE_FLOW(_id) (PHY_PATCH_TYPE_END + _id) +#define RTK_PATCH_TYPE_FLOWID_MAX PHY_PATCH_TYPE_END +#define RTK_PATCH_SEQ_MAX ( PHY_PATCH_TYPE_END + RTK_PATCH_TYPE_FLOWID_MAX -1) + +typedef struct rtk_hwpatch_s +{ + uint8 patch_op; + uint8 portmask; + uint16 pagemmd; + uint16 addr; + uint8 msb; + uint8 lsb; + uint16 data; + uint8 compare_op; + uint16 sram_p; + uint16 sram_rr; + uint16 sram_rw; + uint16 sram_a; +} rtk_hwpatch_t; + +typedef struct rtk_hwpatch_data_s +{ + rtk_hwpatch_t *conf; + uint32 size; +} rtk_hwpatch_data_t; + +typedef struct rtk_hwpatch_seq_s +{ + uint8 patch_type; + union + { + rtk_hwpatch_data_t data; + uint8 flow_id; + } patch; +} rtk_hwpatch_seq_t; + +typedef struct rt_phy_patch_db_s +{ + /* patch operation */ + int32 (*fPatch_op)(uint32 unit, rtk_port_t port, uint8 portOffset, rtk_hwpatch_t *pPatch_data, uint8 patch_mode); + int32 (*fPatch_flow)(uint32 unit, rtk_port_t port, uint8 portOffset, uint8 patch_flow, uint8 patch_mode); + + /* patch data */ + rtk_hwpatch_seq_t seq_table[RTK_PATCH_SEQ_MAX]; + rtk_hwpatch_seq_t cmp_table[RTK_PATCH_SEQ_MAX]; + +} rt_phy_patch_db_t; +#endif + + + +#endif /* __RTK_PHYLIB_DEF_H */ diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c new file mode 100644 index 000000000000..1c33846a70fc --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.c @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#include "rtk_phylib_rtl826xb.h" + +/* Indirect Register Access APIs */ +int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData) +{ + int32 ret = 0; + uint32 rData = 0; + uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8000); + uint32 i = 0; + uint32 mask = 0; + mask = UINT32_BITS_MASK(msb,lsb); + + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op)); + + for (i = 0; i < 10; i++) + { + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 323, 15, 15, &rData)); + if (rData == 0) + { + break; + } + rtk_phylib_udelay(10); + } + if (i == 10) + { + return -1; + } + + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_read(phydev, 30, 322, 15, 0, &rData)); + *pData = REG32_FIELD_GET(rData, lsb, mask); + + return ret; +} + +int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data) +{ + int32 ret = 0; + uint32 wData = 0, rData = 0; + uint32 op = (page & 0x3f) | ((reg & 0x1f) << 6) | (0x8800); + uint32 mask = 0; + mask = UINT32_BITS_MASK(msb,lsb); + + RTK_PHYLIB_ERR_CHK(rtk_phylib_826xb_sds_read(phydev, page, reg, 15, 0, &rData)); + + wData = REG32_FIELD_SET(rData, data, lsb, mask); + + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 321, 15, 0, wData)); + RTK_PHYLIB_ERR_CHK(rtk_phylib_mmd_write(phydev, 30, 323, 15, 0, op)); + + return ret; +} diff --git a/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h new file mode 100644 index 000000000000..9f827d4ba254 --- /dev/null +++ b/drivers/net/phy/rtl8261n/rtk_phylib_rtl826xb.h @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __RTK_PHYLIB_RTL826XB_H +#define __RTK_PHYLIB_RTL826XB_H + +#if defined(RTK_PHYDRV_IN_LINUX) + #include "rtk_phylib.h" +#else + //#include SDK headers +#endif + +int rtk_phylib_826xb_sds_read(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 *pData); +int rtk_phylib_826xb_sds_write(rtk_phydev *phydev, uint32 page, uint32 reg, uint8 msb, uint8 lsb, uint32 data); + +#endif /* __RTK_PHYLIB_RTL826XB_H */ diff --git a/drivers/net/phy/rtl8261n/type.h b/drivers/net/phy/rtl8261n/type.h new file mode 100644 index 000000000000..98d7e15e1e4b --- /dev/null +++ b/drivers/net/phy/rtl8261n/type.h @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Realtek Semiconductor Corp. All rights reserved. + */ + +#ifndef __COMMON_TYPE_H__ +#define __COMMON_TYPE_H__ + +/* + * Symbol Definition + */ + +#define USING_RTSTK_PKT_AS_RAIL + + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef ETHER_ADDR_LEN +#define ETHER_ADDR_LEN 6 +#endif + +#ifndef IP6_ADDR_LEN +#define IP6_ADDR_LEN 16 +#endif + + +/* + * Data Type Declaration + */ +#ifndef uint64 +typedef unsigned long long uint64; +#endif + +#ifndef int64 +typedef signed long long int64; +#endif + +#ifndef uint32 +typedef unsigned int uint32; +#endif + +#ifndef int32 +typedef signed int int32; +#endif + +#ifndef uint16 +typedef unsigned short uint16; +#endif + +#ifndef int16 +typedef signed short int16; +#endif + +#ifndef uint8 +typedef unsigned char uint8; +#endif + +#ifndef int8 +typedef signed char int8; +#endif + +//#define CONFIG_SDK_WORDSIZE_64 /* not ready */ +#ifdef CONFIG_SDK_WORDSIZE_64 + typedef long int intptr; + typedef unsigned long int uintptr; +#else + typedef int intptr; + typedef unsigned int uintptr; +#endif + + +#ifndef ipaddr_t +typedef uint32 ipaddr_t; /* ipv4 address type */ +#endif + +/* configuration mode type */ +typedef enum rtk_enable_e +{ + DISABLED = 0, + ENABLED, + RTK_ENABLE_END +} rtk_enable_t; + +/* initial state of module */ +typedef enum init_state_e +{ + INIT_NOT_COMPLETED = 0, + INIT_COMPLETED, + INIT_STATE_END +} init_state_t; + +/* ethernet address type */ +typedef struct rtk_mac_s +{ + uint8 octet[ETHER_ADDR_LEN]; +} rtk_mac_t; + +typedef uint32 osal_time_t; +typedef uint32 osal_usecs_t; + +/* + * Macro Definition + */ + +#endif /* __COMMON_TYPE_H__ */ + diff --git a/drivers/net/phy/rtl8306.c b/drivers/net/phy/rtl8306.c new file mode 100644 index 000000000000..9bd1735f67b7 --- /dev/null +++ b/drivers/net/phy/rtl8306.c @@ -0,0 +1,1063 @@ +/* + * rtl8306.c: RTL8306S switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG 1 + +/* Global (PHY0) */ +#define RTL8306_REG_PAGE 16 +#define RTL8306_REG_PAGE_LO (1 << 15) +#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */ + +#define RTL8306_NUM_VLANS 16 +#define RTL8306_NUM_PORTS 6 +#define RTL8306_PORT_CPU 5 +#define RTL8306_NUM_PAGES 4 +#define RTL8306_NUM_REGS 32 + +#define RTL_NAME_S "RTL8306S" +#define RTL_NAME_SD "RTL8306SD" +#define RTL_NAME_SDM "RTL8306SDM" +#define RTL_NAME_UNKNOWN "RTL8306(unknown)" + +#define RTL8306_MAGIC 0x8306 + +static LIST_HEAD(phydevs); + +struct rtl_priv { + struct list_head list; + struct switch_dev dev; + int page; + int type; + int do_cpu; + struct mii_bus *bus; + char hwname[sizeof(RTL_NAME_UNKNOWN)]; + bool fixup; +}; + +struct rtl_phyregs { + int nway; + int speed; + int duplex; +}; + +#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev) + +enum { + RTL_TYPE_S, + RTL_TYPE_SD, + RTL_TYPE_SDM, +}; + +struct rtl_reg { + int page; + int phy; + int reg; + int bits; + int shift; + int inverted; +}; + +#define RTL_VLAN_REGOFS(name) \ + (RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name) + +#define RTL_PORT_REGOFS(name) \ + (RTL_REG_PORT1_##name - RTL_REG_PORT0_##name) + +#define RTL_PORT_REG(id, reg) \ + (RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg))) + +#define RTL_VLAN_REG(id, reg) \ + (RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg))) + +#define RTL_GLOBAL_REGATTR(reg) \ + .id = RTL_REG_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = 0, \ + .set = rtl_attr_set_int, \ + .get = rtl_attr_get_int + +#define RTL_PORT_REGATTR(reg) \ + .id = RTL_REG_PORT0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_PORT_REGOFS(reg), \ + .set = rtl_attr_set_port_int, \ + .get = rtl_attr_get_port_int + +#define RTL_VLAN_REGATTR(reg) \ + .id = RTL_REG_VLAN0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_VLAN_REGOFS(reg), \ + .set = rtl_attr_set_vlan_int, \ + .get = rtl_attr_get_vlan_int + +enum rtl_regidx { + RTL_REG_CHIPID, + RTL_REG_CHIPVER, + RTL_REG_CHIPTYPE, + RTL_REG_CPUPORT, + + RTL_REG_EN_CPUPORT, + RTL_REG_EN_TAG_OUT, + RTL_REG_EN_TAG_CLR, + RTL_REG_EN_TAG_IN, + RTL_REG_TRAP_CPU, + RTL_REG_CPU_LINKUP, + RTL_REG_TRUNK_PORTSEL, + RTL_REG_EN_TRUNK, + RTL_REG_RESET, + + RTL_REG_VLAN_ENABLE, + RTL_REG_VLAN_FILTER, + RTL_REG_VLAN_TAG_ONLY, + RTL_REG_VLAN_TAG_AWARE, +#define RTL_VLAN_ENUM(id) \ + RTL_REG_VLAN##id##_VID, \ + RTL_REG_VLAN##id##_PORTMASK + RTL_VLAN_ENUM(0), + RTL_VLAN_ENUM(1), + RTL_VLAN_ENUM(2), + RTL_VLAN_ENUM(3), + RTL_VLAN_ENUM(4), + RTL_VLAN_ENUM(5), + RTL_VLAN_ENUM(6), + RTL_VLAN_ENUM(7), + RTL_VLAN_ENUM(8), + RTL_VLAN_ENUM(9), + RTL_VLAN_ENUM(10), + RTL_VLAN_ENUM(11), + RTL_VLAN_ENUM(12), + RTL_VLAN_ENUM(13), + RTL_VLAN_ENUM(14), + RTL_VLAN_ENUM(15), +#define RTL_PORT_ENUM(id) \ + RTL_REG_PORT##id##_PVID, \ + RTL_REG_PORT##id##_NULL_VID_REPLACE, \ + RTL_REG_PORT##id##_NON_PVID_DISCARD, \ + RTL_REG_PORT##id##_VID_INSERT, \ + RTL_REG_PORT##id##_TAG_INSERT, \ + RTL_REG_PORT##id##_LINK, \ + RTL_REG_PORT##id##_SPEED, \ + RTL_REG_PORT##id##_NWAY, \ + RTL_REG_PORT##id##_NRESTART, \ + RTL_REG_PORT##id##_DUPLEX, \ + RTL_REG_PORT##id##_RXEN, \ + RTL_REG_PORT##id##_TXEN + RTL_PORT_ENUM(0), + RTL_PORT_ENUM(1), + RTL_PORT_ENUM(2), + RTL_PORT_ENUM(3), + RTL_PORT_ENUM(4), + RTL_PORT_ENUM(5), +}; + +static const struct rtl_reg rtl_regs[] = { + [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 }, + [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 }, + [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 }, + + /* CPU port number */ + [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 }, + /* Enable CPU port function */ + [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 }, + /* Enable CPU port tag insertion */ + [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 }, + /* Enable CPU port tag removal */ + [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 }, + /* Enable CPU port tag checking */ + [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 }, + [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 }, + [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 }, + [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 }, + + [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 }, + [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 }, + + [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 }, + [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 }, + [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 }, + [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 }, + +#define RTL_VLAN_REGS(id, phy, page, regofs) \ + [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \ + [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 } + RTL_VLAN_REGS( 0, 0, 0, 0), + RTL_VLAN_REGS( 1, 1, 0, 0), + RTL_VLAN_REGS( 2, 2, 0, 0), + RTL_VLAN_REGS( 3, 3, 0, 0), + RTL_VLAN_REGS( 4, 4, 0, 0), + RTL_VLAN_REGS( 5, 0, 1, 2), + RTL_VLAN_REGS( 6, 1, 1, 2), + RTL_VLAN_REGS( 7, 2, 1, 2), + RTL_VLAN_REGS( 8, 3, 1, 2), + RTL_VLAN_REGS( 9, 4, 1, 2), + RTL_VLAN_REGS(10, 0, 1, 4), + RTL_VLAN_REGS(11, 1, 1, 4), + RTL_VLAN_REGS(12, 2, 1, 4), + RTL_VLAN_REGS(13, 3, 1, 4), + RTL_VLAN_REGS(14, 4, 1, 4), + RTL_VLAN_REGS(15, 0, 1, 6), + +#define REG_PORT_SETTING(port, phy) \ + [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \ + [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \ + [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \ + [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \ + [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \ + [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \ + [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 } + + REG_PORT_SETTING(0, 0), + REG_PORT_SETTING(1, 1), + REG_PORT_SETTING(2, 2), + REG_PORT_SETTING(3, 3), + REG_PORT_SETTING(4, 4), + REG_PORT_SETTING(5, 6), + +#define REG_PORT_PVID(phy, page, regofs) \ + { page, phy, 24 + regofs, 4, 12, 0 } + [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0), + [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0), + [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0), + [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0), + [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0), + [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2), +}; + + +static inline void +rtl_set_page(struct rtl_priv *priv, unsigned int page) +{ + struct mii_bus *bus = priv->bus; + u16 pgsel; + + if (priv->fixup) + return; + + if (priv->page == page) + return; + + BUG_ON(page > RTL8306_NUM_PAGES); + pgsel = bus->read(bus, 0, RTL8306_REG_PAGE); + pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI); + if (page & (1 << 0)) + pgsel |= RTL8306_REG_PAGE_LO; + if (!(page & (1 << 1))) /* bit is inverted */ + pgsel |= RTL8306_REG_PAGE_HI; + bus->write(bus, 0, RTL8306_REG_PAGE, pgsel); +} + +static inline int +rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + bus->write(bus, phy, reg, val); + bus->read(bus, phy, reg); /* flush */ + return 0; +} + +static inline int +rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + return bus->read(bus, phy, reg); +} + +static inline u16 +rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + u16 r; + + rtl_set_page(priv, page); + r = bus->read(bus, phy, reg); + r &= ~mask; + r |= val; + bus->write(bus, phy, reg, r); + return bus->read(bus, phy, reg); /* flush */ +} + + +static inline int +rtl_get(struct switch_dev *dev, enum rtl_regidx s) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 val; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + if (r->bits == 0) /* unimplemented */ + return 0; + + val = rtl_r16(dev, r->page, r->phy, r->reg); + + if (r->shift > 0) + val >>= r->shift; + + if (r->inverted) + val = ~val; + + val &= (1 << r->bits) - 1; + + return val; +} + +static int +rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 mask = 0xffff; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + + if (r->bits == 0) /* unimplemented */ + return 0; + + if (r->shift > 0) + val <<= r->shift; + + if (r->inverted) + val = ~val; + + if (r->bits != 16) { + mask = (1 << r->bits) - 1; + mask <<= r->shift; + } + val &= mask; + return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val); +} + +static void +rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED)); + regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); +} + +static void +rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway); + rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed); + rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex); +} + +static void +rtl_port_set_enable(struct switch_dev *dev, int port, int enabled) +{ + rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled); + rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled); + + if ((port >= 5) || !enabled) + return; + + /* restart autonegotiation if enabled */ + rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1); +} + +static int +rtl_hw_apply(struct switch_dev *dev) +{ + int i; + int trunk_en, trunk_psel; + struct rtl_phyregs port5; + + rtl_phy_save(dev, 5, &port5); + + /* disable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 0); + } + + /* save trunking status */ + trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK); + trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL); + + /* trunk port 3 and 4 + * XXX: Big WTF, but RealTek seems to do it */ + rtl_set(dev, RTL_REG_EN_TRUNK, 1); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1); + + /* execute the software reset */ + rtl_set(dev, RTL_REG_RESET, 1); + + /* wait for the reset to complete, + * but don't wait for too long */ + for (i = 0; i < 10; i++) { + if (rtl_get(dev, RTL_REG_RESET) == 0) + break; + + msleep(1); + } + + /* enable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 1); + } + + /* restore trunking settings */ + rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel); + rtl_phy_restore(dev, 5, &port5); + + rtl_set(dev, RTL_REG_CPU_LINKUP, 1); + + return 0; +} + +static void +rtl_hw_init(struct switch_dev *dev) +{ + struct rtl_priv *priv = to_rtl(dev); + int cpu_mask = 1 << dev->cpu_port; + int i; + + rtl_set(dev, RTL_REG_VLAN_ENABLE, 0); + rtl_set(dev, RTL_REG_VLAN_FILTER, 0); + rtl_set(dev, RTL_REG_EN_TRUNK, 0); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0); + + /* initialize cpu port settings */ + if (priv->do_cpu) { + rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port); + rtl_set(dev, RTL_REG_EN_CPUPORT, 1); + } else { + rtl_set(dev, RTL_REG_CPUPORT, 7); + rtl_set(dev, RTL_REG_EN_CPUPORT, 0); + } + rtl_set(dev, RTL_REG_EN_TAG_OUT, 0); + rtl_set(dev, RTL_REG_EN_TAG_IN, 0); + rtl_set(dev, RTL_REG_EN_TAG_CLR, 0); + + /* reset all vlans */ + for (i = 0; i < RTL8306_NUM_VLANS; i++) { + rtl_set(dev, RTL_VLAN_REG(i, VID), i); + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0); + } + + /* default to port isolation */ + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + unsigned long mask; + + if ((1 << i) == cpu_mask) + mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */ + else + mask = cpu_mask | (1 << i); + + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask); + rtl_set(dev, RTL_PORT_REG(i, PVID), i); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3); + } + rtl_hw_apply(dev); +} + +#ifdef DEBUG +static int +rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + priv->do_cpu = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + val->value.i = priv->do_cpu; + return 0; +} + +static int +rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + dev->cpu_port = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = dev->cpu_port; + return 0; +} +#endif + +static int +rtl_reset(struct switch_dev *dev) +{ + rtl_hw_init(dev); + return 0; +} + +static int +rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + struct rtl_phyregs port; + + if (attr->id >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + if ((attr->max > 0) && (val->value.i > attr->max)) + return -EINVAL; + + /* access to phy register 22 on port 4/5 + * needs phy status save/restore */ + if ((val->port_vlan > 3) && + (rtl_regs[idx].reg == 22) && + (rtl_regs[idx].page == 0)) { + + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, idx, val->value.i); + rtl_phy_restore(dev, val->port_vlan, &port); + } else { + rtl_set(dev, idx, val->value.i); + } + + return 0; +} + +static int +rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + + if (idx >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + val->value.i = rtl_get(dev, idx); + return 0; +} + +static int +rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link) +{ + if (port >= RTL8306_NUM_PORTS) + return -EINVAL; + + /* in case the link changes from down to up, the register is only updated on read */ + link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); + if (!link->link) + link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); + + if (!link->link) + return 0; + + link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); + link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + + if (rtl_get(dev, RTL_PORT_REG(port, SPEED))) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int i, mask; + + mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + struct switch_port *port; + + if (!(mask & (1 << i))) + continue; + + port = &val->value.ports[val->len]; + port->id = i; + if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port) + port->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct rtl_phyregs port; + int en = val->value.i; + int i; + + rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu); + rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en); + if (en) + rtl_set(dev, RTL_REG_VLAN_FILTER, en); + + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (i > 3) + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1)); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3)); + if (i > 3) + rtl_phy_restore(dev, val->port_vlan, &port); + } + rtl_set(dev, RTL_REG_VLAN_ENABLE, en); + + return 0; +} + +static int +rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE); + return 0; +} + +static int +rtl_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int mask = 0; + unsigned int oldmask; + int i; + + for(i = 0; i < val->len; i++) + { + struct switch_port *port = &val->value.ports[i]; + bool tagged = false; + + mask |= (1 << port->id); + + if (port->id == dev->cpu_port) + continue; + + if ((i == dev->cpu_port) || + (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + tagged = true; + + /* fix up PVIDs for added ports */ + if (!tagged) + rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan); + + rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1)); + } + + oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask); + + /* fix up PVIDs for removed ports, default to last vlan */ + oldmask &= ~mask; + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (!(oldmask & (1 << i))) + continue; + + if (i == dev->cpu_port) + continue; + + if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan) + rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1); + } + + return 0; +} + +static struct switch_attr rtl_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .max = 1, + .set = rtl_set_vlan, + .get = rtl_get_vlan, + }, + { + RTL_GLOBAL_REGATTR(EN_TRUNK), + .name = "trunk", + .description = "Enable port trunking", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(TRUNK_PORTSEL), + .name = "trunk_sel", + .description = "Select ports for trunking (0: 0,1 - 1: 3,4)", + .max = 1, + }, +#ifdef DEBUG + { + RTL_GLOBAL_REGATTR(VLAN_FILTER), + .name = "vlan_filter", + .description = "Filter incoming packets for allowed VLANS", + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "cpuport", + .description = "CPU Port", + .set = rtl_set_cpuport, + .get = rtl_get_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + .type = SWITCH_TYPE_INT, + .name = "use_cpuport", + .description = "CPU Port handling flag", + .set = rtl_set_use_cpuport, + .get = rtl_get_use_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + RTL_GLOBAL_REGATTR(TRAP_CPU), + .name = "trap_cpu", + .description = "VLAN trap to CPU", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE), + .name = "vlan_tag_aware", + .description = "Enable VLAN tag awareness", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY), + .name = "tag_only", + .description = "Only accept tagged packets", + .max = 1, + }, +#endif +}; +static struct switch_attr rtl_port[] = { + { + RTL_PORT_REGATTR(PVID), + .name = "pvid", + .description = "Port VLAN ID", + .max = RTL8306_NUM_VLANS - 1, + }, +#ifdef DEBUG + { + RTL_PORT_REGATTR(NULL_VID_REPLACE), + .name = "null_vid", + .description = "NULL VID gets replaced by port default vid", + .max = 1, + }, + { + RTL_PORT_REGATTR(NON_PVID_DISCARD), + .name = "non_pvid_discard", + .description = "discard packets with VID != PVID", + .max = 1, + }, + { + RTL_PORT_REGATTR(VID_INSERT), + .name = "vid_insert_remove", + .description = "how should the switch insert and remove vids ?", + .max = 3, + }, + { + RTL_PORT_REGATTR(TAG_INSERT), + .name = "tag_insert", + .description = "tag insertion handling", + .max = 3, + }, +#endif +}; + +static struct switch_attr rtl_vlan[] = { + { + RTL_VLAN_REGATTR(VID), + .name = "vid", + .description = "VLAN ID (1-4095)", + .max = 4095, + }, +}; + +static const struct switch_dev_ops rtl8306_ops = { + .attr_global = { + .attr = rtl_globals, + .n_attr = ARRAY_SIZE(rtl_globals), + }, + .attr_port = { + .attr = rtl_port, + .n_attr = ARRAY_SIZE(rtl_port), + }, + .attr_vlan = { + .attr = rtl_vlan, + .n_attr = ARRAY_SIZE(rtl_vlan), + }, + + .get_vlan_ports = rtl_get_ports, + .set_vlan_ports = rtl_set_ports, + .apply_config = rtl_hw_apply, + .reset_switch = rtl_reset, + .get_port_link = rtl_get_port_link, +}; + +static int +rtl8306_config_init(struct phy_device *pdev) +{ + struct net_device *netdev = pdev->attached_dev; + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + struct switch_val val; + unsigned int chipid, chipver, chiptype; + int err; + + /* Only init the switch for the primary PHY */ + if (pdev->mdio.addr != 0) + return 0; + + val.value.i = 1; + priv->dev.cpu_port = RTL8306_PORT_CPU; + priv->dev.ports = RTL8306_NUM_PORTS; + priv->dev.vlans = RTL8306_NUM_VLANS; + priv->dev.ops = &rtl8306_ops; + priv->do_cpu = 0; + priv->page = -1; + priv->bus = pdev->mdio.bus; + + chipid = rtl_get(dev, RTL_REG_CHIPID); + chipver = rtl_get(dev, RTL_REG_CHIPVER); + chiptype = rtl_get(dev, RTL_REG_CHIPTYPE); + switch(chiptype) { + case 0: + case 2: + strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname)); + priv->type = RTL_TYPE_S; + break; + case 1: + strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SD; + break; + case 3: + strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SDM; + break; + default: + strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname)); + break; + } + + dev->name = priv->hwname; + rtl_hw_init(dev); + + printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver); + + err = register_switch(dev, netdev); + if (err < 0) { + kfree(priv); + return err; + } + + return 0; +} + + +static int +rtl8306_fixup(struct phy_device *pdev) +{ + struct rtl_priv priv; + u16 chipid; + + /* Attach to primary LAN port and WAN port */ + if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4) + return 0; + + memset(&priv, 0, sizeof(priv)); + priv.fixup = true; + priv.page = -1; + priv.bus = pdev->mdio.bus; + chipid = rtl_get(&priv.dev, RTL_REG_CHIPID); + if (chipid == 0x5988) + pdev->phy_id = RTL8306_MAGIC; + + return 0; +} + +static int +rtl8306_probe(struct phy_device *pdev) +{ + struct rtl_priv *priv; + + list_for_each_entry(priv, &phydevs, list) { + /* + * share one rtl_priv instance between virtual phy + * devices on the same bus + */ + if (priv->bus == pdev->mdio.bus) + goto found; + } + priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus = pdev->mdio.bus; + +found: + pdev->priv = priv; + return 0; +} + +static void +rtl8306_remove(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + unregister_switch(&priv->dev); + kfree(priv); +} + +static int +rtl8306_config_aneg(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + + /* Only for WAN */ + if (pdev->mdio.addr == 0) + return 0; + + /* Restart autonegotiation */ + rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1); + rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1); + + return 0; +} + +static int +rtl8306_read_status(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + + if (pdev->mdio.addr == 4) { + /* WAN */ + pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10; + pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF; + pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK)); + } else { + /* LAN */ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + } + + /* + * Bypass generic PHY status read, + * it doesn't work with this switch + */ + if (pdev->link) { + pdev->state = PHY_RUNNING; + netif_carrier_on(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } else { + pdev->state = PHY_NOLINK; + netif_carrier_off(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } + + return 0; +} + + +static struct phy_driver rtl8306_driver = { + .name = "Realtek RTL8306S", + .phy_id = RTL8306_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &rtl8306_probe, + .remove = &rtl8306_remove, + .config_init = &rtl8306_config_init, + .config_aneg = &rtl8306_config_aneg, + .read_status = &rtl8306_read_status, +}; + + +static int __init +rtl_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); + return phy_driver_register(&rtl8306_driver, THIS_MODULE); +} + +static void __exit +rtl_exit(void) +{ + phy_driver_unregister(&rtl8306_driver); +} + +module_init(rtl_init); +module_exit(rtl_exit); +MODULE_LICENSE("GPL"); + diff --git a/drivers/net/phy/rtl8366_smi.c b/drivers/net/phy/rtl8366_smi.c new file mode 100644 index 000000000000..89fc04fa64d7 --- /dev/null +++ b/drivers/net/phy/rtl8366_smi.c @@ -0,0 +1,1625 @@ +/* + * Realtek RTL8366 SMI interface driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +#include +#endif + +#include "rtl8366_smi.h" + +#define RTL8366_SMI_ACK_RETRY_COUNT 5 + +#define RTL8366_SMI_HW_STOP_DELAY 25 /* msecs */ +#define RTL8366_SMI_HW_START_DELAY 100 /* msecs */ + +static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) +{ + ndelay(smi->clk_delay); +} + +static void rtl8366_smi_start(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + /* + * Set GPIO pins to output mode, with initial state: + * SCK = 0, SDA = 1 + */ + gpio_direction_output(sck, 0); + gpio_direction_output(sda, 1); + rtl8366_smi_clk_delay(smi); + + /* CLK 1: 0 -> 1, 1 -> 0 */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + + /* CLK 2: */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); +} + +static void rtl8366_smi_stop(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* add a click */ + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* set GPIO pins to input mode */ + gpio_direction_input(sda); + gpio_direction_input(sck); +} + +static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + for (; len > 0; len--) { + rtl8366_smi_clk_delay(smi); + + /* prepare data */ + gpio_set_value(sda, !!(data & ( 1 << (len - 1)))); + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + } +} + +static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + gpio_direction_input(sda); + + for (*data = 0; len > 0; len--) { + u32 u; + + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + u = !!gpio_get_value(sda); + gpio_set_value(sck, 0); + + *data |= (u << (len - 1)); + } + + gpio_direction_output(sda, 0); +} + +static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) +{ + int retry_cnt; + + retry_cnt = 0; + do { + u32 ack; + + rtl8366_smi_read_bits(smi, 1, &ack); + if (ack == 0) + break; + + if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) { + dev_err(smi->parent, "ACK timeout\n"); + return -ETIMEDOUT; + } + } while (1); + + return 0; +} + +static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return rtl8366_smi_wait_for_ack(smi); +} + +static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return 0; +} + +static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x00, 1); + + return 0; +} + +static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x01, 1); + + return 0; +} + +static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + unsigned long flags; + u8 lo = 0; + u8 hi = 0; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send READ command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_read); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* read DATA[7:0] */ + rtl8366_smi_read_byte0(smi, &lo); + /* read DATA[15:8] */ + rtl8366_smi_read_byte1(smi, &hi); + + *data = ((u32) lo) | (((u32) hi) << 8); + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} +/* Read/write via mdiobus */ +#define MDC_MDIO_CTRL0_REG 31 +#define MDC_MDIO_START_REG 29 +#define MDC_MDIO_CTRL1_REG 21 +#define MDC_MDIO_ADDRESS_REG 23 +#define MDC_MDIO_DATA_WRITE_REG 24 +#define MDC_MDIO_DATA_READ_REG 25 + +#define MDC_MDIO_START_OP 0xFFFF +#define MDC_MDIO_ADDR_OP 0x000E +#define MDC_MDIO_READ_OP 0x0001 +#define MDC_MDIO_WRITE_OP 0x0003 +#define MDC_REALTEK_PHY_ADDR 0x0 + +static int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + u32 phy_id = smi->phy_id; + struct mii_bus *mbus = smi->ext_mbus; + + BUG_ON(in_interrupt()); + + mutex_lock(&mbus->mdio_lock); + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address control code to register 31 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address to register 23 */ + mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write read control code to register 21 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); + + /* Write Start command to register 29 */ + mbus->write(smi->ext_mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Read data from register 25 */ + *data = mbus->read(mbus, phy_id, MDC_MDIO_DATA_READ_REG); + + mutex_unlock(&mbus->mdio_lock); + + return 0; +} + +static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + u32 phy_id = smi->phy_id; + struct mii_bus *mbus = smi->ext_mbus; + + BUG_ON(in_interrupt()); + + mutex_lock(&mbus->mdio_lock); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address control code to register 31 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address to register 23 */ + mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write data to register 24 */ + mbus->write(mbus, phy_id, MDC_MDIO_DATA_WRITE_REG, data); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write data control code to register 21 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); + + mutex_unlock(&mbus->mdio_lock); + return 0; +} + +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + if (smi->ext_mbus) + return __rtl8366_mdio_read_reg(smi, addr, data); + else + return __rtl8366_smi_read_reg(smi, addr, data); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); + +static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi, + u32 addr, u32 data, bool ack) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send WRITE command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_write); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* write DATA[7:0] */ + ret = rtl8366_smi_write_byte(smi, data & 0xff); + if (ret) + goto out; + + /* write DATA[15:8] */ + if (ack) + ret = rtl8366_smi_write_byte(smi, data >> 8); + else + ret = rtl8366_smi_write_byte_noack(smi, data >> 8); + if (ret) + goto out; + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} + +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + if (smi->ext_mbus) + return __rtl8366_mdio_write_reg(smi, addr, data); + else + return __rtl8366_smi_write_reg(smi, addr, data, true); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); + +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, false); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack); + +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) +{ + u32 t; + int err; + + err = rtl8366_smi_read_reg(smi, addr, &t); + if (err) + return err; + + err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data); + return err; + +} +EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr); + +static int rtl8366_reset(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) { + smi->hw_reset(smi, true); + msleep(RTL8366_SMI_HW_STOP_DELAY); + smi->hw_reset(smi, false); + msleep(RTL8366_SMI_HW_START_DELAY); + return 0; + } + + return smi->ops->reset_chip(smi); +} + +static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used) +{ + int err; + int i; + + *used = 0; + for (i = 0; i < smi->num_ports; i++) { + int index = 0; + + err = smi->ops->get_mc_index(smi, i, &index); + if (err) + return err; + + if (mc_index == index) { + *used = 1; + break; + } + } + + return 0; +} + +static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, + u32 untag, u32 fid) +{ + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Update the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlan4k.member = member; + vlan4k.untag = untag; + vlan4k.fid = fid; + err = smi->ops->set_vlan_4k(smi, &vlan4k); + if (err) + return err; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + struct rtl8366_vlan_mc vlanmc; + + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + /* update the MC entry */ + vlanmc.member = member; + vlanmc.untag = untag; + vlanmc.fid = fid; + + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + break; + } + } + + return err; +} + +static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int index; + + err = smi->ops->get_mc_index(smi, port, &index); + if (err) + return err; + + err = smi->ops->get_vlan_mc(smi, index, &vlanmc); + if (err) + return err; + + *val = vlanmc.vid; + return 0; +} + +static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, + unsigned vid) +{ + struct rtl8366_vlan_mc vlanmc; + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* We have no MC entry for this VID, try to find an empty one */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vlanmc.vid == 0 && vlanmc.member == 0) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* MC table is full, try to find an unused entry and replace it */ + for (i = 0; i < smi->num_vlan_mc; i++) { + int used; + + err = rtl8366_mc_is_used(smi, i, &used); + if (err) + return err; + + if (!used) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + dev_err(smi->parent, + "all VLAN member configurations are in use\n"); + + return -ENOSPC; +} + +static int rtl8366_smi_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + int err; + + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + + if (!enable) { + smi->vlan4k_enabled = 0; + err = smi->ops->enable_vlan4k(smi, enable); + } + + return err; +} + +static int rtl8366_smi_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + int err; + + if (enable) { + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + } + + err = smi->ops->enable_vlan4k(smi, enable); + if (err) + return err; + + smi->vlan4k_enabled = enable; + return 0; +} + +static int rtl8366_smi_enable_all_ports(struct rtl8366_smi *smi, int enable) +{ + int port; + int err; + + for (port = 0; port < smi->num_ports; port++) { + err = smi->ops->enable_port(smi, port, enable); + if (err) + return err; + } + + return 0; +} + +static int rtl8366_smi_reset_vlan(struct rtl8366_smi *smi) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int i; + + rtl8366_smi_enable_vlan(smi, 0); + rtl8366_smi_enable_vlan4k(smi, 0); + + /* clear VLAN member configurations */ + vlanmc.vid = 0; + vlanmc.priority = 0; + vlanmc.member = 0; + vlanmc.untag = 0; + vlanmc.fid = 0; + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + } + + return 0; +} + +static int rtl8366_init_vlan(struct rtl8366_smi *smi) +{ + int port; + int err; + + err = rtl8366_smi_reset_vlan(smi); + if (err) + return err; + + for (port = 0; port < smi->num_ports; port++) { + u32 mask; + + if (port == smi->cpu_port) + mask = (1 << smi->num_ports) - 1; + else + mask = (1 << port) | (1 << smi->cpu_port); + + err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); + if (err) + return err; + + err = rtl8366_set_pvid(smi, port, (port + 1)); + if (err) + return err; + } + + return rtl8366_smi_enable_vlan(smi, 1); +} + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_debugfs_open); + +static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2s %6s %4s %6s %6s %3s\n", + "id", "vid","prio", "member", "untag", "fid"); + + for (i = 0; i < smi->num_vlan_mc; ++i) { + struct rtl8366_vlan_mc vlanmc; + + smi->ops->get_vlan_mc(smi, i, &vlanmc); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2d %6d %4d 0x%04x 0x%04x %3d\n", + i, vlanmc.vid, vlanmc.priority, + vlanmc.member, vlanmc.untag, vlanmc.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +#define RTL8366_VLAN4K_PAGE_SIZE 64 +#define RTL8366_VLAN4K_NUM_PAGES (4096 / RTL8366_VLAN4K_PAGE_SIZE) + +static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + int offset; + char *buf = smi->buf; + + if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "invalid page: %u\n", smi->dbg_vlan_4k_page); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4s %6s %6s %3s\n", + "vid", "member", "untag", "fid"); + + offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page; + for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) { + struct rtl8366_vlan_4k vlan4k; + + smi->ops->get_vlan_4k(smi, offset + i, &vlan4k); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d 0x%04x 0x%04x %3d\n", + vlan4k.vid, vlan4k.member, + vlan4k.untag, vlan4k.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_pvid(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + char *buf = smi->buf; + int len = 0; + int i; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n", + "port", "pvid"); + + for (i = 0; i < smi->num_ports; i++) { + int pvid; + int err; + + err = rtl8366_get_pvid(smi, i, &pvid); + if (err) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d error\n", i); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d %4d\n", i, pvid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_reg(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + u32 t, reg = smi->dbg_reg; + int err, len = 0; + char *buf = smi->buf; + + memset(buf, '\0', sizeof(smi->buf)); + + err = rtl8366_smi_read_reg(smi, reg, &t); + if (err) { + len += snprintf(buf, sizeof(smi->buf), + "Read failed (reg: 0x%04x)\n", reg); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n", + reg, t); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_write_debugfs_reg(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + unsigned long data; + u32 reg = smi->dbg_reg; + int err; + size_t len; + char *buf = smi->buf; + + len = min(count, sizeof(smi->buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + dev_err(smi->parent, "copy from user failed\n"); + return -EFAULT; + } + + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + + if (kstrtoul(buf, 16, &data)) { + dev_err(smi->parent, "Invalid reg value %s\n", buf); + } else { + err = rtl8366_smi_write_reg(smi, reg, data); + if (err) { + dev_err(smi->parent, + "writing reg 0x%04x val 0x%04lx failed\n", + reg, data); + } + } + + return count; +} + +static ssize_t rtl8366_read_debugfs_mibs(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = file->private_data; + int i, j, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s", + "Counter"); + + for (i = 0; i < smi->num_ports; i++) { + char port_buf[10]; + + snprintf(port_buf, sizeof(port_buf), "Port %d", i); + len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s", + port_buf); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + + for (i = 0; i < smi->num_mib_counters; i++) { + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ", + smi->mib_counters[i].name); + for (j = 0; j < smi->num_ports; j++) { + unsigned long long counter = 0; + + if (!smi->ops->get_mib_counter(smi, i, j, &counter)) + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12llu ", counter); + else + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12s ", "error"); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_rtl8366_regs = { + .read = rtl8366_read_debugfs_reg, + .write = rtl8366_write_debugfs_reg, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_mc = { + .read = rtl8366_read_debugfs_vlan_mc, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_4k = { + .read = rtl8366_read_debugfs_vlan_4k, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_pvid = { + .read = rtl8366_read_debugfs_pvid, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_mibs = { + .read = rtl8366_read_debugfs_mibs, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static void rtl8366_debugfs_init(struct rtl8366_smi *smi) +{ + struct dentry *node; + struct dentry *root; + + if (!smi->debugfs_root) + smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent), + NULL); + + if (!smi->debugfs_root) { + dev_err(smi->parent, "Unable to create debugfs dir\n"); + return; + } + root = smi->debugfs_root; + + node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, + &smi->dbg_reg); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "reg"); + return; + } + + node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi, + &fops_rtl8366_regs); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "val"); + return; + } + + node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi, + &fops_rtl8366_vlan_mc); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_mc"); + return; + } + + node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root, + &smi->dbg_vlan_4k_page); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k_page"); + return; + } + + node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi, + &fops_rtl8366_vlan_4k); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k"); + return; + } + + node = debugfs_create_file("pvid", S_IRUSR, root, smi, + &fops_rtl8366_pvid); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "pvid"); + return; + } + + node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi, + &fops_rtl8366_mibs); + if (!node) + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "mibs"); +} + +static void rtl8366_debugfs_remove(struct rtl8366_smi *smi) +{ + if (smi->debugfs_root) { + debugfs_remove_recursive(smi->debugfs_root); + smi->debugfs_root = NULL; + } +} +#else +static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {} +static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {} +#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */ + +static int rtl8366_smi_mii_init(struct rtl8366_smi *smi) +{ + int ret; + +#ifdef CONFIG_OF + struct device_node *np = NULL; + + np = of_get_child_by_name(smi->parent->of_node, "mdio-bus"); +#endif + + smi->mii_bus = mdiobus_alloc(); + if (smi->mii_bus == NULL) { + ret = -ENOMEM; + goto err; + } + + smi->mii_bus->priv = (void *) smi; + smi->mii_bus->name = dev_name(smi->parent); + smi->mii_bus->read = smi->ops->mii_read; + smi->mii_bus->write = smi->ops->mii_write; + snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(smi->parent)); + smi->mii_bus->parent = smi->parent; + smi->mii_bus->phy_mask = ~(0x1f); + +#ifdef CONFIG_OF + if (np) + ret = of_mdiobus_register(smi->mii_bus, np); + else +#endif + ret = mdiobus_register(smi->mii_bus); + + if (ret) + goto err_free; + + return 0; + + err_free: + mdiobus_free(smi->mii_bus); + err: + return ret; +} + +static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi) +{ + mdiobus_unregister(smi->mii_bus); + mdiobus_free(smi->mii_bus); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + err = rtl8366_reset(smi); + if (err) + return err; + + err = smi->ops->setup(smi); + if (err) + return err; + + err = rtl8366_smi_reset_vlan(smi); + if (err) + return err; + + err = rtl8366_smi_enable_vlan(smi, 1); + if (err) + return err; + + return rtl8366_smi_enable_all_ports(smi, 1); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch); + +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_get_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid); + +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_set_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid); + +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int i, len = 0; + unsigned long long counter = 0; + char *buf = smi->buf; + + if (val->port_vlan >= smi->num_ports) + return -EINVAL; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "Port %d MIB counters\n", + val->port_vlan); + + for (i = 0; i < smi->num_mib_counters; ++i) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%-36s: ", smi->mib_counters[i].name); + if (!smi->ops->get_mib_counter(smi, i, val->port_vlan, + &counter)) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%llu\n", counter); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%s\n", "error"); + } + + val->value.s = buf; + val->len = len; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib); + +int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats, + int txb_id, int rxb_id) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + unsigned long long counter = 0; + int ret; + + if (port >= smi->num_ports) + return -EINVAL; + + ret = smi->ops->get_mib_counter(smi, txb_id, port, &counter); + if (ret) + return ret; + + stats->tx_bytes = counter; + + ret = smi->ops->get_mib_counter(smi, rxb_id, port, &counter); + if (ret) + return ret; + + stats->rx_bytes = counter; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_stats); + +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i; + u32 len = 0; + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char *buf = smi->buf; + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + memset(buf, '\0', sizeof(smi->buf)); + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "VLAN %d: Ports: '", vlan4k.vid); + + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & (1 << i))) + continue; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i, + (vlan4k.untag & (1 << i)) ? "" : "t"); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "', members=%04x, untag=%04x, fid=%u", + vlan4k.member, vlan4k.untag, vlan4k.fid); + + val->value.s = buf; + val->len = len; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info); + +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + struct rtl8366_vlan_4k vlan4k; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + + port = &val->value.ports[0]; + val->len = 0; + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & BIT(i))) + continue; + + port->id = i; + port->flags = (vlan4k.untag & BIT(i)) ? + 0 : BIT(SWITCH_PORT_FLAG_TAGGED); + val->len++; + port++; + } + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports); + +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + u32 member = 0; + u32 untag = 0; + int err; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + port = &val->value.ports[0]; + for (i = 0; i < val->len; i++, port++) { + int pvid = 0; + member |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) + untag |= BIT(port->id); + + /* + * To ensure that we have a valid MC entry for this VLAN, + * initialize the port VLAN ID here. + */ + err = rtl8366_get_pvid(smi, port->id, &pvid); + if (err < 0) + return err; + if (pvid == 0) { + err = rtl8366_set_pvid(smi, port->id, val->port_vlan); + if (err < 0) + return err; + } + } + + return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports); + +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + val->value.i = vlan4k.fid; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid); + +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + if (val->value.i < 0 || val->value.i > attr->max) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + return rtl8366_set_vlan(smi, val->port_vlan, + vlan4k.member, + vlan4k.untag, + val->value.i); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid); + +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + val->value.i = smi->vlan_enabled; + else + val->value.i = smi->vlan4k_enabled; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable); + +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + err = rtl8366_smi_enable_vlan(smi, val->value.i); + else + err = rtl8366_smi_enable_vlan4k(smi, val->value.i); + + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable); + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent) +{ + struct rtl8366_smi *smi; + + BUG_ON(!parent); + + smi = kzalloc(sizeof(*smi), GFP_KERNEL); + if (!smi) { + dev_err(parent, "no memory for private data\n"); + return NULL; + } + + smi->parent = parent; + return smi; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_alloc); + +static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name) +{ + int err; + + if (!smi->ext_mbus) { + err = gpio_request(smi->gpio_sda, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sda, err); + goto err_out; + } + + err = gpio_request(smi->gpio_sck, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sck, err); + goto err_free_sda; + } + } + + spin_lock_init(&smi->lock); + + /* start the switch */ + if (smi->hw_reset) { + smi->hw_reset(smi, false); + msleep(RTL8366_SMI_HW_START_DELAY); + } + + return 0; + + err_free_sda: + gpio_free(smi->gpio_sda); + err_out: + return err; +} + +static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) + smi->hw_reset(smi, true); + + if (!smi->ext_mbus) { + gpio_free(smi->gpio_sck); + gpio_free(smi->gpio_sda); + } +} + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata) +{ + static struct rtl8366_smi smi; + enum rtl8366_type type = RTL8366_TYPE_UNKNOWN; + u32 reg = 0; + + memset(&smi, 0, sizeof(smi)); + smi.gpio_sda = pdata->gpio_sda; + smi.gpio_sck = pdata->gpio_sck; + smi.clk_delay = 10; + smi.cmd_read = 0xa9; + smi.cmd_write = 0xa8; + + if (__rtl8366_smi_init(&smi, "rtl8366")) + goto out; + + if (rtl8366_smi_read_reg(&smi, 0x5c, ®)) + goto cleanup; + + switch(reg) { + case 0x6027: + printk("Found an RTL8366S switch\n"); + type = RTL8366_TYPE_S; + break; + case 0x5937: + printk("Found an RTL8366RB switch\n"); + type = RTL8366_TYPE_RB; + break; + default: + printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg); + break; + } + +cleanup: + __rtl8366_smi_cleanup(&smi); +out: + return type; +} + +int rtl8366_smi_init(struct rtl8366_smi *smi) +{ + int err; + + if (!smi->ops) + return -EINVAL; + + err = __rtl8366_smi_init(smi, dev_name(smi->parent)); + if (err) + goto err_out; + + if (!smi->ext_mbus) + dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", + smi->gpio_sda, smi->gpio_sck); + else + dev_info(smi->parent, "using MDIO bus '%s'\n", smi->ext_mbus->name); + + err = smi->ops->detect(smi); + if (err) { + dev_err(smi->parent, "chip detection failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_reset(smi); + if (err) + goto err_free_sck; + + err = smi->ops->setup(smi); + if (err) { + dev_err(smi->parent, "chip setup failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_init_vlan(smi); + if (err) { + dev_err(smi->parent, "VLAN initialization failed, err=%d\n", + err); + goto err_free_sck; + } + + err = rtl8366_smi_enable_all_ports(smi, 1); + if (err) + goto err_free_sck; + + err = rtl8366_smi_mii_init(smi); + if (err) + goto err_free_sck; + + rtl8366_debugfs_init(smi); + + return 0; + + err_free_sck: + __rtl8366_smi_cleanup(smi); + err_out: + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_init); + +void rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + rtl8366_debugfs_remove(smi); + rtl8366_smi_mii_cleanup(smi); + __rtl8366_smi_cleanup(smi); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup); + +#ifdef CONFIG_OF +static void rtl8366_smi_reset(struct rtl8366_smi *smi, bool active) +{ + if (active) + reset_control_assert(smi->reset); + else + reset_control_deassert(smi->reset); +} + +static int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0); + int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0); + struct device_node *np = pdev->dev.of_node; + struct device_node *mdio_node; + + mdio_node = of_parse_phandle(np, "mii-bus", 0); + if (!mdio_node) { + dev_err(&pdev->dev, "cannot find mdio node phandle"); + goto try_gpio; + } + + smi->ext_mbus = of_mdio_find_bus(mdio_node); + if (!smi->ext_mbus) { + dev_info(&pdev->dev, + "cannot find mdio bus from bus handle (yet)"); + goto try_gpio; + } + + if (of_property_read_u32(np, "phy-id", &smi->phy_id)) + smi->phy_id = MDC_REALTEK_PHY_ADDR; + + return 0; + +try_gpio: + if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) { + if (!mdio_node) { + dev_err(&pdev->dev, "gpios missing in devictree\n"); + return -EINVAL; + } else { + return -EPROBE_DEFER; + } + } + + smi->gpio_sda = sda; + smi->gpio_sck = sck; + smi->reset = devm_reset_control_get(&pdev->dev, "switch"); + if (!IS_ERR(smi->reset)) + smi->hw_reset = rtl8366_smi_reset; + + return 0; +} +#else +static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + return -ENODEV; +} +#endif + +static int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata = pdev->dev.platform_data; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + return -EINVAL; + } + + smi->gpio_sda = pdata->gpio_sda; + smi->gpio_sck = pdata->gpio_sck; + smi->hw_reset = pdata->hw_reset; + smi->phy_id = MDC_REALTEK_PHY_ADDR; + + return 0; +} + + +struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_alloc(&pdev->dev); + if (!smi) + return NULL; + + if (pdev->dev.of_node) + err = rtl8366_smi_probe_of(pdev, smi); + else + err = rtl8366_smi_probe_plat(pdev, smi); + + if (err) + goto free_smi; + + return smi; + +free_smi: + kfree(smi); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_probe); + +MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/rtl8366_smi.h b/drivers/net/phy/rtl8366_smi.h new file mode 100644 index 000000000000..2608240bb083 --- /dev/null +++ b/drivers/net/phy/rtl8366_smi.h @@ -0,0 +1,171 @@ +/* + * Realtek RTL8366 SMI interface driver defines + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _RTL8366_SMI_H +#define _RTL8366_SMI_H + +#include +#include +#include +#include + +struct rtl8366_smi_ops; +struct rtl8366_vlan_ops; +struct mii_bus; +struct dentry; +struct inode; +struct file; + +typedef enum rtl8367b_chip_e { + RTL8367B_CHIP_UNKNOWN, + /* Family B */ + RTL8367B_CHIP_RTL8367RB, + RTL8367B_CHIP_RTL8367R_VB, /* chip with exception in extif assignment */ +/* Family C */ + RTL8367B_CHIP_RTL8367RB_VB, + RTL8367B_CHIP_RTL8367S, +/* Family D */ + RTL8367B_CHIP_RTL8367S_VB /* chip with exception in extif assignment */ +} rtl8367b_chip_t; + +struct rtl8366_mib_counter { + unsigned base; + unsigned offset; + unsigned length; + const char *name; +}; + +struct rtl8366_smi { + struct device *parent; + unsigned int gpio_sda; + unsigned int gpio_sck; + void (*hw_reset)(struct rtl8366_smi *smi, bool active); + unsigned int clk_delay; /* ns */ + u8 cmd_read; + u8 cmd_write; + spinlock_t lock; + struct mii_bus *mii_bus; + int mii_irq[PHY_MAX_ADDR]; + struct switch_dev sw_dev; + + unsigned int cpu_port; + unsigned int num_ports; + unsigned int num_vlan_mc; + unsigned int num_mib_counters; + struct rtl8366_mib_counter *mib_counters; + + struct rtl8366_smi_ops *ops; + + int vlan_enabled; + int vlan4k_enabled; + + char buf[4096]; + + struct reset_control *reset; + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS + struct dentry *debugfs_root; + u16 dbg_reg; + u8 dbg_vlan_4k_page; +#endif + u32 phy_id; + rtl8367b_chip_t rtl8367b_chip; + struct mii_bus *ext_mbus; + struct rtl8366_vlan_mc *emu_vlanmc; +}; + +struct rtl8366_vlan_mc { + u16 vid; + u16 untag; + u16 member; + u8 fid; + u8 priority; +}; + +struct rtl8366_vlan_4k { + u16 vid; + u16 untag; + u16 member; + u8 fid; +}; + +struct rtl8366_smi_ops { + int (*detect)(struct rtl8366_smi *smi); + int (*reset_chip)(struct rtl8366_smi *smi); + int (*setup)(struct rtl8366_smi *smi); + + int (*mii_read)(struct mii_bus *bus, int addr, int reg); + int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val); + + int (*get_vlan_mc)(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc); + int (*set_vlan_mc)(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc); + int (*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k); + int (*set_vlan_4k)(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k); + int (*get_mc_index)(struct rtl8366_smi *smi, int port, int *val); + int (*set_mc_index)(struct rtl8366_smi *smi, int port, int index); + int (*get_mib_counter)(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val); + int (*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan); + int (*enable_vlan)(struct rtl8366_smi *smi, int enable); + int (*enable_vlan4k)(struct rtl8366_smi *smi, int enable); + int (*enable_port)(struct rtl8366_smi *smi, int port, int enable); +}; + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent); +int rtl8366_smi_init(struct rtl8366_smi *smi); +void rtl8366_smi_cleanup(struct rtl8366_smi *smi); +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file); +#endif + +static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) +{ + return container_of(sw, struct rtl8366_smi, sw_dev); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev); +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val); +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val); +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats, + int txb_id, int rxb_id); + +struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev); + +#endif /* _RTL8366_SMI_H */ diff --git a/drivers/net/phy/rtl8366rb.c b/drivers/net/phy/rtl8366rb.c new file mode 100644 index 000000000000..7057b252526d --- /dev/null +++ b/drivers/net/phy/rtl8366rb.c @@ -0,0 +1,1529 @@ +/* + * Platform driver for the Realtek RTL8366RB ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366RB_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" +#define RTL8366RB_DRIVER_VER "0.2.4" + +#define RTL8366RB_PHY_NO_MAX 4 +#define RTL8366RB_PHY_PAGE_MAX 7 +#define RTL8366RB_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366RB_SGCR 0x0000 +#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366RB_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) +#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) +#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) +#define RTL8366RB_SGCR_MAX_LENGTH_9216 RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_EN_VLAN BIT(13) +#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) + +/* Port Enable Control register */ +#define RTL8366RB_PECR 0x0001 + +/* Port Mirror Control Register */ +#define RTL8366RB_PMCR 0x0007 +#define RTL8366RB_PMCR_SOURCE_PORT(_x) (_x) +#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f +#define RTL8366RB_PMCR_MONITOR_PORT(_x) ((_x) << 4) +#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 +#define RTL8366RB_PMCR_MIRROR_RX BIT(8) +#define RTL8366RB_PMCR_MIRROR_TX BIT(9) +#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) +#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) + +/* Switch Security Control registers */ +#define RTL8366RB_SSCR0 0x0002 +#define RTL8366RB_SSCR1 0x0003 +#define RTL8366RB_SSCR2 0x0004 +#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366RB_RESET_CTRL_REG 0x0100 +#define RTL8366RB_CHIP_CTRL_RESET_HW 1 +#define RTL8366RB_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A +#define RTL8366RB_CHIP_VERSION_MASK 0xf +#define RTL8366RB_CHIP_ID_REG 0x0509 +#define RTL8366RB_CHIP_ID_8366 0x5937 + +/* PHY registers control */ +#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 +#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 + +#define RTL8366RB_PHY_CTRL_READ 1 +#define RTL8366RB_PHY_CTRL_WRITE 0 + +#define RTL8366RB_PHY_REG_MASK 0x1f +#define RTL8366RB_PHY_PAGE_OFFSET 5 +#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) +#define RTL8366RB_PHY_NO_OFFSET 9 +#define RTL8366RB_PHY_NO_MASK (0x1f << 9) + +#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + +/* LED control registers */ +#define RTL8366RB_LED_BLINKRATE_REG 0x0430 +#define RTL8366RB_LED_BLINKRATE_BIT 0 +#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366RB_LED_CTRL_REG 0x0431 +#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 +#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 + +#define RTL8366RB_MIB_COUNT 33 +#define RTL8366RB_GLOBAL_MIB_COUNT 1 +#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 +#define RTL8366RB_MIB_COUNTER_BASE 0x1000 +#define RTL8366RB_MIB_CTRL_REG 0x13F0 +#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC +#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) +#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) +#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) + +#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 +#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C +#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 + + +#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) + + +#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 +#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366RB_PORT_NUM_CPU 5 +#define RTL8366RB_NUM_PORTS 6 +#define RTL8366RB_NUM_VLANS 16 +#define RTL8366RB_NUM_LEDGROUPS 4 +#define RTL8366RB_NUM_VIDS 4096 +#define RTL8366RB_PRIORITYMAX 7 +#define RTL8366RB_FIDMAX 7 + + +#define RTL8366RB_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366RB_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366RB_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366RB_PORT_4 (1 << 3) /* In userspace port 3 */ +#define RTL8366RB_PORT_5 (1 << 4) /* In userspace port 4 */ + +#define RTL8366RB_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5 | \ + RTL8366RB_PORT_CPU) + +#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5) + +#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4) + +#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU + +#define RTL8366RB_VLAN_VID_MASK 0xfff +#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 +#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 +#define RTL8366RB_VLAN_UNTAG_SHIFT 8 +#define RTL8366RB_VLAN_UNTAG_MASK 0xff +#define RTL8366RB_VLAN_MEMBER_MASK 0xff +#define RTL8366RB_VLAN_FID_MASK 0x7 + + +/* Port ingress bandwidth control */ +#define RTL8366RB_IB_BASE 0x0200 +#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + pnum) +#define RTL8366RB_IB_BDTH_MASK 0x3fff +#define RTL8366RB_IB_PREIFG_OFFSET 14 +#define RTL8366RB_IB_PREIFG_MASK (1 << RTL8366RB_IB_PREIFG_OFFSET) + +/* Port egress bandwidth control */ +#define RTL8366RB_EB_BASE 0x02d1 +#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + pnum) +#define RTL8366RB_EB_BDTH_MASK 0x3fff +#define RTL8366RB_EB_PREIFG_REG 0x02f8 +#define RTL8366RB_EB_PREIFG_OFFSET 9 +#define RTL8366RB_EB_PREIFG_MASK (1 << RTL8366RB_EB_PREIFG_OFFSET) + +#define RTL8366RB_BDTH_SW_MAX 1048512 +#define RTL8366RB_BDTH_UNIT 64 +#define RTL8366RB_BDTH_REG_DEFAULT 16383 + +/* QOS */ +#define RTL8366RB_QOS_BIT 15 +#define RTL8366RB_QOS_MASK (1 << RTL8366RB_QOS_BIT) +/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ +#define RTL8366RB_QOS_DEFAULT_PREIFG 1 + + +#define RTL8366RB_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8366RB_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366rb_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, + RTL8366RB_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366rb_setup(struct rtl8366_smi *smi) +{ + int err; +#ifdef CONFIG_OF + unsigned i; + struct device_node *np; + unsigned num_initvals; + const __be32 *paddr; + + np = smi->parent->of_node; + + paddr = of_get_property(np, "realtek,initvals", &num_initvals); + if (paddr) { + dev_info(smi->parent, "applying initvals from DTS\n"); + + if (num_initvals < (2 * sizeof(*paddr))) + return -EINVAL; + + num_initvals /= sizeof(*paddr); + + for (i = 0; i < num_initvals - 1; i += 2) { + u32 reg = be32_to_cpup(paddr + i); + u32 val = be32_to_cpup(paddr + i + 1); + + REG_WR(smi, reg, val); + } + } +#endif + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK, + RTL8366RB_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT) + return -EINVAL; + + addr = RTL8366RB_MIB_COUNTER_BASE + + RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + + rtl8366rb_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366RB_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366RB_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366RB_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE, + vid & RTL8366RB_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + if (vlan4k->vid >= RTL8366RB_NUM_VIDS || + vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & + RTL8366RB_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + if (index >= RTL8366RB_NUM_VLANS || + vlanmc->vid >= RTL8366RB_NUM_VIDS || + vlanmc->priority > RTL8366RB_PRIORITYMAX || + vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << + RTL8366RB_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366RB_PORT_VLAN_CTRL_MASK; + + return 0; + +} + +static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + RTL8366RB_PORT_VLAN_CTRL_MASK << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366RB_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366RB_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, + (enable) ? RTL8366RB_SGCR_EN_VLAN : 0); +} + +static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, + RTL8366RB_SGCR_EN_VLAN_4KTB, + (enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); +} + +static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_GLOBAL_RESET); +} + +static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG, + RTL8366RB_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366RB_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, portmask); + + return 0; +} + +static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) { + reg = RTL8366RB_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366RB_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 mask, data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + mask = 1 << val->port_vlan ; + if (val->value.i) + data = mask; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data); +} + +static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data); + if (data & (1 << val->port_vlan)) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan), + RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK, + val->value.i | + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET)); + +} + +static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data); + data &= RTL8366RB_IB_BDTH_MASK; + if (data < RTL8366RB_IB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG, + RTL8366RB_EB_PREIFG_MASK, + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET)); + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan), + RTL8366RB_EB_BDTH_MASK, val->value.i ); + +} + +static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data); + data &= RTL8366RB_EB_BDTH_MASK; + if (data < RTL8366RB_EB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_QOS_MASK; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data); +} + +static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data); + if (data & RTL8366RB_QOS_MASK) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_RX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data); +} + +static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_RX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_TX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data); +} + +static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_TX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_ISO; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data); +} + +static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_ISO) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_SPC; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data); +} + +static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_SPC) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK; + + return 0; +} + +static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan)); +} + +static int rtl8366rb_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8366RB_MIB_TXB_ID, RTL8366RB_MIB_RXB_ID)); +} + +static struct switch_attr rtl8366rb_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366rb_sw_set_learning_enable, + .get = rtl8366rb_sw_get_learning_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366rb_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366rb_sw_set_blinkrate, + .get = rtl8366rb_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_qos", + .description = "Enable QOS", + .set = rtl8366rb_sw_set_qos_enable, + .get = rtl8366rb_sw_get_qos_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = rtl8366rb_sw_set_mirror_rx_enable, + .get = rtl8366rb_sw_get_mirror_rx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = rtl8366rb_sw_set_mirror_tx_enable, + .get = rtl8366rb_sw_get_mirror_tx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_monitor_isolation", + .description = "Enable isolation of monitor port (TX packets will be dropped)", + .set = rtl8366rb_sw_set_monitor_isolation_enable, + .get = rtl8366rb_sw_get_monitor_isolation_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_pause_frames", + .description = "Enable mirroring of RX pause frames", + .set = rtl8366rb_sw_set_mirror_pause_frames_enable, + .get = rtl8366rb_sw_get_mirror_pause_frames_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = rtl8366rb_sw_set_mirror_monitor_port, + .get = rtl8366rb_sw_get_mirror_monitor_port, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = rtl8366rb_sw_set_mirror_source_port, + .get = rtl8366rb_sw_get_mirror_source_port, + .max = 5 + }, +}; + +static struct switch_attr rtl8366rb_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366rb_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366rb_sw_set_port_led, + .get = rtl8366rb_sw_get_port_led, + }, { + .type = SWITCH_TYPE_INT, + .name = "disable", + .description = "Get/Set port state (enabled or disabled)", + .max = 1, + .set = rtl8366rb_sw_set_port_disable, + .get = rtl8366rb_sw_get_port_disable, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_in", + .description = "Get/Set port ingress (incoming) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_in, + .get = rtl8366rb_sw_get_port_rate_in, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_out", + .description = "Get/Set port egress (outgoing) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_out, + .get = rtl8366rb_sw_get_port_rate_out, + }, +}; + +static struct switch_attr rtl8366rb_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366RB_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366rb_globals, + .n_attr = ARRAY_SIZE(rtl8366rb_globals), + }, + .attr_port = { + .attr = rtl8366rb_port, + .n_attr = ARRAY_SIZE(rtl8366rb_port), + }, + .attr_vlan = { + .attr = rtl8366rb_vlan, + .n_attr = ARRAY_SIZE(rtl8366rb_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366rb_sw_get_port_link, + .get_port_stats = rtl8366rb_sw_get_port_stats, +}; + +static int rtl8366rb_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366RB"; + dev->cpu_port = RTL8366RB_PORT_NUM_CPU; + dev->ports = RTL8366RB_NUM_PORTS; + dev->vlans = RTL8366RB_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366rb_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366RB_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366rb_smi_ops = { + .detect = rtl8366rb_detect, + .reset_chip = rtl8366rb_reset_chip, + .setup = rtl8366rb_setup, + + .mii_read = rtl8366rb_mii_read, + .mii_write = rtl8366rb_mii_write, + + .get_vlan_mc = rtl8366rb_get_vlan_mc, + .set_vlan_mc = rtl8366rb_set_vlan_mc, + .get_vlan_4k = rtl8366rb_get_vlan_4k, + .set_vlan_4k = rtl8366rb_set_vlan_4k, + .get_mc_index = rtl8366rb_get_mc_index, + .set_mc_index = rtl8366rb_set_mc_index, + .get_mib_counter = rtl8366rb_get_mib_counter, + .is_vlan_valid = rtl8366rb_is_vlan_valid, + .enable_vlan = rtl8366rb_enable_vlan, + .enable_vlan4k = rtl8366rb_enable_vlan4k, + .enable_port = rtl8366rb_enable_port, +}; + +static int rtl8366rb_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366RB_DRIVER_DESC + " version " RTL8366RB_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366rb_smi_ops; + smi->cpu_port = RTL8366RB_PORT_NUM_CPU; + smi->num_ports = RTL8366RB_NUM_PORTS; + smi->num_vlan_mc = RTL8366RB_NUM_VLANS; + smi->mib_counters = rtl8366rb_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366rb_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static void rtl8366rb_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366rb_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366rb_match[] = { + { .compatible = "realtek,rtl8366rb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366rb_match); +#endif + +static struct platform_driver rtl8366rb_driver = { + .driver = { + .name = RTL8366RB_DRIVER_NAME, + .of_match_table = of_match_ptr(rtl8366rb_match), + }, + .probe = rtl8366rb_probe, + .remove_new = rtl8366rb_remove, +}; + +static int __init rtl8366rb_module_init(void) +{ + return platform_driver_register(&rtl8366rb_driver); +} +module_init(rtl8366rb_module_init); + +static void __exit rtl8366rb_module_exit(void) +{ + platform_driver_unregister(&rtl8366rb_driver); +} +module_exit(rtl8366rb_module_exit); + +MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC); +MODULE_VERSION(RTL8366RB_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_AUTHOR("Roman Yeryomin "); +MODULE_AUTHOR("Colin Leitner "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); diff --git a/drivers/net/phy/rtl8366s.c b/drivers/net/phy/rtl8366s.c new file mode 100644 index 000000000000..5458c5048728 --- /dev/null +++ b/drivers/net/phy/rtl8366s.c @@ -0,0 +1,1317 @@ +/* + * Platform driver for the Realtek RTL8366S ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366S_DRIVER_DESC "Realtek RTL8366S ethernet switch driver" +#define RTL8366S_DRIVER_VER "0.2.2" + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366S_SGCR 0x0000 +#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) +#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) +#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) +#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_EN_VLAN BIT(13) + +/* Port Enable Control register */ +#define RTL8366S_PECR 0x0001 + +/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */ +#define RTL8366S_GREEN_ETHERNET_CTRL_REG 0x000a +#define RTL8366S_GREEN_ETHERNET_CTRL_MASK 0x0018 +#define RTL8366S_GREEN_ETHERNET_TX_BIT (1 << 3) +#define RTL8366S_GREEN_ETHERNET_RX_BIT (1 << 4) + +/* Switch Security Control registers */ +#define RTL8366S_SSCR0 0x0002 +#define RTL8366S_SSCR1 0x0003 +#define RTL8366S_SSCR2 0x0004 +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366S_RESET_CTRL_REG 0x0100 +#define RTL8366S_CHIP_CTRL_RESET_HW 1 +#define RTL8366S_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 +#define RTL8366S_CHIP_VERSION_MASK 0xf +#define RTL8366S_CHIP_ID_REG 0x0105 +#define RTL8366S_CHIP_ID_8366 0x8366 + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1f +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0x7 << 5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1f << 9) + +/* Green Ethernet Feature for PHY ports */ +#define RTL8366S_PHY_POWER_SAVING_CTRL_REG 12 +#define RTL8366S_PHY_POWER_SAVING_MASK 0x1000 + +/* LED control registers */ +#define RTL8366S_LED_BLINKRATE_REG 0x0420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366S_LED_CTRL_REG 0x0421 +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 + +#define RTL8366S_MIB_COUNT 33 +#define RTL8366S_GLOBAL_MIB_COUNT 1 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 +#define RTL8366S_MIB_COUNTER_BASE 0x1000 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 +#define RTL8366S_MIB_COUNTER_BASE2 0x1180 +#define RTL8366S_MIB_CTRL_REG 0x11F0 +#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 + +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC + + +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 + +#define RTL8366S_VLAN_TB_CTRL_REG 0x010F + +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) + +#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 + +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366S_PORT_NUM_CPU 5 +#define RTL8366S_NUM_PORTS 6 +#define RTL8366S_NUM_VLANS 16 +#define RTL8366S_NUM_LEDGROUPS 4 +#define RTL8366S_NUM_VIDS 4096 +#define RTL8366S_PRIORITYMAX 7 +#define RTL8366S_FIDMAX 7 + + +#define RTL8366S_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366S_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366S_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366S_PORT_4 (1 << 3) /* In userspace port 3 */ + +#define RTL8366S_PORT_UNKNOWN (1 << 4) /* No known connection */ +#define RTL8366S_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN) + +#define RTL8366S_PORT_ALL_EXTERNAL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4) + +#define RTL8366S_PORT_ALL_INTERNAL (RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_VLAN_VID_MASK 0xfff +#define RTL8366S_VLAN_PRIORITY_SHIFT 12 +#define RTL8366S_VLAN_PRIORITY_MASK 0x7 +#define RTL8366S_VLAN_MEMBER_MASK 0x3f +#define RTL8366S_VLAN_UNTAG_SHIFT 6 +#define RTL8366S_VLAN_UNTAG_MASK 0x3f +#define RTL8366S_VLAN_FID_SHIFT 12 +#define RTL8366S_VLAN_FID_MASK 0x7 + +#define RTL8366S_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8366S_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + + /* + * The following counters are accessible at a different + * base address. + */ + { 1, 0, 2, "Dot1dTpPortInDiscards" }, + { 1, 2, 2, "IfOutUcastPkts" }, + { 1, 4, 2, "IfOutMulticastPkts" }, + { 1, 6, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366s_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, + RTL8366S_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366S_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_set_green_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + u32 phyData; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366s_read_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); + if (err) + return err; + + if (enable) + phyData |= RTL8366S_PHY_POWER_SAVING_MASK; + else + phyData &= ~RTL8366S_PHY_POWER_SAVING_MASK; + + err = rtl8366s_write_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, phyData); + if (err) + return err; + + return 0; +} + +static int rtl8366s_set_green(struct rtl8366_smi *smi, int enable) +{ + int err; + unsigned i; + u32 data = 0; + + if (!enable) { + for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { + rtl8366s_set_green_port(smi, i, 0); + } + } + + if (enable) + data = (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT); + + REG_RMW(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, RTL8366S_GREEN_ETHERNET_CTRL_MASK, data); + + return 0; +} + +static int rtl8366s_setup(struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata; + int err; + unsigned i; +#ifdef CONFIG_OF + struct device_node *np; + unsigned num_initvals; + const __be32 *paddr; +#endif + + pdata = smi->parent->platform_data; + if (pdata && pdata->num_initvals && pdata->initvals) { + dev_info(smi->parent, "applying initvals\n"); + for (i = 0; i < pdata->num_initvals; i++) + REG_WR(smi, pdata->initvals[i].reg, + pdata->initvals[i].val); + } + +#ifdef CONFIG_OF + np = smi->parent->of_node; + + paddr = of_get_property(np, "realtek,initvals", &num_initvals); + if (paddr) { + dev_info(smi->parent, "applying initvals from DTS\n"); + + if (num_initvals < (2 * sizeof(*paddr))) + return -EINVAL; + + num_initvals /= sizeof(*paddr); + + for (i = 0; i < num_initvals - 1; i += 2) { + u32 reg = be32_to_cpup(paddr + i); + u32 val = be32_to_cpup(paddr + i + 1); + + REG_WR(smi, reg, val); + } + } + + if (of_property_read_bool(np, "realtek,green-ethernet-features")) { + dev_info(smi->parent, "activating Green Ethernet features\n"); + + err = rtl8366s_set_green(smi, 1); + if (err) + return err; + + for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { + err = rtl8366s_set_green_port(smi, i, 1); + if (err) + return err; + } + } +#endif + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK, + RTL8366S_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) + return -EINVAL; + + switch (rtl8366s_mib_counters[counter].base) { + case 0: + addr = RTL8366S_MIB_COUNTER_BASE + + RTL8366S_MIB_COUNTER_PORT_OFFSET * port; + break; + + case 1: + addr = RTL8366S_MIB_COUNTER_BASE2 + + RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; + break; + + default: + return -EINVAL; + } + + addr += rtl8366s_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366S_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366S_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366S_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, + vid & RTL8366S_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + if (vlan4k->vid >= RTL8366S_NUM_VIDS || + vlan4k->member > RTL8366S_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) & + RTL8366S_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + if (index >= RTL8366S_NUM_VLANS || + vlanmc->vid >= RTL8366S_NUM_VIDS || + vlanmc->priority > RTL8366S_PRIORITYMAX || + vlanmc->member > RTL8366S_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) << + RTL8366S_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366S_PORT_VLAN_CTRL_MASK; + + return 0; +} + +static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + RTL8366S_PORT_VLAN_CTRL_MASK << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366S_PORT_VLAN_CTRL_MASK) << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN, + (enable) ? RTL8366S_SGCR_EN_VLAN : 0); +} + +static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG, + 1, (enable) ? 1 : 0); +} + +static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366S_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366S_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366s_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); +} + +static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG, + RTL8366S_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366s_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data); + + val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4); + + return 0; +} + +static int rtl8366s_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char length_code; + + switch (val->value.i) { + case 0: + length_code = RTL8366S_SGCR_MAX_LENGTH_1522; + break; + case 1: + length_code = RTL8366S_SGCR_MAX_LENGTH_1536; + break; + case 2: + length_code = RTL8366S_SGCR_MAX_LENGTH_1552; + break; + case 3: + length_code = RTL8366S_SGCR_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, + RTL8366S_SGCR_MAX_LENGTH_MASK, + length_code); +} + +static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366S_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, portmask); + + return 0; +} + +static int rtl8366s_sw_get_green(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + int err; + + err = rtl8366_smi_read_reg(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, &data); + if (err) + return err; + + val->value.i = ((data & (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT)) != 0) ? 1 : 0; + + return 0; +} + +static int rtl8366s_sw_set_green(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366s_set_green(smi, val->value.i); +} + +static int rtl8366s_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366s_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366S_NUM_PORTS || + (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN) + return -EINVAL; + + if (val->port_vlan == RTL8366S_PORT_NUM_CPU) { + reg = RTL8366S_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366S_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366s_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366s_sw_get_green_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + u32 phyData; + + if (val->port_vlan >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366s_read_phy_reg(smi, val->port_vlan, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); + if (err) + return err; + + val->value.i = ((phyData & RTL8366S_PHY_POWER_SAVING_MASK) != 0) ? 1 : 0; + + return 0; +} + +static int rtl8366s_sw_set_green_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366s_set_green_port(smi, val->port_vlan, val->value.i); +} + +static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366S_NUM_PORTS) + return -EINVAL; + + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, + 0, (1 << (val->port_vlan + 3))); +} + +static int rtl8366s_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8366S_MIB_TXB_ID, RTL8366S_MIB_RXB_ID)); +} + +static struct switch_attr rtl8366s_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366s_sw_set_learning_enable, + .get = rtl8366s_sw_get_learning_enable, + .max = 1, + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366s_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366s_sw_set_blinkrate, + .get = rtl8366s_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + " (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))", + .set = rtl8366s_sw_set_max_length, + .get = rtl8366s_sw_get_max_length, + .max = 3, + }, { + .type = SWITCH_TYPE_INT, + .name = "green_mode", + .description = "Get/Set the router green feature", + .set = rtl8366s_sw_set_green, + .get = rtl8366s_sw_get_green, + .max = 1, + }, +}; + +static struct switch_attr rtl8366s_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366s_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366s_sw_set_port_led, + .get = rtl8366s_sw_get_port_led, + }, { + .type = SWITCH_TYPE_INT, + .name = "green_port", + .description = "Get/Set port green feature (0 - 1)", + .max = 1, + .set = rtl8366s_sw_set_green_port, + .get = rtl8366s_sw_get_green_port, + }, +}; + +static struct switch_attr rtl8366s_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366S_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366s_globals, + .n_attr = ARRAY_SIZE(rtl8366s_globals), + }, + .attr_port = { + .attr = rtl8366s_port, + .n_attr = ARRAY_SIZE(rtl8366s_port), + }, + .attr_vlan = { + .attr = rtl8366s_vlan, + .n_attr = ARRAY_SIZE(rtl8366s_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366s_sw_get_port_link, + .get_port_stats = rtl8366s_sw_get_port_stats, +}; + +static int rtl8366s_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366S"; + dev->cpu_port = RTL8366S_PORT_NUM_CPU; + dev->ports = RTL8366S_NUM_PORTS; + dev->vlans = RTL8366S_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366s_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366S_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366s_smi_ops = { + .detect = rtl8366s_detect, + .reset_chip = rtl8366s_reset_chip, + .setup = rtl8366s_setup, + + .mii_read = rtl8366s_mii_read, + .mii_write = rtl8366s_mii_write, + + .get_vlan_mc = rtl8366s_get_vlan_mc, + .set_vlan_mc = rtl8366s_set_vlan_mc, + .get_vlan_4k = rtl8366s_get_vlan_4k, + .set_vlan_4k = rtl8366s_set_vlan_4k, + .get_mc_index = rtl8366s_get_mc_index, + .set_mc_index = rtl8366s_set_mc_index, + .get_mib_counter = rtl8366_get_mib_counter, + .is_vlan_valid = rtl8366s_is_vlan_valid, + .enable_vlan = rtl8366s_enable_vlan, + .enable_vlan4k = rtl8366s_enable_vlan4k, + .enable_port = rtl8366s_enable_port, +}; + +static int rtl8366s_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366S_DRIVER_DESC + " version " RTL8366S_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366s_smi_ops; + smi->cpu_port = RTL8366S_PORT_NUM_CPU; + smi->num_ports = RTL8366S_NUM_PORTS; + smi->num_vlan_mc = RTL8366S_NUM_VLANS; + smi->mib_counters = rtl8366s_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366s_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static void rtl8366s_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366s_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366s_match[] = { + { .compatible = "realtek,rtl8366s" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366s_match); +#endif + +static struct platform_driver rtl8366s_driver = { + .driver = { + .name = RTL8366S_DRIVER_NAME, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8366s_match), +#endif + }, + .probe = rtl8366s_probe, + .remove_new = rtl8366s_remove, +}; + +static int __init rtl8366s_module_init(void) +{ + return platform_driver_register(&rtl8366s_driver); +} +module_init(rtl8366s_module_init); + +static void __exit rtl8366s_module_exit(void) +{ + platform_driver_unregister(&rtl8366s_driver); +} +module_exit(rtl8366s_module_exit); + +MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); +MODULE_VERSION(RTL8366S_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME); diff --git a/drivers/net/phy/rtl8367.c b/drivers/net/phy/rtl8367.c new file mode 100644 index 000000000000..1b996019a614 --- /dev/null +++ b/drivers/net/phy/rtl8367.c @@ -0,0 +1,1859 @@ +/* + * Platform driver for the Realtek RTL8367R/M ethernet switches + * + * Copyright (C) 2011 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367_PHY_ADDR_MAX 8 +#define RTL8367_PHY_REG_MAX 31 + +#define RTL8367_VID_MASK 0xffff +#define RTL8367_FID_MASK 0xfff +#define RTL8367_UNTAG_MASK 0xffff +#define RTL8367_MEMBER_MASK 0xffff + +#define RTL8367_PORT_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367_PORT_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367_PORT_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367_PORT_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367_PORT_CFG_EGRESS_MODE_PRI 2 +#define RTL8367_PORT_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367_TA_CTRL_REG 0x0500 +#define RTL8367_TA_CTRL_STATUS BIT(12) +#define RTL8367_TA_CTRL_METHOD BIT(5) +#define RTL8367_TA_CTRL_CMD_SHIFT 4 +#define RTL8367_TA_CTRL_CMD_READ 0 +#define RTL8367_TA_CTRL_CMD_WRITE 1 +#define RTL8367_TA_CTRL_TABLE_SHIFT 0 +#define RTL8367_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367_TA_CTRL_TABLE_L2 4 +#define RTL8367_TA_CTRL_CVLAN_READ \ + ((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) +#define RTL8367_TA_CTRL_CVLAN_WRITE \ + ((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) + +#define RTL8367_TA_ADDR_REG 0x0501 +#define RTL8367_TA_ADDR_MASK 0x3fff + +#define RTL8367_TA_DATA_REG(_x) (0x0503 + (_x)) +#define RTL8367_TA_VLAN_DATA_SIZE 4 +#define RTL8367_TA_VLAN_VID_MASK RTL8367_VID_MASK +#define RTL8367_TA_VLAN_MEMBER_SHIFT 0 +#define RTL8367_TA_VLAN_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_TA_VLAN_FID_SHIFT 0 +#define RTL8367_TA_VLAN_FID_MASK RTL8367_FID_MASK +#define RTL8367_TA_VLAN_UNTAG1_SHIFT 14 +#define RTL8367_TA_VLAN_UNTAG1_MASK 0x3 +#define RTL8367_TA_VLAN_UNTAG2_SHIFT 0 +#define RTL8367_TA_VLAN_UNTAG2_MASK 0x3fff + +#define RTL8367_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) +#define RTL8367_VLAN_PVID_CTRL_MASK 0x1f +#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) + +#define RTL8367_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) +#define RTL8367_VLAN_MC_DATA_SIZE 4 +#define RTL8367_VLAN_MC_MEMBER_SHIFT 0 +#define RTL8367_VLAN_MC_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_VLAN_MC_FID_SHIFT 0 +#define RTL8367_VLAN_MC_FID_MASK RTL8367_FID_MASK +#define RTL8367_VLAN_MC_EVID_SHIFT 0 +#define RTL8367_VLAN_MC_EVID_MASK RTL8367_VID_MASK + +#define RTL8367_VLAN_CTRL_REG 0x07a8 +#define RTL8367_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367_VLAN_INGRESS_REG 0x07a9 + +#define RTL8367_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) + +#define RTL8367_MIB_COUNTER_REG(_x) (0x1000 + (_x)) + +#define RTL8367_MIB_ADDRESS_REG 0x1004 + +#define RTL8367_MIB_CTRL_REG(_x) (0x1005 + (_x)) +#define RTL8367_MIB_CTRL_GLOBAL_RESET_MASK BIT(11) +#define RTL8367_MIB_CTRL_QM_RESET_MASK BIT(10) +#define RTL8367_MIB_CTRL_PORT_RESET_MASK(_p) BIT(2 + (_p)) +#define RTL8367_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8367_MIB_CTRL_BUSY_MASK BIT(0) + +#define RTL8367_MIB_COUNT 36 +#define RTL8367_MIB_COUNTER_PORT_OFFSET 0x0050 + +#define RTL8367_SWC0_REG 0x1200 +#define RTL8367_SWC0_MAX_LENGTH_SHIFT 13 +#define RTL8367_SWC0_MAX_LENGTH(_x) ((_x) << 13) +#define RTL8367_SWC0_MAX_LENGTH_MASK RTL8367_SWC0_MAX_LENGTH(0x3) +#define RTL8367_SWC0_MAX_LENGTH_1522 RTL8367_SWC0_MAX_LENGTH(0) +#define RTL8367_SWC0_MAX_LENGTH_1536 RTL8367_SWC0_MAX_LENGTH(1) +#define RTL8367_SWC0_MAX_LENGTH_1552 RTL8367_SWC0_MAX_LENGTH(2) +#define RTL8367_SWC0_MAX_LENGTH_16000 RTL8367_SWC0_MAX_LENGTH(3) + +#define RTL8367_CHIP_NUMBER_REG 0x1300 + +#define RTL8367_CHIP_VER_REG 0x1301 +#define RTL8367_CHIP_VER_RLVID_SHIFT 12 +#define RTL8367_CHIP_VER_RLVID_MASK 0xf +#define RTL8367_CHIP_VER_MCID_SHIFT 8 +#define RTL8367_CHIP_VER_MCID_MASK 0xf +#define RTL8367_CHIP_VER_BOID_SHIFT 4 +#define RTL8367_CHIP_VER_BOID_MASK 0xf + +#define RTL8367_CHIP_MODE_REG 0x1302 +#define RTL8367_CHIP_MODE_MASK 0x7 + +#define RTL8367_CHIP_DEBUG0_REG 0x1303 +#define RTL8367_CHIP_DEBUG0_DUMMY0(_x) BIT(8 + (_x)) + +#define RTL8367_CHIP_DEBUG1_REG 0x1304 + +#define RTL8367_DIS_REG 0x1305 +#define RTL8367_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367_DIS_RGMII_MASK 0x7 + +#define RTL8367_EXT_RGMXF_REG(_x) (0x1306 + (_x)) +#define RTL8367_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367_DI_FORCE_REG(_x) (0x1310 + (_x)) +#define RTL8367_DI_FORCE_MODE BIT(12) +#define RTL8367_DI_FORCE_NWAY BIT(7) +#define RTL8367_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367_DI_FORCE_LINK BIT(4) +#define RTL8367_DI_FORCE_DUPLEX BIT(2) +#define RTL8367_DI_FORCE_SPEED_MASK 3 +#define RTL8367_DI_FORCE_SPEED_10 0 +#define RTL8367_DI_FORCE_SPEED_100 1 +#define RTL8367_DI_FORCE_SPEED_1000 2 + +#define RTL8367_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367_CHIP_RESET_REG 0x1322 +#define RTL8367_CHIP_RESET_SW BIT(1) +#define RTL8367_CHIP_RESET_HW BIT(0) + +#define RTL8367_PORT_STATUS_REG(_p) (0x1352 + (_p)) +#define RTL8367_PORT_STATUS_NWAY BIT(7) +#define RTL8367_PORT_STATUS_TXPAUSE BIT(6) +#define RTL8367_PORT_STATUS_RXPAUSE BIT(5) +#define RTL8367_PORT_STATUS_LINK BIT(4) +#define RTL8367_PORT_STATUS_DUPLEX BIT(2) +#define RTL8367_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8367_PORT_STATUS_SPEED_10 0 +#define RTL8367_PORT_STATUS_SPEED_100 1 +#define RTL8367_PORT_STATUS_SPEED_1000 2 + +#define RTL8367_RTL_NO_REG 0x13c0 +#define RTL8367_RTL_NO_8367R 0x3670 +#define RTL8367_RTL_NO_8367M 0x3671 + +#define RTL8367_RTL_VER_REG 0x13c1 +#define RTL8367_RTL_VER_MASK 0xf + +#define RTL8367_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367_LED_SYS_CONFIG_REG 0x1b00 +#define RTL8367_LED_MODE_REG 0x1b02 +#define RTL8367_LED_MODE_RATE_M 0x7 +#define RTL8367_LED_MODE_RATE_S 1 + +#define RTL8367_LED_CONFIG_REG 0x1b03 +#define RTL8367_LED_CONFIG_DATA_S 12 +#define RTL8367_LED_CONFIG_DATA_M 0x3 +#define RTL8367_LED_CONFIG_SEL BIT(14) +#define RTL8367_LED_CONFIG_LED_CFG_M 0xf + +#define RTL8367_PARA_LED_IO_EN1_REG 0x1b24 +#define RTL8367_PARA_LED_IO_EN2_REG 0x1b25 +#define RTL8367_PARA_LED_IO_EN_PMASK 0xff + +#define RTL8367_IA_CTRL_REG 0x1f00 +#define RTL8367_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367_IA_CTRL_RW_READ RTL8367_IA_CTRL_RW(0) +#define RTL8367_IA_CTRL_RW_WRITE RTL8367_IA_CTRL_RW(1) +#define RTL8367_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367_IA_STATUS_REG 0x1f01 +#define RTL8367_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367_IA_ADDRESS_REG 0x1f02 + +#define RTL8367_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367_IA_READ_DATA_REG 0x1f04 + +#define RTL8367_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367_CPU_PORT_NUM 9 +#define RTL8367_NUM_PORTS 10 +#define RTL8367_NUM_VLANS 32 +#define RTL8367_NUM_LEDGROUPS 4 +#define RTL8367_NUM_VIDS 4096 +#define RTL8367_PRIORITYMAX 7 +#define RTL8367_FIDMAX 7 + +#define RTL8367_PORT_0 BIT(0) +#define RTL8367_PORT_1 BIT(1) +#define RTL8367_PORT_2 BIT(2) +#define RTL8367_PORT_3 BIT(3) +#define RTL8367_PORT_4 BIT(4) +#define RTL8367_PORT_5 BIT(5) +#define RTL8367_PORT_6 BIT(6) +#define RTL8367_PORT_7 BIT(7) +#define RTL8367_PORT_E1 BIT(8) /* external port 1 */ +#define RTL8367_PORT_E0 BIT(9) /* external port 0 */ + +#define RTL8367_PORTS_ALL \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 | \ + RTL8367_PORT_E0) + +#define RTL8367_PORTS_ALL_BUT_CPU \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1) + +struct rtl8367_initval { + u16 reg; + u16 val; +}; + +#define RTL8367_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8367_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8367_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 2, "Dot3StatsFCSErrors" }, + { 0, 6, 2, "Dot3StatsSymbolErrors" }, + { 0, 8, 2, "Dot3InPauseFrames" }, + { 0, 10, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 12, 2, "EtherStatsFragments" }, + { 0, 14, 2, "EtherStatsJabbers" }, + { 0, 16, 2, "IfInUcastPkts" }, + { 0, 18, 2, "EtherStatsDropEvents" }, + { 0, 20, 4, "EtherStatsOctets" }, + + { 0, 24, 2, "EtherStatsUnderSizePkts" }, + { 0, 26, 2, "EtherOversizeStats" }, + { 0, 28, 2, "EtherStatsPkts64Octets" }, + { 0, 30, 2, "EtherStatsPkts65to127Octets" }, + { 0, 32, 2, "EtherStatsPkts128to255Octets" }, + { 0, 34, 2, "EtherStatsPkts256to511Octets" }, + { 0, 36, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 38, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 40, 2, "EtherStatsMulticastPkts" }, + { 0, 42, 2, "EtherStatsBroadcastPkts" }, + + { 0, 44, 4, "IfOutOctets" }, + + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, + { 0, 72, 2, "OutOampduPkts" }, + { 0, 74, 2, "InOampduPkts" }, + { 0, 76, 2, "PktgenPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367_initval rtl8367_initvals_0_0[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8}, + {0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277}, + {0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277}, + {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8}, + {0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8}, + {0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b}, + {0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b}, + {0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b}, + {0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b}, + {0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940}, +}; + +static const struct rtl8367_initval rtl8367_initvals_0_1[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0}, + {0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb}, + {0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb}, + {0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0}, + {0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0}, + {0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190}, + {0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190}, + {0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190}, + {0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190}, + {0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_0[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230}, + {0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230}, + {0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4}, + {0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8}, + {0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8}, + {0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8}, + {0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8}, + {0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000}, + {0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, + {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_1[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, + {0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000}, + {0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, + {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, + {0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, + {0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, + {0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, + {0x1B03, 0x0876}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_0[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16}, + {0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244}, + {0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244}, + {0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, + {0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8}, + {0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8}, + {0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8}, + {0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8}, + {0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, + {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00}, + {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, + {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, + {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_1[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000}, + {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, + {0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, + {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, + {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040}, + {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x130c, 0x0050}, +}; + +static int rtl8367_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + int err; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_0_0; + count = ARRAY_SIZE(rtl8367_initvals_0_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_0_1; + count = ARRAY_SIZE(rtl8367_initvals_0_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + err = rtl8367_write_initvals(smi, initvals, count); + if (err) + return err; + + /* TODO: complete this */ + + return 0; +} + +static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_1_0; + count = ARRAY_SIZE(rtl8367_initvals_1_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_1_1; + count = ARRAY_SIZE(rtl8367_initvals_1_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_2_0; + count = ARRAY_SIZE(rtl8367_initvals_2_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_2_1; + count = ARRAY_SIZE(rtl8367_initvals_2_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs(struct rtl8366_smi *smi) +{ + u32 data; + u32 rlvid; + u32 mode; + int err; + + REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL); + + REG_RD(smi, RTL8367_CHIP_VER_REG, &data); + rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) & + RTL8367_CHIP_VER_RLVID_MASK; + + REG_RD(smi, RTL8367_CHIP_MODE_REG, &data); + mode = data & RTL8367_CHIP_MODE_MASK; + + switch (rlvid) { + case 0: + err = rtl8367_init_regs0(smi, mode); + break; + + case 1: + err = rtl8367_write_phy_reg(smi, 0, 31, 5); + if (err) + break; + + err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe); + if (err) + break; + + err = rtl8367_read_phy_reg(smi, 0, 6, &data); + if (err) + break; + + if (data == 0x94eb) { + err = rtl8367_init_regs1(smi, mode); + } else if (data == 0x2104) { + err = rtl8367_init_regs2(smi, mode); + } else { + dev_err(smi->parent, "unknow phy data %04x\n", data); + return -ENODEV; + } + + break; + + default: + dev_err(smi->parent, "unknow rlvid %u\n", rlvid); + err = -ENODEV; + break; + } + + return err; +} + +static int rtl8367_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW); + msleep(RTL8367_RESET_DELAY); + + do { + REG_RD(smi, RTL8367_CHIP_RESET_REG, &data); + if (!(data & RTL8367_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + case RTL8367_EXTIF_MODE_RGMII_33V: + REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367); + REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777); + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), BIT((id + 1) % 2)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG, + RTL8367_CHIP_DEBUG0_DUMMY0(id), + RTL8367_CHIP_DEBUG0_DUMMY0(id)); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), 0); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + REG_RMW(smi, RTL8367_DIS_REG, + RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id), + mode << RTL8367_DIS_RGMII_SHIFT(id)); + + return 0; +} + +static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_DI_FORCE_MODE | + RTL8367_DI_FORCE_NWAY | + RTL8367_DI_FORCE_TXPAUSE | + RTL8367_DI_FORCE_RXPAUSE | + RTL8367_DI_FORCE_LINK | + RTL8367_DI_FORCE_DUPLEX | + RTL8367_DI_FORCE_SPEED_MASK); + + val = pa->speed; + val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0; + val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0; + + REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK | + (RTL8367_EXT_RGMXF_TXDELAY_MASK << + RTL8367_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi, + unsigned int group, u16 port_mask) +{ + u32 reg; + u32 s; + int err; + + port_mask &= RTL8367_PARA_LED_IO_EN_PMASK; + s = (group % 2) * 8; + reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2); + + REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s); + + return 0; +} + +static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi, + unsigned int mode) +{ + u16 mask; + u16 set; + int err; + + mode &= RTL8367_LED_CONFIG_DATA_M; + + mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) | + RTL8367_LED_CONFIG_SEL; + set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL; + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + + return 0; +} + +static int rtl8367_led_group_set_config(struct rtl8366_smi *smi, + unsigned int led, unsigned int cfg) +{ + u16 mask; + u16 set; + int err; + + mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) | + RTL8367_LED_CONFIG_SEL; + set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4); + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + return 0; +} + +static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi) +{ + int err; + + REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472); + return 0; +} + +static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate) +{ + u16 mask; + u16 set; + int err; + + mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S; + set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S; + REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set); + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + unsigned cpu_port; + unsigned id = UINT_MAX; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop || (size != (10 * sizeof(*prop)))) { + dev_err(smi->parent, "%s property is not defined or invalid\n", name); + err = -EINVAL; + goto err_init; + } + + cpu_port = be32_to_cpup(prop++); + switch (cpu_port) { + case RTL8367_CPU_PORT_NUM - 1: + case RTL8367_CPU_PORT_NUM: + id = RTL8367_CPU_PORT_NUM - cpu_port; + if (smi->cpu_port == UINT_MAX) { + dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); + smi->cpu_port = cpu_port; + } + break; + default: + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367_extif_init(smi, id, cfg); + kfree(cfg); + +err_init: + if (id != 0) rtl8367_extif_init(smi, 0, NULL); + if (id != 1) rtl8367_extif_init(smi, 1, NULL); + + return err; +} +#else +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367_extif_init_of(smi, "realtek,extif"); + if (err) + return err; + } else { + err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK, + RTL8367_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367_PORT_CFG_REG(i), + RTL8367_PORT_CFG_EGRESS_MODE_MASK << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT, + RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT); + + /* setup LEDs */ + err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL); + if (err) + return err; + + err = rtl8367_led_group_set_mode(smi, 0); + if (err) + return err; + + err = rtl8367_led_op_select_parallel(smi); + if (err) + return err; + + err = rtl8367_led_blinkrate_set(smi, 1); + if (err) + return err; + + err = rtl8367_led_group_set_config(smi, 0, 2); + if (err) + return err; + + return 0; +} + +static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT) + return -EINVAL; + + mib = &rtl8367_mib_counters[counter]; + addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data); + + if (data & RTL8367_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367_MIB_CTRL_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) & + RTL8367_TA_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) & + RTL8367_TA_VLAN_FID_MASK; + vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) & + RTL8367_TA_VLAN_UNTAG1_MASK; + vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) & + RTL8367_TA_VLAN_UNTAG2_MASK) << 2; + + return 0; +} + +static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + if (vlan4k->vid >= RTL8367_NUM_VIDS || + vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8367_UNTAG_MASK || + vlan4k->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) << + RTL8367_TA_VLAN_MEMBER_SHIFT; + data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) << + RTL8367_TA_VLAN_FID_SHIFT; + data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) << + RTL8367_TA_VLAN_UNTAG1_SHIFT; + data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) << + RTL8367_TA_VLAN_UNTAG2_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]); + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, + vlan4k->vid & RTL8367_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) & + RTL8367_VLAN_MC_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) & + RTL8367_VLAN_MC_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) & + RTL8367_VLAN_MC_EVID_MASK; + + return 0; +} + +static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + if (index >= RTL8367_NUM_VLANS || + vlanmc->vid >= RTL8367_NUM_VIDS || + vlanmc->priority > RTL8367_PRIORITYMAX || + vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK || + vlanmc->untag > RTL8367_UNTAG_MASK || + vlanmc->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) << + RTL8367_VLAN_MC_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) << + RTL8367_VLAN_MC_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) << + RTL8367_VLAN_MC_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367_VLAN_PVID_CTRL_MASK; + + return 0; +} + +static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port), + RTL8367_VLAN_PVID_CTRL_MASK << + RTL8367_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367_VLAN_PVID_CTRL_MASK) << + RTL8367_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG, + RTL8367_VLAN_CTRL_ENABLE, + (enable) ? RTL8367_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port), + (enable) ? RTL8367_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0, + RTL8367_MIB_CTRL_GLOBAL_RESET_MASK); +} + +static int rtl8367_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY); + + speed = (data & RTL8367_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data); + val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >> + RTL8367_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG, + RTL8367_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0, + RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8)); +} + +static int rtl8367_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8367_MIB_TXB_ID, RTL8367_MIB_RXB_ID)); +} + +static struct switch_attr rtl8367_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367_sw_set_max_length, + .get = rtl8367_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8367_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8367_sw_ops = { + .attr_global = { + .attr = rtl8367_globals, + .n_attr = ARRAY_SIZE(rtl8367_globals), + }, + .attr_port = { + .attr = rtl8367_port, + .n_attr = ARRAY_SIZE(rtl8367_port), + }, + .attr_vlan = { + .attr = rtl8367_vlan, + .n_attr = ARRAY_SIZE(rtl8367_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367_sw_get_port_link, + .get_port_stats = rtl8367_sw_get_port_stats, +}; + +static int rtl8367_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367"; + dev->cpu_port = smi->cpu_port; + dev->ports = RTL8367_NUM_PORTS; + dev->vlans = RTL8367_NUM_VIDS; + dev->ops = &rtl8367_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367_detect(struct rtl8366_smi *smi) +{ + u32 rtl_no = 0; + u32 rtl_ver = 0; + char *chip_name; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no); + if (ret) { + dev_err(smi->parent, "unable to read chip number\n"); + return ret; + } + + switch (rtl_no) { + case RTL8367_RTL_NO_8367R: + chip_name = "8367R"; + break; + case RTL8367_RTL_NO_8367M: + chip_name = "8367M"; + break; + default: + dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%s ver. %u chip found\n", + chip_name, rtl_ver & RTL8367_RTL_VER_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367_smi_ops = { + .detect = rtl8367_detect, + .reset_chip = rtl8367_reset_chip, + .setup = rtl8367_setup, + + .mii_read = rtl8367_mii_read, + .mii_write = rtl8367_mii_write, + + .get_vlan_mc = rtl8367_get_vlan_mc, + .set_vlan_mc = rtl8367_set_vlan_mc, + .get_vlan_4k = rtl8367_get_vlan_4k, + .set_vlan_4k = rtl8367_set_vlan_4k, + .get_mc_index = rtl8367_get_mc_index, + .set_mc_index = rtl8367_set_mc_index, + .get_mib_counter = rtl8367_get_mib_counter, + .is_vlan_valid = rtl8367_is_vlan_valid, + .enable_vlan = rtl8367_enable_vlan, + .enable_vlan4k = rtl8367_enable_vlan4k, + .enable_port = rtl8367_enable_port, +}; + +static int rtl8367_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367_smi_ops; + smi->cpu_port = UINT_MAX; /* not defined yet */ + smi->num_ports = RTL8367_NUM_PORTS; + smi->num_vlan_mc = RTL8367_NUM_VLANS; + smi->mib_counters = rtl8367_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static void rtl8367_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } +} + +static void rtl8367_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367_match[] = { + { .compatible = "realtek,rtl8367" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367_match); +#endif + +static struct platform_driver rtl8367_driver = { + .driver = { + .name = RTL8367_DRIVER_NAME, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367_match), +#endif + }, + .probe = rtl8367_probe, + .remove_new = rtl8367_remove, + .shutdown = rtl8367_shutdown, +}; + +static int __init rtl8367_module_init(void) +{ + return platform_driver_register(&rtl8367_driver); +} +module_init(rtl8367_module_init); + +static void __exit rtl8367_module_exit(void) +{ + platform_driver_unregister(&rtl8367_driver); +} +module_exit(rtl8367_module_exit); + +MODULE_DESCRIPTION("Realtek RTL8367 ethernet switch driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME); diff --git a/drivers/net/phy/rtl8367b.c b/drivers/net/phy/rtl8367b.c new file mode 100644 index 000000000000..5adcf00f0cac --- /dev/null +++ b/drivers/net/phy/rtl8367b.c @@ -0,0 +1,1649 @@ +/* + * Platform driver for Realtek RTL8367B family chips, i.e. RTL8367RB and RTL8367R-VB + * extended with support for RTL8367C family chips, i.e. RTL8367RB-VB and RTL8367S + * extended with support for RTL8367D family chips, i.e. RTL8367S-VB + * + * Copyright (C) 2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367B_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367B_PHY_ADDR_MAX 8 +#define RTL8367B_PHY_REG_MAX 31 + +#define RTL8367B_VID_MASK 0x3fff +#define RTL8367B_FID_MASK 0xf +#define RTL8367B_UNTAG_MASK 0xff +#define RTL8367B_MEMBER_MASK 0xff + +#define RTL8367B_PORT_MISC_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI 2 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367B_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367B_TA_CTRL_REG 0x0500 /*GOOD*/ +#define RTL8367B_TA_CTRL_SPA_SHIFT 8 +#define RTL8367B_TA_CTRL_SPA_MASK 0x7 +#define RTL8367B_TA_CTRL_METHOD BIT(4)/*GOOD*/ +#define RTL8367B_TA_CTRL_CMD_SHIFT 3 +#define RTL8367B_TA_CTRL_CMD_READ 0 +#define RTL8367B_TA_CTRL_CMD_WRITE 1 +#define RTL8367B_TA_CTRL_TABLE_SHIFT 0 /*GOOD*/ +#define RTL8367B_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367B_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367B_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367B_TA_CTRL_TABLE_L2 4 +#define RTL8367B_TA_CTRL_CVLAN_READ \ + ((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) +#define RTL8367B_TA_CTRL_CVLAN_WRITE \ + ((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) + +#define RTL8367B_TA_ADDR_REG 0x0501/*GOOD*/ +#define RTL8367B_TA_ADDR_MASK 0x3fff/*GOOD*/ + +#define RTL8367B_TA_LUT_REG 0x0502/*GOOD*/ + +#define RTL8367B_TA_WRDATA_REG(_x) (0x0510 + (_x))/*GOOD*/ +#define RTL8367B_TA_VLAN_NUM_WORDS 2 +#define RTL8367B_TA_VLAN_VID_MASK RTL8367B_VID_MASK +#define RTL8367B_TA_VLAN0_MEMBER_SHIFT 0 +#define RTL8367B_TA_VLAN0_MEMBER_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN0_UNTAG_SHIFT 8 +#define RTL8367B_TA_VLAN0_UNTAG_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN1_FID_SHIFT 0 +#define RTL8367B_TA_VLAN1_FID_MASK RTL8367B_FID_MASK + +#define RTL8367B_TA_RDDATA_REG(_x) (0x0520 + (_x))/*GOOD*/ + +#define RTL8367B_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_MASK 0x1f /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) /*GOOD*/ + +#define RTL8367B_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) /*GOOD*/ +#define RTL8367B_VLAN_MC_NUM_WORDS 4 /*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_MASK RTL8367B_MEMBER_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_MASK RTL8367B_FID_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_MASK RTL8367B_VID_MASK/*GOOD*/ + +#define RTL8367B_VLAN_CTRL_REG 0x07a8 /*GOOD*/ +#define RTL8367B_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367B_VLAN_INGRESS_REG 0x07a9 /*GOOD*/ + +#define RTL8367B_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) /*GOOD*/ + +#define RTL8367B_MIB_COUNTER_REG(_x) (0x1000 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_COUNTER_PORT_OFFSET 0x007c /*GOOD*/ + +#define RTL8367B_MIB_ADDRESS_REG 0x1004 /*GOOD*/ + +#define RTL8367B_MIB_CTRL0_REG(_x) (0x1005 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK BIT(11) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_QM_RESET_MASK BIT(10) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_RESET_MASK BIT(1) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_BUSY_MASK BIT(0) /*GOOD*/ + +#define RTL8367B_SWC0_REG 0x1200/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_SHIFT 13/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH(_x) ((_x) << 13) /*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_MASK RTL8367B_SWC0_MAX_LENGTH(0x3) +#define RTL8367B_SWC0_MAX_LENGTH_1522 RTL8367B_SWC0_MAX_LENGTH(0) +#define RTL8367B_SWC0_MAX_LENGTH_1536 RTL8367B_SWC0_MAX_LENGTH(1) +#define RTL8367B_SWC0_MAX_LENGTH_1552 RTL8367B_SWC0_MAX_LENGTH(2) +#define RTL8367B_SWC0_MAX_LENGTH_16000 RTL8367B_SWC0_MAX_LENGTH(3) + +#define RTL8367B_CHIP_NUMBER_REG 0x1300/*GOOD*/ + +#define RTL8367B_CHIP_VER_REG 0x1301/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_SHIFT 12/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_SHIFT 8/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_SHIFT 4/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_SHIFT 0/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_MASK 0x1/*GOOD*/ + +#define RTL8367B_CHIP_MODE_REG 0x1302 +#define RTL8367B_CHIP_MODE_MASK 0x7 + +#define RTL8367B_CHIP_DEBUG0_REG 0x1303 +#define RTL8367B_DEBUG0_SEL33(_x) BIT(8 + (_x)) +#define RTL8367B_DEBUG0_DRI_OTHER BIT(7) +#define RTL8367B_DEBUG0_DRI_RG(_x) BIT(5 + (_x)) +#define RTL8367B_DEBUG0_DRI(_x) BIT(3 + (_x)) +#define RTL8367B_DEBUG0_SLR_OTHER BIT(2) +#define RTL8367B_DEBUG0_SLR(_x) BIT(_x) + +#define RTL8367B_CHIP_DEBUG1_REG 0x1304 +#define RTL8367B_DEBUG1_DN_MASK(_x) \ + GENMASK(6 + (_x)*8, 4 + (_x)*8) +#define RTL8367B_DEBUG1_DN_SHIFT(_x) (4 + (_x) * 8) +#define RTL8367B_DEBUG1_DP_MASK(_x) \ + GENMASK(2 + (_x) * 8, (_x) * 8) +#define RTL8367B_DEBUG1_DP_SHIFT(_x) ((_x) * 8) + +#define RTL8367B_CHIP_DEBUG2_REG 0x13e2 +#define RTL8367B_DEBUG2_RG2_DN_MASK GENMASK(8, 6) +#define RTL8367B_DEBUG2_RG2_DN_SHIFT 6 +#define RTL8367B_DEBUG2_RG2_DP_MASK GENMASK(5, 3) +#define RTL8367B_DEBUG2_RG2_DP_SHIFT 3 +#define RTL8367B_DEBUG2_DRI_EXT2_RG BIT(2) +#define RTL8367B_DEBUG2_DRI_EXT2 BIT(1) +#define RTL8367B_DEBUG2_SLR_EXT2 BIT(0) + +#define RTL8367B_DIS_REG 0x1305 +#define RTL8367B_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367B_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367B_DIS_RGMII_MASK 0x7 + +#define RTL8367B_DIS2_REG 0x13c3 +#define RTL8367B_DIS2_SKIP_MII_RXER_SHIFT 4 +#define RTL8367B_DIS2_SKIP_MII_RXER 0x10 +#define RTL8367B_DIS2_RGMII_SHIFT 0 +#define RTL8367B_DIS2_RGMII_MASK 0xf + +#define RTL8367B_EXT_RGMXF_REG(_x) \ + ((_x) == 2 ? 0x13c5 : 0x1306 + (_x)) +#define RTL8367B_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367B_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367B_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367B_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367B_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367B_DI_FORCE_REG(_x) \ + ((_x) == 2 ? 0x13c4 : 0x1310 + (_x)) +#define RTL8367B_DI_FORCE_MODE BIT(12) +#define RTL8367B_DI_FORCE_NWAY BIT(7) +#define RTL8367B_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367B_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367B_DI_FORCE_LINK BIT(4) +#define RTL8367B_DI_FORCE_DUPLEX BIT(2) +#define RTL8367B_DI_FORCE_SPEED_MASK 3 +#define RTL8367B_DI_FORCE_SPEED_10 0 +#define RTL8367B_DI_FORCE_SPEED_100 1 +#define RTL8367B_DI_FORCE_SPEED_1000 2 + +#define RTL8367B_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367B_CHIP_RESET_REG 0x1322 /*GOOD*/ +#define RTL8367B_CHIP_RESET_SW BIT(1) /*GOOD*/ +#define RTL8367B_CHIP_RESET_HW BIT(0) /*GOOD*/ + +#define RTL8367B_PORT_STATUS_REG(_p) (0x1352 + (_p)) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_1000_SPI BIT(11) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_100_SPI BIT(10)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY_FAULT BIT(9)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK_MASTER BIT(8)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY BIT(7)/*GOOD*/ +#define RTL8367B_PORT_STATUS_TXPAUSE BIT(6)/*GOOD*/ +#define RTL8367B_PORT_STATUS_RXPAUSE BIT(5)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK BIT(4)/*GOOD*/ +#define RTL8367B_PORT_STATUS_DUPLEX BIT(2)/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_MASK 0x0003/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_10 0/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_100 1/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_1000 2/*GOOD*/ + +#define RTL8367B_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367B_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367B_IA_CTRL_REG 0x1f00 +#define RTL8367B_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367B_IA_CTRL_RW_READ RTL8367B_IA_CTRL_RW(0) +#define RTL8367B_IA_CTRL_RW_WRITE RTL8367B_IA_CTRL_RW(1) +#define RTL8367B_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367B_IA_STATUS_REG 0x1f01 +#define RTL8367B_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367B_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367B_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367B_IA_ADDRESS_REG 0x1f02 +#define RTL8367B_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367B_IA_READ_DATA_REG 0x1f04 + +#define RTL8367B_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367B_NUM_MIB_COUNTERS 58 + +#define RTL8367B_CPU_PORT_NUM 5 +#define RTL8367B_NUM_PORTS 8 +#define RTL8367B_NUM_VLANS 32 +#define RTL8367B_NUM_VIDS 4096 +#define RTL8367B_PRIORITYMAX 7 +#define RTL8367B_FIDMAX 7 + +#define RTL8367B_PORT_0 BIT(0) +#define RTL8367B_PORT_1 BIT(1) +#define RTL8367B_PORT_2 BIT(2) +#define RTL8367B_PORT_3 BIT(3) +#define RTL8367B_PORT_4 BIT(4) +#define RTL8367B_PORT_E0 BIT(5) /* External port 0 */ +#define RTL8367B_PORT_E1 BIT(6) /* External port 1 */ +#define RTL8367B_PORT_E2 BIT(7) /* External port 2 */ + +#define RTL8367B_PORTS_ALL \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \ + RTL8367B_PORT_E1 | RTL8367B_PORT_E2) + +#define RTL8367B_PORTS_ALL_BUT_CPU \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 | \ + RTL8367B_PORT_E2) + +struct rtl8367b_initval { + u16 reg; + u16 val; +}; + +#define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */ + +#define RTL8367D_PORT_STATUS_REG(_p) (0x12d0 + (_p)) + +#define RTL8367D_PORT_STATUS_SPEED1_MASK 0x3000 +#define RTL8367D_PORT_STATUS_SPEED1_SHIFT 10 /*12-2*/ + +#define RTL8367D_REG_MAC0_FORCE_SELECT 0x12c0 +#define RTL8367D_REG_MAC0_FORCE_SELECT_EN 0x12c8 + +#define RTL8367D_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p)) +#define RTL8367D_VLAN_PVID_CTRL_MASK 0xfff +#define RTL8367D_VLAN_PVID_CTRL_SHIFT(_p) 0 + +#define RTL8367D_FIDMAX 3 +#define RTL8367D_FID_MASK 3 +#define RTL8367D_TA_VLAN1_FID_SHIFT 0 +#define RTL8367D_TA_VLAN1_FID_MASK RTL8367D_FID_MASK + +#define RTL8367D_VID_MASK 0xfff +#define RTL8367D_TA_VLAN_VID_MASK RTL8367D_VID_MASK + +#define RTL8367D_REG_EXT_TXC_DLY 0x13f9 +#define RTL8367D_EXT1_RGMII_TX_DLY_MASK 0x38 + +#define RTL8367D_REG_TOP_CON0 0x1d70 +#define RTL8367D_MAC7_SEL_EXT1_MASK 0x2000 +#define RTL8367D_MAC4_SEL_EXT1_MASK 0x1000 + +#define RTL8367D_REG_SDS1_MISC0 0x1d78 +#define RTL8367D_SDS1_MODE_MASK 0x1f +#define RTL8367D_PORT_SDS_MODE_DISABLE 0x1f + +static struct rtl8366_mib_counter +rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { + {0, 0, 4, "ifInOctets" }, + {0, 4, 2, "dot3StatsFCSErrors" }, + {0, 6, 2, "dot3StatsSymbolErrors" }, + {0, 8, 2, "dot3InPauseFrames" }, + {0, 10, 2, "dot3ControlInUnknownOpcodes" }, + {0, 12, 2, "etherStatsFragments" }, + {0, 14, 2, "etherStatsJabbers" }, + {0, 16, 2, "ifInUcastPkts" }, + {0, 18, 2, "etherStatsDropEvents" }, + {0, 20, 2, "ifInMulticastPkts" }, + {0, 22, 2, "ifInBroadcastPkts" }, + {0, 24, 2, "inMldChecksumError" }, + {0, 26, 2, "inIgmpChecksumError" }, + {0, 28, 2, "inMldSpecificQuery" }, + {0, 30, 2, "inMldGeneralQuery" }, + {0, 32, 2, "inIgmpSpecificQuery" }, + {0, 34, 2, "inIgmpGeneralQuery" }, + {0, 36, 2, "inMldLeaves" }, + {0, 38, 2, "inIgmpLeaves" }, + + {0, 40, 4, "etherStatsOctets" }, + {0, 44, 2, "etherStatsUnderSizePkts" }, + {0, 46, 2, "etherOversizeStats" }, + {0, 48, 2, "etherStatsPkts64Octets" }, + {0, 50, 2, "etherStatsPkts65to127Octets" }, + {0, 52, 2, "etherStatsPkts128to255Octets" }, + {0, 54, 2, "etherStatsPkts256to511Octets" }, + {0, 56, 2, "etherStatsPkts512to1023Octets" }, + {0, 58, 2, "etherStatsPkts1024to1518Octets" }, + + {0, 60, 4, "ifOutOctets" }, + {0, 64, 2, "dot3StatsSingleCollisionFrames" }, + {0, 66, 2, "dot3StatMultipleCollisionFrames" }, + {0, 68, 2, "dot3sDeferredTransmissions" }, + {0, 70, 2, "dot3StatsLateCollisions" }, + {0, 72, 2, "etherStatsCollisions" }, + {0, 74, 2, "dot3StatsExcessiveCollisions" }, + {0, 76, 2, "dot3OutPauseFrames" }, + {0, 78, 2, "ifOutDiscards" }, + {0, 80, 2, "dot1dTpPortInDiscards" }, + {0, 82, 2, "ifOutUcastPkts" }, + {0, 84, 2, "ifOutMulticastPkts" }, + {0, 86, 2, "ifOutBroadcastPkts" }, + {0, 88, 2, "outOampduPkts" }, + {0, 90, 2, "inOampduPkts" }, + {0, 92, 2, "inIgmpJoinsSuccess" }, + {0, 94, 2, "inIgmpJoinsFail" }, + {0, 96, 2, "inMldJoinsSuccess" }, + {0, 98, 2, "inMldJoinsFail" }, + {0, 100, 2, "inReportSuppressionDrop" }, + {0, 102, 2, "inLeaveSuppressionDrop" }, + {0, 104, 2, "outIgmpReports" }, + {0, 106, 2, "outIgmpLeaves" }, + {0, 108, 2, "outIgmpGeneralQuery" }, + {0, 110, 2, "outIgmpSpecificQuery" }, + {0, 112, 2, "outMldReports" }, + {0, 114, 2, "outMldLeaves" }, + {0, 116, 2, "outMldGeneralQuery" }, + {0, 118, 2, "outMldSpecificQuery" }, + {0, 120, 2, "inKnownMulticastPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367b_initval rtl8367b_initvals[] = { + {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA}, + {0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078}, + {0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00}, + {0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000}, + {0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000}, + {0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000}, + {0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B}, + {0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00}, + {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100}, + {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280}, + {0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, + {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, + {0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0}, + {0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1}, + {0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE}, + {0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1}, + {0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD}, + {0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7}, + {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20}, + {0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, + {0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A}, + {0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E}, + {0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5}, + {0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2}, + {0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC}, + {0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE}, + {0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, + {0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685}, + {0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85}, + {0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC}, + {0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140}, + {0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E}, + {0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22}, + {0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340}, + {0x133E, 0x000E}, {0x133F, 0x0010}, +}; + +static const struct rtl8367b_initval rtl8367c_initvals[] = { + {0x13c2, 0x0000}, {0x0018, 0x0f00}, {0x0038, 0x0f00}, {0x0058, 0x0f00}, + {0x0078, 0x0f00}, {0x0098, 0x0f00}, {0x1d15, 0x0a69}, {0x2000, 0x1340}, + {0x2020, 0x1340}, {0x2040, 0x1340}, {0x2060, 0x1340}, {0x2080, 0x1340}, + {0x13eb, 0x15bb}, {0x1303, 0x06d6}, {0x1304, 0x0700}, {0x13E2, 0x003F}, + {0x13F9, 0x0090}, {0x121e, 0x03CA}, {0x1233, 0x0352}, {0x1237, 0x00a0}, + {0x123a, 0x0030}, {0x1239, 0x0084}, {0x0301, 0x1000}, {0x1349, 0x001F}, + {0x18e0, 0x4004}, {0x122b, 0x641c}, {0x1305, 0xc000}, {0x1200, 0x7fcb}, + {0x0884, 0x0003}, {0x06eb, 0x0001}, {0x00cf, 0xffff}, {0x00d0, 0x0007}, + {0x00ce, 0x48b0}, {0x00ce, 0x48b0}, {0x0398, 0xffff}, {0x0399, 0x0007}, + {0x0300, 0x0001}, {0x03fa, 0x0007}, {0x08c8, 0x00c0}, {0x0a30, 0x020e}, + {0x0800, 0x0000}, {0x0802, 0x0000}, {0x09da, 0x0017}, {0x1d32, 0x0002}, +}; + +static int rtl8367b_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367b_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367b_init_regs(struct rtl8366_smi *smi) +{ + const struct rtl8367b_initval *initvals; + int count; + + switch (smi->rtl8367b_chip) { + case RTL8367B_CHIP_RTL8367RB: + case RTL8367B_CHIP_RTL8367R_VB: + initvals = rtl8367b_initvals; + count = ARRAY_SIZE(rtl8367b_initvals); + break; + case RTL8367B_CHIP_RTL8367RB_VB: + case RTL8367B_CHIP_RTL8367S: + case RTL8367B_CHIP_RTL8367S_VB: + initvals = rtl8367c_initvals; + count = ARRAY_SIZE(rtl8367c_initvals); + if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (smi->emu_vlanmc == NULL)) { + smi->emu_vlanmc = kzalloc(sizeof(struct rtl8366_vlan_mc) * smi->num_vlan_mc, GFP_KERNEL); + dev_info(smi->parent, "alloc vlan mc emulator"); + } + break; + default: + return -ENODEV; + } + + return rtl8367b_write_initvals(smi, initvals, count); +} + +static int rtl8367b_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW); + msleep(RTL8367B_RESET_DELAY); + + do { + REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data); + if (!(data & RTL8367B_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + u32 data; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_SEL33(id), + RTL8367B_DEBUG0_SEL33(id)); + if (id <= 1) { + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_DRI(id) | + RTL8367B_DEBUG0_DRI_RG(id) | + RTL8367B_DEBUG0_SLR(id), + RTL8367B_DEBUG0_DRI_RG(id) | + RTL8367B_DEBUG0_SLR(id)); + REG_RMW(smi, RTL8367B_CHIP_DEBUG1_REG, + RTL8367B_DEBUG1_DN_MASK(id) | + RTL8367B_DEBUG1_DP_MASK(id), + (7 << RTL8367B_DEBUG1_DN_SHIFT(id)) | + (7 << RTL8367B_DEBUG1_DP_SHIFT(id))); + if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (id == 1)) { + REG_RMW(smi, RTL8367D_REG_EXT_TXC_DLY, RTL8367D_EXT1_RGMII_TX_DLY_MASK, 0); + /* Configure RGMII/MII mux to port 7 if UTP_PORT4 is not RGMII mode */ + REG_RD(smi, RTL8367D_REG_TOP_CON0, &data); + data &= RTL8367D_MAC4_SEL_EXT1_MASK; + if (data == 0) + REG_RMW(smi, RTL8367D_REG_TOP_CON0, RTL8367D_MAC7_SEL_EXT1_MASK, RTL8367D_MAC7_SEL_EXT1_MASK); + REG_RMW(smi, RTL8367D_REG_SDS1_MISC0, RTL8367D_SDS1_MODE_MASK, RTL8367D_PORT_SDS_MODE_DISABLE); + } + } else { + REG_RMW(smi, RTL8367B_CHIP_DEBUG2_REG, + RTL8367B_DEBUG2_DRI_EXT2 | + RTL8367B_DEBUG2_DRI_EXT2_RG | + RTL8367B_DEBUG2_SLR_EXT2 | + RTL8367B_DEBUG2_RG2_DN_MASK | + RTL8367B_DEBUG2_RG2_DP_MASK, + RTL8367B_DEBUG2_DRI_EXT2_RG | + RTL8367B_DEBUG2_SLR_EXT2 | + (7 << RTL8367B_DEBUG2_RG2_DN_SHIFT) | + (7 << RTL8367B_DEBUG2_RG2_DP_SHIFT)); + } + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), BIT(id)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_SEL33(id), + RTL8367B_DEBUG0_SEL33(id)); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), 0); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + if (id <= 1) + REG_RMW(smi, RTL8367B_DIS_REG, + RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id), + mode << RTL8367B_DIS_RGMII_SHIFT(id)); + else + REG_RMW(smi, RTL8367B_DIS2_REG, + RTL8367B_DIS2_RGMII_MASK << RTL8367B_DIS2_RGMII_SHIFT, + mode << RTL8367B_DIS2_RGMII_SHIFT); + + return 0; +} + +static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + val = pa->speed & RTL8367B_DI_FORCE_SPEED_MASK; + val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + val |= (pa->speed << RTL8367D_PORT_STATUS_SPEED1_SHIFT) & RTL8367D_PORT_STATUS_SPEED1_MASK; + if (smi->cpu_port != UINT_MAX) { + REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT + smi->cpu_port, val); + REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT_EN + smi->cpu_port, pa->force_mode ? 0xffff : 0x0000); + } + } else { + val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; + mask = (RTL8367B_DI_FORCE_MODE | + RTL8367B_DI_FORCE_NWAY | + RTL8367B_DI_FORCE_TXPAUSE | + RTL8367B_DI_FORCE_RXPAUSE | + RTL8367B_DI_FORCE_LINK | + RTL8367B_DI_FORCE_DUPLEX | + RTL8367B_DI_FORCE_SPEED_MASK); + + REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); + } + + return 0; +} + +static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK | + (RTL8367B_EXT_RGMXF_TXDELAY_MASK << + RTL8367B_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367b_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367b_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + unsigned cpu_port; + unsigned id = UINT_MAX; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop || (size != (10 * sizeof(*prop)))) { + dev_err(smi->parent, "%s property is not defined or invalid\n", name); + err = -EINVAL; + goto err_init; + } + + cpu_port = be32_to_cpup(prop++); + switch (cpu_port) { + case RTL8367B_CPU_PORT_NUM: + case RTL8367B_CPU_PORT_NUM + 1: + case RTL8367B_CPU_PORT_NUM + 2: + if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367R_VB) { /* for the RTL8367R-VB chip, cpu_port 5 corresponds to extif1 */ + if (cpu_port == RTL8367B_CPU_PORT_NUM) + id = 1; + else { + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + } else if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) { /* for the RTL8367S-VB chip, cpu_port 7 corresponds to extif1, cpu_port 6 corresponds to extif0 */ + if (cpu_port != RTL8367B_CPU_PORT_NUM) { + id = cpu_port - RTL8367B_CPU_PORT_NUM - 1; + } else { + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + } else { + id = cpu_port - RTL8367B_CPU_PORT_NUM; + } + if (smi->cpu_port == UINT_MAX) { + dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); + smi->cpu_port = cpu_port; + } + break; + default: + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367b_extif_init(smi, id, cfg); + kfree(cfg); + +err_init: + if (id != 0) rtl8367b_extif_init(smi, 0, NULL); + if (id != 1) rtl8367b_extif_init(smi, 1, NULL); + if (id != 2) rtl8367b_extif_init(smi, 2, NULL); + + return err; +} +#else +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367b_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367b_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367b_extif_init_of(smi, "realtek,extif"); + if (err) + return err; + } else { + err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK, + RTL8367B_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367B_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367B_PORT_MISC_CFG_REG(i), + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT, + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT); + + return 0; +} + +static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367B_NUM_PORTS || + counter >= RTL8367B_NUM_MIB_COUNTERS) + return -EINVAL; + + mib = &rtl8367b_mib_counters[counter]; + addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data); + + if (data & RTL8367B_MIB_CTRL0_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367B_MIB_CTRL0_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367B_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) & + RTL8367B_TA_VLAN0_MEMBER_MASK; + vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) & + RTL8367B_TA_VLAN0_UNTAG_MASK; + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + vlan4k->fid = (data[1] >> RTL8367D_TA_VLAN1_FID_SHIFT) & + RTL8367D_TA_VLAN1_FID_MASK; + else + vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & + RTL8367B_TA_VLAN1_FID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + if (vlan4k->vid >= RTL8367B_NUM_VIDS || + vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK || + vlan4k->untag > RTL8367B_UNTAG_MASK || + vlan4k->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) + return -EINVAL; + + memset(data, 0, sizeof(data)); + + data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) << + RTL8367B_TA_VLAN0_MEMBER_SHIFT; + data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) << + RTL8367B_TA_VLAN0_UNTAG_SHIFT; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + data[1] = ((vlan4k->fid & RTL8367D_TA_VLAN1_FID_MASK) << + RTL8367D_TA_VLAN1_FID_SHIFT) | 12; /* ivl_svl - BIT(3), svlan_chek_ivl_svl - BIT(2) */ + else + data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << + RTL8367B_TA_VLAN1_FID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]); + + /* write VID */ + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367D_TA_VLAN_VID_MASK); + else + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + if (smi->emu_vlanmc) { /* use vlan mc emulation */ + vlanmc->vid = smi->emu_vlanmc[index].vid; + vlanmc->member = smi->emu_vlanmc[index].member; + vlanmc->fid = smi->emu_vlanmc[index].fid; + vlanmc->untag = smi->emu_vlanmc[index].untag; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) & + RTL8367B_VLAN_MC0_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) & + RTL8367B_VLAN_MC1_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) & + RTL8367B_VLAN_MC3_EVID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + if (index >= RTL8367B_NUM_VLANS || + vlanmc->vid >= RTL8367B_NUM_VIDS || + vlanmc->priority > RTL8367B_PRIORITYMAX || + vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK || + vlanmc->untag > RTL8367B_UNTAG_MASK || + vlanmc->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) + return -EINVAL; + + if (smi->emu_vlanmc) { /* use vlanmc emulation */ + smi->emu_vlanmc[index].vid = vlanmc->vid; + smi->emu_vlanmc[index].member = vlanmc->member; + smi->emu_vlanmc[index].fid = vlanmc->fid; + smi->emu_vlanmc[index].untag = vlanmc->untag; + return 0; + } + + data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) << + RTL8367B_VLAN_MC0_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) << + RTL8367B_VLAN_MC1_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) << + RTL8367B_VLAN_MC3_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + int i; + struct rtl8366_vlan_mc vlanmc; + + err = rtl8366_smi_read_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), &data); + + if (err) { + dev_err(smi->parent, "read pvid register 0x%04x fail", RTL8367D_VLAN_PVID_CTRL_REG(port)); + return err; + } + + data &= RTL8367D_VLAN_PVID_CTRL_MASK; + for (i = 0; i < smi->num_vlan_mc; i++) { + err = rtl8367b_get_vlan_mc(smi, i, &vlanmc); + + if (err) { + dev_err(smi->parent, "get vlan mc index %d fail", i); + return err; + } + + if (data == vlanmc.vid) break; + } + + if (i < smi->num_vlan_mc) { + *val = i; + } else { + dev_err(smi->parent, "vlan mc index for pvid %d not found", data); + return -EINVAL; + } + } else { + REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367B_VLAN_PVID_CTRL_MASK; + } + + return 0; +} + +static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + int pvid, err; + struct rtl8366_vlan_mc vlanmc; + + err = rtl8367b_get_vlan_mc(smi, index, &vlanmc); + + if (err) { + dev_err(smi->parent, "get vlan mc index %d fail", index); + return err; + } + + pvid = vlanmc.vid & RTL8367D_VLAN_PVID_CTRL_MASK; + err = rtl8366_smi_write_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), pvid); + + if (err) { + dev_err(smi->parent, "set port %d pvid %d fail", port, pvid); + return err; + } + + return 0; + } else + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), + RTL8367B_VLAN_PVID_CTRL_MASK << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367B_VLAN_PVID_CTRL_MASK) << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG, + RTL8367B_VLAN_CTRL_ENABLE, + (enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367B_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367B_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port), + (enable) ? RTL8367B_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367b_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0, + RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK); +} + +static int rtl8367b_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + rtl8366_smi_read_reg(smi, RTL8367D_PORT_STATUS_REG(port), &data); + else + rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367B_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY); + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK) | ((data & RTL8367D_PORT_STATUS_SPEED1_MASK) >> RTL8367D_PORT_STATUS_SPEED1_SHIFT); + else + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); + switch (speed) { + case RTL8367B_PORT_STATUS_SPEED_10: + link->speed = SWITCH_PORT_SPEED_10; + break; + case RTL8367B_PORT_STATUS_SPEED_100: + link->speed = SWITCH_PORT_SPEED_100; + break; + case RTL8367B_PORT_STATUS_SPEED_1000: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367b_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data); + val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >> + RTL8367B_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367b_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367B_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367B_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367B_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367B_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG, + RTL8367B_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0, + RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8)); +} + +static int rtl8367b_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8367B_MIB_TXB_ID, RTL8367B_MIB_RXB_ID)); +} + +static struct switch_attr rtl8367b_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367b_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367b_sw_set_max_length, + .get = rtl8367b_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367b_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367b_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367b_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, +}; + +static const struct switch_dev_ops rtl8367b_sw_ops = { + .attr_global = { + .attr = rtl8367b_globals, + .n_attr = ARRAY_SIZE(rtl8367b_globals), + }, + .attr_port = { + .attr = rtl8367b_port, + .n_attr = ARRAY_SIZE(rtl8367b_port), + }, + .attr_vlan = { + .attr = rtl8367b_vlan, + .n_attr = ARRAY_SIZE(rtl8367b_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367b_sw_get_port_link, + .get_port_stats = rtl8367b_sw_get_port_stats, +}; + +static int rtl8367b_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367B"; + dev->cpu_port = smi->cpu_port; + dev->ports = RTL8367B_NUM_PORTS; + dev->vlans = RTL8367B_NUM_VIDS; + dev->ops = &rtl8367b_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367b_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367b_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367b_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367b_detect(struct rtl8366_smi *smi) +{ + const char *chip_name = NULL; + u32 chip_num; + u32 chip_ver; + int ret; + + smi->emu_vlanmc = NULL; + smi->rtl8367b_chip = RTL8367B_CHIP_UNKNOWN; + + rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG, + RTL8367B_RTL_MAGIC_ID_VAL); + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip number"); + return ret; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip version"); + return ret; + } + + switch (chip_ver) { + case 0x0010: + if (chip_num == 0x6642) { + chip_name = "8367S-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S_VB; + } + break; + case 0x0020: + if (chip_num == 0x6367) { + chip_name = "8367RB-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB_VB; + } + break; + case 0x00A0: + if (chip_num == 0x6367) { + chip_name = "8367S"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S; + } + break; + case 0x1000: + chip_name = "8367RB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB; + break; + case 0x1010: + chip_name = "8367R-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367R_VB; + } + + if (!chip_name) { + dev_err(smi->parent, + "unknown chip (num:%04x ver:%04x)\n", + chip_num, chip_ver); + return -ENODEV; + } + + dev_info(smi->parent, "RTL%s chip found (num:%04x ver:%04x)\n", chip_name, chip_num, chip_ver); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367b_smi_ops = { + .detect = rtl8367b_detect, + .reset_chip = rtl8367b_reset_chip, + .setup = rtl8367b_setup, + + .mii_read = rtl8367b_mii_read, + .mii_write = rtl8367b_mii_write, + + .get_vlan_mc = rtl8367b_get_vlan_mc, + .set_vlan_mc = rtl8367b_set_vlan_mc, + .get_vlan_4k = rtl8367b_get_vlan_4k, + .set_vlan_4k = rtl8367b_set_vlan_4k, + .get_mc_index = rtl8367b_get_mc_index, + .set_mc_index = rtl8367b_set_mc_index, + .get_mib_counter = rtl8367b_get_mib_counter, + .is_vlan_valid = rtl8367b_is_vlan_valid, + .enable_vlan = rtl8367b_enable_vlan, + .enable_vlan4k = rtl8367b_enable_vlan4k, + .enable_port = rtl8367b_enable_port, +}; + +static int rtl8367b_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367b_smi_ops; + smi->num_ports = RTL8367B_NUM_PORTS; + smi->cpu_port = UINT_MAX; /* not defined yet */ + smi->num_vlan_mc = RTL8367B_NUM_VLANS; + smi->mib_counters = rtl8367b_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367b_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + if (smi->emu_vlanmc) + kfree(smi->emu_vlanmc); + kfree(smi); + return err; +} + +static void rtl8367b_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367b_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } +} + +static void rtl8367b_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367b_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367b_match[] = { + { .compatible = "realtek,rtl8367b" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367b_match); +#endif + +static struct platform_driver rtl8367b_driver = { + .driver = { + .name = RTL8367B_DRIVER_NAME, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367b_match), +#endif + }, + .probe = rtl8367b_probe, + .remove_new = rtl8367b_remove, + .shutdown = rtl8367b_shutdown, +}; + +module_platform_driver(rtl8367b_driver); + +MODULE_DESCRIPTION("Realtek RTL8367B ethernet switch driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME); + diff --git a/drivers/net/phy/swconfig.c b/drivers/net/phy/swconfig.c new file mode 100644 index 000000000000..71dd5b31f541 --- /dev/null +++ b/drivers/net/phy/swconfig.c @@ -0,0 +1,1242 @@ +/* + * swconfig.c: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SWCONFIG_DEVNAME "switch%d" + +#include "swconfig_leds.c" + +MODULE_AUTHOR("Felix Fietkau "); +MODULE_LICENSE("GPL"); + +static int swdev_id; +static struct list_head swdevs; +static DEFINE_MUTEX(swdevs_lock); +struct swconfig_callback; + +struct swconfig_callback { + struct sk_buff *msg; + struct genlmsghdr *hdr; + struct genl_info *info; + int cmd; + + /* callback for filling in the message data */ + int (*fill)(struct swconfig_callback *cb, void *arg); + + /* callback for closing the message before sending it */ + int (*close)(struct swconfig_callback *cb, void *arg); + + struct nlattr *nest[4]; + int args[4]; +}; + +/* defaults */ + +static int +swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + int ret; + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + if (!dev->ops->get_vlan_ports) + return -EOPNOTSUPP; + + ret = dev->ops->get_vlan_ports(dev, val); + return ret; +} + +static int +swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port *ports = val->value.ports; + const struct switch_dev_ops *ops = dev->ops; + int i; + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + /* validate ports */ + if (val->len > dev->ports) + return -EINVAL; + + if (!ops->set_vlan_ports) + return -EOPNOTSUPP; + + for (i = 0; i < val->len; i++) { + if (ports[i].id >= dev->ports) + return -EINVAL; + + if (ops->set_port_pvid && + !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + ops->set_port_pvid(dev, ports[i].id, val->port_vlan); + } + + return ops->set_vlan_ports(dev, val); +} + +static int +swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->set_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i); +} + +static int +swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i); +} + +static int +swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (!dev->ops->set_port_link) + return -EOPNOTSUPP; + + return dev->ops->set_port_link(dev, val->port_vlan, val->value.link); +} + +static int +swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port_link *link = val->value.link; + + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_link) + return -EOPNOTSUPP; + + memset(link, 0, sizeof(*link)); + return dev->ops->get_port_link(dev, val->port_vlan, link); +} + +static int +swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->apply_config) + return 0; + + return dev->ops->apply_config(dev); +} + +static int +swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->reset_switch) + return 0; + + return dev->ops->reset_switch(dev); +} + +enum global_defaults { + GLOBAL_APPLY, + GLOBAL_RESET, +}; + +enum vlan_defaults { + VLAN_PORTS, +}; + +enum port_defaults { + PORT_PVID, + PORT_LINK, +}; + +static struct switch_attr default_global[] = { + [GLOBAL_APPLY] = { + .type = SWITCH_TYPE_NOVAL, + .name = "apply", + .description = "Activate changes in the hardware", + .set = swconfig_apply_config, + }, + [GLOBAL_RESET] = { + .type = SWITCH_TYPE_NOVAL, + .name = "reset", + .description = "Reset the switch", + .set = swconfig_reset_switch, + } +}; + +static struct switch_attr default_port[] = { + [PORT_PVID] = { + .type = SWITCH_TYPE_INT, + .name = "pvid", + .description = "Primary VLAN ID", + .set = swconfig_set_pvid, + .get = swconfig_get_pvid, + }, + [PORT_LINK] = { + .type = SWITCH_TYPE_LINK, + .name = "link", + .description = "Get port link information", + .set = swconfig_set_link, + .get = swconfig_get_link, + } +}; + +static struct switch_attr default_vlan[] = { + [VLAN_PORTS] = { + .type = SWITCH_TYPE_PORTS, + .name = "ports", + .description = "VLAN port mapping", + .set = swconfig_set_vlan_ports, + .get = swconfig_get_vlan_ports, + }, +}; + +static const struct switch_attr * +swconfig_find_attr_by_name(const struct switch_attrlist *alist, + const char *name) +{ + int i; + + for (i = 0; i < alist->n_attr; i++) + if (strcmp(name, alist->attr[i].name) == 0) + return &alist->attr[i]; + + return NULL; +} + +static void swconfig_defaults_init(struct switch_dev *dev) +{ + const struct switch_dev_ops *ops = dev->ops; + + dev->def_global = 0; + dev->def_vlan = 0; + dev->def_port = 0; + + if (ops->get_vlan_ports || ops->set_vlan_ports) + set_bit(VLAN_PORTS, &dev->def_vlan); + + if (ops->get_port_pvid || ops->set_port_pvid) + set_bit(PORT_PVID, &dev->def_port); + + if (ops->get_port_link && + !swconfig_find_attr_by_name(&ops->attr_port, "link")) + set_bit(PORT_LINK, &dev->def_port); + + /* always present, can be no-op */ + set_bit(GLOBAL_APPLY, &dev->def_global); + set_bit(GLOBAL_RESET, &dev->def_global); +} + + +static struct genl_family switch_fam; + +static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { + [SWITCH_ATTR_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, + [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, + [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, +}; + +static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { + [SWITCH_PORT_ID] = { .type = NLA_U32 }, + [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, +}; + +static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = { + [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG }, + [SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG }, + [SWITCH_LINK_SPEED] = { .type = NLA_U32 }, +}; + +static inline void +swconfig_lock(void) +{ + mutex_lock(&swdevs_lock); +} + +static inline void +swconfig_unlock(void) +{ + mutex_unlock(&swdevs_lock); +} + +static struct switch_dev * +swconfig_get_dev(struct genl_info *info) +{ + struct switch_dev *dev = NULL; + struct switch_dev *p; + int id; + + if (!info->attrs[SWITCH_ATTR_ID]) + goto done; + + id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); + swconfig_lock(); + list_for_each_entry(p, &swdevs, dev_list) { + if (id != p->id) + continue; + + dev = p; + break; + } + if (dev) + mutex_lock(&dev->sw_mutex); + else + pr_debug("device %d not found\n", id); + swconfig_unlock(); +done: + return dev; +} + +static inline void +swconfig_put_dev(struct switch_dev *dev) +{ + mutex_unlock(&dev->sw_mutex); +} + +static int +swconfig_dump_attr(struct swconfig_callback *cb, void *arg) +{ + struct switch_attr *op = arg; + struct genl_info *info = cb->info; + struct sk_buff *msg = cb->msg; + int id = cb->args[0]; + void *hdr; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name)) + goto nla_put_failure; + if (op->description) + if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION, + op->description)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +/* spread multipart messages across multiple message buffers */ +static int +swconfig_send_multipart(struct swconfig_callback *cb, void *arg) +{ + struct genl_info *info = cb->info; + int restart = 0; + int err; + + do { + if (!cb->msg) { + cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (cb->msg == NULL) + goto error; + } + + if (!(cb->fill(cb, arg) < 0)) + break; + + /* fill failed, check if this was already the second attempt */ + if (restart) + goto error; + + /* try again in a new message, send the current one */ + restart = 1; + if (cb->close) { + if (cb->close(cb, arg) < 0) + goto error; + } + err = genlmsg_reply(cb->msg, info); + cb->msg = NULL; + if (err < 0) + goto error; + + } while (restart); + + return 0; + +error: + if (cb->msg) + nlmsg_free(cb->msg); + return -1; +} + +static int +swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + struct switch_dev *dev; + struct swconfig_callback cb; + int err = -EINVAL; + int i; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + switch (hdr->cmd) { + case SWITCH_CMD_LIST_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_LIST_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + break; + case SWITCH_CMD_LIST_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + break; + default: + WARN_ON(1); + goto out; + } + + memset(&cb, 0, sizeof(cb)); + cb.info = info; + cb.fill = swconfig_dump_attr; + for (i = 0; i < alist->n_attr; i++) { + if (alist->attr[i].disabled) + continue; + cb.args[0] = i; + err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); + if (err < 0) + goto error; + } + + /* defaults */ + for (i = 0; i < n_def; i++) { + if (!test_bit(i, def_active)) + continue; + cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; + err = swconfig_send_multipart(&cb, (void *) &def_list[i]); + if (err < 0) + goto error; + } + swconfig_put_dev(dev); + + if (!cb.msg) + return 0; + + return genlmsg_reply(cb.msg, info); + +error: + if (cb.msg) + nlmsg_free(cb.msg); +out: + swconfig_put_dev(dev); + return err; +} + +static const struct switch_attr * +swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, + struct switch_val *val) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + const struct switch_attr *attr = NULL; + unsigned int attr_id; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + if (!info->attrs[SWITCH_ATTR_OP_ID]) + goto done; + + switch (hdr->cmd) { + case SWITCH_CMD_SET_GLOBAL: + case SWITCH_CMD_GET_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_SET_VLAN: + case SWITCH_CMD_GET_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + if (!info->attrs[SWITCH_ATTR_OP_VLAN]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); + if (val->port_vlan >= dev->vlans) + goto done; + break; + case SWITCH_CMD_SET_PORT: + case SWITCH_CMD_GET_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + if (!info->attrs[SWITCH_ATTR_OP_PORT]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); + if (val->port_vlan >= dev->ports) + goto done; + break; + default: + WARN_ON(1); + goto done; + } + + if (!alist) + goto done; + + attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); + if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { + attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; + if (attr_id >= n_def) + goto done; + if (!test_bit(attr_id, def_active)) + goto done; + attr = &def_list[attr_id]; + } else { + if (attr_id >= alist->n_attr) + goto done; + attr = &alist->attr[attr_id]; + } + + if (attr->disabled) + attr = NULL; + +done: + if (!attr) + pr_debug("attribute lookup failed\n"); + val->attr = attr; + return attr; +} + +static int +swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, + struct switch_val *val, int max) +{ + struct nlattr *nla; + int rem; + + val->len = 0; + nla_for_each_nested(nla, head, rem) { + struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; + struct switch_port *port; + + if (val->len >= max) + return -EINVAL; + + port = &val->value.ports[val->len]; + + if (nla_parse_nested_deprecated(tb, SWITCH_PORT_ATTR_MAX, nla, + port_policy, NULL)) + return -EINVAL; + + if (!tb[SWITCH_PORT_ID]) + return -EINVAL; + + port->id = nla_get_u32(tb[SWITCH_PORT_ID]); + if (tb[SWITCH_PORT_FLAG_TAGGED]) + port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +swconfig_parse_link(struct sk_buff *msg, struct nlattr *nla, + struct switch_port_link *link) +{ + struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1]; + + if (nla_parse_nested_deprecated(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy, NULL)) + return -EINVAL; + + link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX]; + link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG]; + link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]); + + return 0; +} + +static int +swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) +{ + const struct switch_attr *attr; + struct switch_dev *dev; + struct switch_val val; + int err = -EINVAL; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->set) + goto error; + + val.attr = attr; + switch (attr->type) { + case SWITCH_TYPE_NOVAL: + break; + case SWITCH_TYPE_INT: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) + goto error; + val.value.i = + nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); + break; + case SWITCH_TYPE_STRING: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) + goto error; + val.value.s = + nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); + break; + case SWITCH_TYPE_PORTS: + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + + /* TODO: implement multipart? */ + if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { + err = swconfig_parse_ports(skb, + info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], + &val, dev->ports); + if (err < 0) + goto error; + } else { + val.len = 0; + err = 0; + } + break; + case SWITCH_TYPE_LINK: + val.value.link = &dev->linkbuf; + memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); + + if (info->attrs[SWITCH_ATTR_OP_VALUE_LINK]) { + err = swconfig_parse_link(skb, + info->attrs[SWITCH_ATTR_OP_VALUE_LINK], + val.value.link); + if (err < 0) + goto error; + } else { + val.len = 0; + err = 0; + } + break; + default: + goto error; + } + + err = attr->set(dev, attr, &val); +error: + swconfig_put_dev(dev); + return err; +} + +static int +swconfig_close_portlist(struct swconfig_callback *cb, void *arg) +{ + if (cb->nest[0]) + nla_nest_end(cb->msg, cb->nest[0]); + return 0; +} + +static int +swconfig_send_port(struct swconfig_callback *cb, void *arg) +{ + const struct switch_port *port = arg; + struct nlattr *p = NULL; + + if (!cb->nest[0]) { + cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); + if (!cb->nest[0]) + return -1; + } + + p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); + if (!p) + goto error; + + if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id)) + goto nla_put_failure; + if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED)) + goto nla_put_failure; + } + + nla_nest_end(cb->msg, p); + return 0; + +nla_put_failure: + nla_nest_cancel(cb->msg, p); +error: + nla_nest_cancel(cb->msg, cb->nest[0]); + return -1; +} + +static int +swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, + const struct switch_val *val) +{ + struct swconfig_callback cb; + int err = 0; + int i; + + if (!val->value.ports) + return -EINVAL; + + memset(&cb, 0, sizeof(cb)); + cb.cmd = attr; + cb.msg = *msg; + cb.info = info; + cb.fill = swconfig_send_port; + cb.close = swconfig_close_portlist; + + cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); + for (i = 0; i < val->len; i++) { + err = swconfig_send_multipart(&cb, &val->value.ports[i]); + if (err) + goto done; + } + err = val->len; + swconfig_close_portlist(&cb, NULL); + *msg = cb.msg; + +done: + return err; +} + +static int +swconfig_send_link(struct sk_buff *msg, struct genl_info *info, int attr, + const struct switch_port_link *link) +{ + struct nlattr *p = NULL; + int err = 0; + + p = nla_nest_start(msg, attr); + if (link->link) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_LINK)) + goto nla_put_failure; + } + if (link->duplex) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_DUPLEX)) + goto nla_put_failure; + } + if (link->aneg) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_ANEG)) + goto nla_put_failure; + } + if (link->tx_flow) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_TX_FLOW)) + goto nla_put_failure; + } + if (link->rx_flow) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_RX_FLOW)) + goto nla_put_failure; + } + if (nla_put_u32(msg, SWITCH_LINK_SPEED, link->speed)) + goto nla_put_failure; + if (link->eee & ADVERTISED_100baseT_Full) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_100BASET)) + goto nla_put_failure; + } + if (link->eee & ADVERTISED_1000baseT_Full) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_1000BASET)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + + return err; + +nla_put_failure: + nla_nest_cancel(msg, p); + return -1; +} + +static int +swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attr *attr; + struct switch_dev *dev; + struct sk_buff *msg = NULL; + struct switch_val val; + int err = -EINVAL; + int cmd = hdr->cmd; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->get) + goto error; + + if (attr->type == SWITCH_TYPE_PORTS) { + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + } else if (attr->type == SWITCH_TYPE_LINK) { + val.value.link = &dev->linkbuf; + memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); + } + + err = attr->get(dev, attr, &val); + if (err) + goto error; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto error; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + 0, cmd); + if (IS_ERR(hdr)) + goto nla_put_failure; + + switch (attr->type) { + case SWITCH_TYPE_INT: + if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i)) + goto nla_put_failure; + break; + case SWITCH_TYPE_STRING: + if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s)) + goto nla_put_failure; + break; + case SWITCH_TYPE_PORTS: + err = swconfig_send_ports(&msg, info, + SWITCH_ATTR_OP_VALUE_PORTS, &val); + if (err < 0) + goto nla_put_failure; + break; + case SWITCH_TYPE_LINK: + err = swconfig_send_link(msg, info, + SWITCH_ATTR_OP_VALUE_LINK, val.value.link); + if (err < 0) + goto nla_put_failure; + break; + default: + pr_debug("invalid type in attribute\n"); + err = -EINVAL; + goto nla_put_failure; + } + genlmsg_end(msg, hdr); + err = msg->len; + if (err < 0) + goto nla_put_failure; + + swconfig_put_dev(dev); + return genlmsg_reply(msg, info); + +nla_put_failure: + if (msg) + nlmsg_free(msg); +error: + swconfig_put_dev(dev); + if (!err) + err = -ENOMEM; + return err; +} + +static int +swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, + const struct switch_dev *dev) +{ + struct nlattr *p = NULL, *m = NULL; + void *hdr; + int i; + + hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, + SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port)) + goto nla_put_failure; + + m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP); + if (!m) + goto nla_put_failure; + for (i = 0; i < dev->ports; i++) { + p = nla_nest_start(msg, SWITCH_ATTR_PORTS); + if (!p) + continue; + if (dev->portmap[i].s) { + if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT, + dev->portmap[i].s)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT, + dev->portmap[i].virt)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + } + nla_nest_end(msg, m); + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int swconfig_dump_switches(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct switch_dev *dev; + int start = cb->args[0]; + int idx = 0; + + swconfig_lock(); + list_for_each_entry(dev, &swdevs, dev_list) { + if (++idx <= start) + continue; + if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + dev) < 0) + break; + } + swconfig_unlock(); + cb->args[0] = idx; + + return skb->len; +} + +static int +swconfig_done(struct netlink_callback *cb) +{ + return 0; +} + +static struct genl_ops swconfig_ops[] = { + { + .cmd = SWITCH_CMD_LIST_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_LIST_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_LIST_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_GET_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_GET_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_GET_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_SET_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_SET_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_SET_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_GET_SWITCH, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .dumpit = swconfig_dump_switches, + .done = swconfig_done, + } +}; + +static struct genl_family switch_fam = { + .name = "switch", + .hdrsize = 0, + .version = 1, + .maxattr = SWITCH_ATTR_MAX, + .policy = switch_policy, + .module = THIS_MODULE, + .ops = swconfig_ops, + .n_ops = ARRAY_SIZE(swconfig_ops), + .resv_start_op = SWITCH_CMD_SET_VLAN + 1, +}; + +#ifdef CONFIG_OF +static void +of_switch_load_portmap(struct switch_dev *dev) +{ + struct device_node *port; + + if (!dev->of_node) + return; + + for_each_child_of_node(dev->of_node, port) { + const __be32 *prop; + const char *segment; + int size, phys; + + if (!of_device_is_compatible(port, "swconfig,port")) + continue; + + if (of_property_read_string(port, "swconfig,segment", &segment)) + continue; + + prop = of_get_property(port, "swconfig,portmap", &size); + if (!prop) + continue; + + if (size != (2 * sizeof(*prop))) { + pr_err("%s: failed to parse port mapping\n", + port->name); + continue; + } + + phys = be32_to_cpup(prop++); + if ((phys < 0) | (phys >= dev->ports)) { + pr_err("%s: physical port index out of range\n", + port->name); + continue; + } + + dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL); + dev->portmap[phys].virt = be32_to_cpup(prop); + pr_debug("Found port: %s, physical: %d, virtual: %d\n", + segment, phys, dev->portmap[phys].virt); + } +} +#endif + +int +register_switch(struct switch_dev *dev, struct net_device *netdev) +{ + struct switch_dev *sdev; + const int max_switches = 8 * sizeof(unsigned long); + unsigned long in_use = 0; + int err; + int i; + + INIT_LIST_HEAD(&dev->dev_list); + if (netdev) { + dev->netdev = netdev; + if (!dev->alias) + dev->alias = netdev->name; + } + BUG_ON(!dev->alias); + + /* Make sure swdev_id doesn't overflow */ + if (swdev_id == INT_MAX) { + return -ENOMEM; + } + + if (dev->ports > 0) { + dev->portbuf = kzalloc(sizeof(struct switch_port) * + dev->ports, GFP_KERNEL); + if (!dev->portbuf) + return -ENOMEM; + dev->portmap = kzalloc(sizeof(struct switch_portmap) * + dev->ports, GFP_KERNEL); + if (!dev->portmap) { + kfree(dev->portbuf); + return -ENOMEM; + } + } + swconfig_defaults_init(dev); + mutex_init(&dev->sw_mutex); + swconfig_lock(); + dev->id = ++swdev_id; + + list_for_each_entry(sdev, &swdevs, dev_list) { + if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i)) + continue; + if (i < 0 || i > max_switches) + continue; + + set_bit(i, &in_use); + } + i = find_first_zero_bit(&in_use, max_switches); + + if (i == max_switches) { + swconfig_unlock(); + return -ENFILE; + } + +#ifdef CONFIG_OF + if (dev->ports) + of_switch_load_portmap(dev); +#endif + + /* fill device name */ + snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); + + list_add_tail(&dev->dev_list, &swdevs); + swconfig_unlock(); + + err = swconfig_create_led_trigger(dev); + if (err) + return err; + + return 0; +} +EXPORT_SYMBOL_GPL(register_switch); + +void +unregister_switch(struct switch_dev *dev) +{ + swconfig_destroy_led_trigger(dev); + kfree(dev->portbuf); + mutex_lock(&dev->sw_mutex); + swconfig_lock(); + list_del(&dev->dev_list); + swconfig_unlock(); + mutex_unlock(&dev->sw_mutex); +} +EXPORT_SYMBOL_GPL(unregister_switch); + +int +switch_generic_set_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + if (WARN_ON(!dev->ops->phy_write16)) + return -ENOTSUPP; + + /* Generic implementation */ + if (link->aneg) { + dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000); + dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + } else { + u16 bmcr = 0; + + if (link->duplex) + bmcr |= BMCR_FULLDPLX; + + switch (link->speed) { + case SWITCH_PORT_SPEED_10: + break; + case SWITCH_PORT_SPEED_100: + bmcr |= BMCR_SPEED100; + break; + case SWITCH_PORT_SPEED_1000: + bmcr |= BMCR_SPEED1000; + break; + default: + return -ENOTSUPP; + } + + dev->ops->phy_write16(dev, port, MII_BMCR, bmcr); + } + + return 0; +} +EXPORT_SYMBOL_GPL(switch_generic_set_link); + +static int __init +swconfig_init(void) +{ + INIT_LIST_HEAD(&swdevs); + + return genl_register_family(&switch_fam); +} + +static void __exit +swconfig_exit(void) +{ + genl_unregister_family(&switch_fam); +} + +module_init(swconfig_init); +module_exit(swconfig_exit); diff --git a/drivers/net/phy/swconfig_leds.c b/drivers/net/phy/swconfig_leds.c new file mode 100644 index 000000000000..1fcd4432b54e --- /dev/null +++ b/drivers/net/phy/swconfig_leds.c @@ -0,0 +1,555 @@ +/* + * swconfig_led.c: LED trigger support for the switch configuration API + * + * Copyright (C) 2011 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + */ + +#ifdef CONFIG_SWCONFIG_LEDS + +#include +#include +#include +#include + +#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10) +#define SWCONFIG_LED_NUM_PORTS 32 + +#define SWCONFIG_LED_PORT_SPEED_NA 0x01 /* unknown speed */ +#define SWCONFIG_LED_PORT_SPEED_10 0x02 /* 10 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_100 0x04 /* 100 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_1000 0x08 /* 1000 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_ALL (SWCONFIG_LED_PORT_SPEED_NA | \ + SWCONFIG_LED_PORT_SPEED_10 | \ + SWCONFIG_LED_PORT_SPEED_100 | \ + SWCONFIG_LED_PORT_SPEED_1000) + +#define SWCONFIG_LED_MODE_LINK 0x01 +#define SWCONFIG_LED_MODE_TX 0x02 +#define SWCONFIG_LED_MODE_RX 0x04 +#define SWCONFIG_LED_MODE_TXRX (SWCONFIG_LED_MODE_TX | \ + SWCONFIG_LED_MODE_RX) +#define SWCONFIG_LED_MODE_ALL (SWCONFIG_LED_MODE_LINK | \ + SWCONFIG_LED_MODE_TX | \ + SWCONFIG_LED_MODE_RX) + +struct switch_led_trigger { + struct led_trigger trig; + struct switch_dev *swdev; + + struct delayed_work sw_led_work; + u32 port_mask; + u32 port_link; + unsigned long long port_tx_traffic[SWCONFIG_LED_NUM_PORTS]; + unsigned long long port_rx_traffic[SWCONFIG_LED_NUM_PORTS]; + u8 link_speed[SWCONFIG_LED_NUM_PORTS]; +}; + +struct swconfig_trig_data { + struct led_classdev *led_cdev; + struct switch_dev *swdev; + + rwlock_t lock; + u32 port_mask; + + bool prev_link; + unsigned long prev_traffic; + enum led_brightness prev_brightness; + u8 mode; + u8 speed_mask; +}; + +static void +swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data, + enum led_brightness brightness) +{ + led_set_brightness(trig_data->led_cdev, brightness); + trig_data->prev_brightness = brightness; +} + +static void +swconfig_trig_update_port_mask(struct led_trigger *trigger) +{ + struct list_head *entry; + struct switch_led_trigger *sw_trig; + u32 port_mask; + + if (!trigger) + return; + + sw_trig = (void *) trigger; + + port_mask = 0; + spin_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + struct swconfig_trig_data *trig_data; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + trig_data = led_cdev->trigger_data; + if (trig_data) { + read_lock(&trig_data->lock); + port_mask |= trig_data->port_mask; + read_unlock(&trig_data->lock); + } + } + spin_unlock(&trigger->leddev_list_lock); + + sw_trig->port_mask = port_mask; + + if (port_mask) + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); + else + cancel_delayed_work_sync(&sw_trig->sw_led_work); +} + +static ssize_t +swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + unsigned long port_mask; + int ret; + bool changed; + + ret = kstrtoul(buf, 0, &port_mask); + if (ret) + return ret; + + write_lock(&trig_data->lock); + changed = (trig_data->port_mask != port_mask); + trig_data->port_mask = port_mask; + write_unlock(&trig_data->lock); + + if (changed) { + if (port_mask == 0) + swconfig_trig_set_brightness(trig_data, LED_OFF); + + swconfig_trig_update_port_mask(led_cdev->trigger); + } + + return size; +} + +static ssize_t +swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u32 port_mask; + + read_lock(&trig_data->lock); + port_mask = trig_data->port_mask; + read_unlock(&trig_data->lock); + + sprintf(buf, "%#x\n", port_mask); + + return strlen(buf) + 1; +} + +static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show, + swconfig_trig_port_mask_store); + +/* speed_mask file handler - display value */ +static ssize_t swconfig_trig_speed_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 speed_mask; + + read_lock(&trig_data->lock); + speed_mask = trig_data->speed_mask; + read_unlock(&trig_data->lock); + + sprintf(buf, "%#x\n", speed_mask); + + return strlen(buf) + 1; +} + +/* speed_mask file handler - store value */ +static ssize_t swconfig_trig_speed_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 speed_mask; + int ret; + + ret = kstrtou8(buf, 0, &speed_mask); + if (ret) + return ret; + + write_lock(&trig_data->lock); + trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL; + write_unlock(&trig_data->lock); + + return size; +} + +/* speed_mask special file */ +static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show, + swconfig_trig_speed_mask_store); + +static ssize_t swconfig_trig_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 mode; + + read_lock(&trig_data->lock); + mode = trig_data->mode; + read_unlock(&trig_data->lock); + + if (mode == 0) { + strcpy(buf, "none\n"); + } else { + if (mode & SWCONFIG_LED_MODE_LINK) + strcat(buf, "link "); + if (mode & SWCONFIG_LED_MODE_TX) + strcat(buf, "tx "); + if (mode & SWCONFIG_LED_MODE_RX) + strcat(buf, "rx "); + strcat(buf, "\n"); + } + + return strlen(buf)+1; +} + +static ssize_t swconfig_trig_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + char copybuf[128]; + int new_mode = -1; + char *p, *token; + + /* take a copy since we don't want to trash the inbound buffer when using strsep */ + strncpy(copybuf, buf, sizeof(copybuf)); + copybuf[sizeof(copybuf) - 1] = 0; + p = copybuf; + + while ((token = strsep(&p, " \t\n")) != NULL) { + if (!*token) + continue; + + if (new_mode < 0) + new_mode = 0; + + if (!strcmp(token, "none")) + new_mode = 0; + else if (!strcmp(token, "tx")) + new_mode |= SWCONFIG_LED_MODE_TX; + else if (!strcmp(token, "rx")) + new_mode |= SWCONFIG_LED_MODE_RX; + else if (!strcmp(token, "link")) + new_mode |= SWCONFIG_LED_MODE_LINK; + else + return -EINVAL; + } + + if (new_mode < 0) + return -EINVAL; + + write_lock(&trig_data->lock); + trig_data->mode = (u8)new_mode; + write_unlock(&trig_data->lock); + + return size; +} + +/* mode special file */ +static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show, + swconfig_trig_mode_store); + +static int +swconfig_trig_activate(struct led_classdev *led_cdev) +{ + struct switch_led_trigger *sw_trig; + struct swconfig_trig_data *trig_data; + int err; + + trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL); + if (!trig_data) + return -ENOMEM; + + sw_trig = (void *) led_cdev->trigger; + + rwlock_init(&trig_data->lock); + trig_data->led_cdev = led_cdev; + trig_data->swdev = sw_trig->swdev; + trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL; + trig_data->mode = SWCONFIG_LED_MODE_ALL; + led_cdev->trigger_data = trig_data; + + err = device_create_file(led_cdev->dev, &dev_attr_port_mask); + if (err) + goto err_free; + + err = device_create_file(led_cdev->dev, &dev_attr_speed_mask); + if (err) + goto err_dev_free; + + err = device_create_file(led_cdev->dev, &dev_attr_mode); + if (err) + goto err_mode_free; + + return 0; + +err_mode_free: + device_remove_file(led_cdev->dev, &dev_attr_speed_mask); + +err_dev_free: + device_remove_file(led_cdev->dev, &dev_attr_port_mask); + +err_free: + led_cdev->trigger_data = NULL; + kfree(trig_data); + + return err; +} + +static void +swconfig_trig_deactivate(struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + + swconfig_trig_update_port_mask(led_cdev->trigger); + + trig_data = (void *) led_cdev->trigger_data; + if (trig_data) { + device_remove_file(led_cdev->dev, &dev_attr_port_mask); + device_remove_file(led_cdev->dev, &dev_attr_speed_mask); + device_remove_file(led_cdev->dev, &dev_attr_mode); + kfree(trig_data); + } +} + +/* + * link off -> led off (can't be any other reason to turn it on) + * link on: + * mode link: led on by default only if speed matches, else off + * mode txrx: blink only if speed matches, else off + */ +static void +swconfig_trig_led_event(struct switch_led_trigger *sw_trig, + struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + u32 port_mask; + bool link; + u8 speed_mask, mode; + enum led_brightness led_base, led_blink; + + trig_data = led_cdev->trigger_data; + if (!trig_data) + return; + + read_lock(&trig_data->lock); + port_mask = trig_data->port_mask; + speed_mask = trig_data->speed_mask; + mode = trig_data->mode; + read_unlock(&trig_data->lock); + + link = !!(sw_trig->port_link & port_mask); + if (!link) { + if (trig_data->prev_brightness != LED_OFF) + swconfig_trig_set_brightness(trig_data, LED_OFF); /* and stop */ + } + else { + unsigned long traffic; + int speedok; /* link speed flag */ + int i; + + led_base = LED_FULL; + led_blink = LED_OFF; + traffic = 0; + speedok = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + if (port_mask & (1 << i)) { + if (sw_trig->link_speed[i] & speed_mask) { + traffic += ((mode & SWCONFIG_LED_MODE_TX) ? + sw_trig->port_tx_traffic[i] : 0) + + ((mode & SWCONFIG_LED_MODE_RX) ? + sw_trig->port_rx_traffic[i] : 0); + speedok = 1; + } + } + } + + if (speedok) { + /* At least one port speed matches speed_mask */ + if (!(mode & SWCONFIG_LED_MODE_LINK)) { + led_base = LED_OFF; + led_blink = LED_FULL; + } + + if (trig_data->prev_brightness != led_base) + swconfig_trig_set_brightness(trig_data, + led_base); + else if (traffic != trig_data->prev_traffic) + swconfig_trig_set_brightness(trig_data, + led_blink); + } else if (trig_data->prev_brightness != LED_OFF) + swconfig_trig_set_brightness(trig_data, LED_OFF); + + trig_data->prev_traffic = traffic; + } + + trig_data->prev_link = link; +} + +static void +swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) +{ + struct list_head *entry; + struct led_trigger *trigger; + + trigger = &sw_trig->trig; + spin_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + swconfig_trig_led_event(sw_trig, led_cdev); + } + spin_unlock(&trigger->leddev_list_lock); +} + +static void +swconfig_led_work_func(struct work_struct *work) +{ + struct switch_led_trigger *sw_trig; + struct switch_dev *swdev; + u32 port_mask; + u32 link; + int i; + + sw_trig = container_of(work, struct switch_led_trigger, + sw_led_work.work); + + port_mask = sw_trig->port_mask; + swdev = sw_trig->swdev; + + link = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + u32 port_bit; + + sw_trig->link_speed[i] = 0; + + port_bit = BIT(i); + if ((port_mask & port_bit) == 0) + continue; + + if (swdev->ops->get_port_link) { + struct switch_port_link port_link; + + memset(&port_link, '\0', sizeof(port_link)); + swdev->ops->get_port_link(swdev, i, &port_link); + + if (port_link.link) { + link |= port_bit; + switch (port_link.speed) { + case SWITCH_PORT_SPEED_UNKNOWN: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_NA; + break; + case SWITCH_PORT_SPEED_10: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_10; + break; + case SWITCH_PORT_SPEED_100: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_100; + break; + case SWITCH_PORT_SPEED_1000: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_1000; + break; + } + } + } + + if (swdev->ops->get_port_stats) { + struct switch_port_stats port_stats; + + memset(&port_stats, '\0', sizeof(port_stats)); + swdev->ops->get_port_stats(swdev, i, &port_stats); + sw_trig->port_tx_traffic[i] = port_stats.tx_bytes; + sw_trig->port_rx_traffic[i] = port_stats.rx_bytes; + } + } + + sw_trig->port_link = link; + + swconfig_trig_update_leds(sw_trig); + + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); +} + +static int +swconfig_create_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + int err; + + if (!swdev->ops->get_port_link) + return 0; + + sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL); + if (!sw_trig) + return -ENOMEM; + + sw_trig->swdev = swdev; + sw_trig->trig.name = swdev->devname; + sw_trig->trig.activate = swconfig_trig_activate; + sw_trig->trig.deactivate = swconfig_trig_deactivate; + + INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func); + + err = led_trigger_register(&sw_trig->trig); + if (err) + goto err_free; + + swdev->led_trigger = sw_trig; + + return 0; + +err_free: + kfree(sw_trig); + return err; +} + +static void +swconfig_destroy_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + + sw_trig = swdev->led_trigger; + if (sw_trig) { + cancel_delayed_work_sync(&sw_trig->sw_led_work); + led_trigger_unregister(&sw_trig->trig); + kfree(sw_trig); + } +} + +#else /* SWCONFIG_LEDS */ +static inline int +swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; } + +static inline void +swconfig_destroy_led_trigger(struct switch_dev *swdev) { } +#endif /* CONFIG_SWCONFIG_LEDS */ diff --git a/drivers/nvmem/an8855-efuse.c b/drivers/nvmem/an8855-efuse.c new file mode 100644 index 000000000000..7940453d6e58 --- /dev/null +++ b/drivers/nvmem/an8855-efuse.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Airoha AN8855 Switch EFUSE Driver + */ + +#include +#include +#include +#include +#include + +#define AN8855_EFUSE_CELL 50 + +#define AN8855_EFUSE_DATA0 0x1000a500 +#define AN8855_EFUSE_R50O GENMASK(30, 24) + +static int an8855_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) +{ + struct regmap *regmap = context; + + return regmap_bulk_read(regmap, AN8855_EFUSE_DATA0 + offset, + val, bytes / sizeof(u32)); +} + +static int an8855_efuse_probe(struct platform_device *pdev) +{ + struct nvmem_config an8855_nvmem_config = { + .name = "an8855-efuse", + .size = AN8855_EFUSE_CELL * sizeof(u32), + .stride = sizeof(u32), + .word_size = sizeof(u32), + .reg_read = an8855_efuse_read, + }; + struct device *dev = &pdev->dev; + struct nvmem_device *nvmem; + + /* Assign NVMEM priv to MFD regmap */ + an8855_nvmem_config.priv = dev_get_regmap(dev->parent, NULL); + an8855_nvmem_config.dev = dev; + nvmem = devm_nvmem_register(dev, &an8855_nvmem_config); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static const struct of_device_id an8855_efuse_of_match[] = { + { .compatible = "airoha,an8855-efuse", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, an8855_efuse_of_match); + +static struct platform_driver an8855_efuse_driver = { + .probe = an8855_efuse_probe, + .driver = { + .name = "an8855-efuse", + .of_match_table = an8855_efuse_of_match, + }, +}; +module_platform_driver(an8855_efuse_driver); + +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Driver for AN8855 Switch EFUSE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/mikrotik/Kconfig b/drivers/platform/mikrotik/Kconfig new file mode 100644 index 000000000000..85fe7b20503c --- /dev/null +++ b/drivers/platform/mikrotik/Kconfig @@ -0,0 +1,31 @@ +menuconfig MIKROTIK + bool "Platform support for MikroTik RouterBoard virtual devices" + help + Say Y here to get to see options for the MikroTik RouterBoard platform. + This option alone does not add any kernel code. + + +if MIKROTIK + +config MIKROTIK_RB_SYSFS + tristate "RouterBoot sysfs support" + depends on MTD + select LZO_DECOMPRESS + select CRC32 + help + This driver exposes RouterBoot configuration in sysfs. + +config NVMEM_LAYOUT_MIKROTIK + tristate "RouterBoot NVMEM layout support" + depends on NVMEM_LAYOUTS + help + This driver exposes MikroTik hard_config via NVMEM layout. + +config MIKROTIK_WLAN_DECOMPRESS_LZ77 + tristate "Mikrotik factory Wi-Fi caldata LZ77 decompression support" + depends on MIKROTIK_RB_SYSFS + help + Allow Mikrotik LZ77 factory flashed Wi-Fi calibration data to be + decompressed + +endif # MIKROTIK diff --git a/drivers/platform/mikrotik/Makefile b/drivers/platform/mikrotik/Makefile new file mode 100644 index 000000000000..9ffb355c1e3d --- /dev/null +++ b/drivers/platform/mikrotik/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for MikroTik RouterBoard platform specific drivers +# +obj-$(CONFIG_MIKROTIK_RB_SYSFS) += routerboot.o rb_hardconfig.o rb_softconfig.o +obj-$(CONFIG_NVMEM_LAYOUT_MIKROTIK) += rb_nvmem.o +obj-$(CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77) += rb_lz77.o diff --git a/drivers/platform/mikrotik/rb_hardconfig.c b/drivers/platform/mikrotik/rb_hardconfig.c new file mode 100644 index 000000000000..4c1edad08178 --- /dev/null +++ b/drivers/platform/mikrotik/rb_hardconfig.c @@ -0,0 +1,844 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot hard config. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This driver exposes the data encoded in the "hard_config" flash segment of + * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder + * named "hard_config". The WLAN calibration data is available on demand via + * the 'wlan_data' sysfs file in that folder. + * + * This driver permanently allocates a chunk of RAM as large as the hard_config + * MTD partition, although it is technically possible to operate entirely from + * the MTD device without using a local buffer (except when requesting WLAN + * calibration data), at the cost of a performance penalty. + * + * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show + * routines need not check for output overflow. + * + * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rb_hardconfig.h" +#include "routerboot.h" +#include "rb_lz77.h" + +#define RB_HARDCONFIG_VER "0.08" +#define RB_HC_PR_PFX "[rb_hardconfig] " + +/* Bit definitions for hardware options */ +#define RB_HW_OPT_NO_UART BIT(0) +#define RB_HW_OPT_HAS_VOLTAGE BIT(1) +#define RB_HW_OPT_HAS_USB BIT(2) +#define RB_HW_OPT_HAS_ATTINY BIT(3) +#define RB_HW_OPT_PULSE_DUTY_CYCLE BIT(9) +#define RB_HW_OPT_NO_NAND BIT(14) +#define RB_HW_OPT_HAS_LCD BIT(15) +#define RB_HW_OPT_HAS_POE_OUT BIT(16) +#define RB_HW_OPT_HAS_uSD BIT(17) +#define RB_HW_OPT_HAS_SIM BIT(18) +#define RB_HW_OPT_HAS_SFP BIT(20) +#define RB_HW_OPT_HAS_WIFI BIT(21) +#define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22) +#define RB_HW_OPT_HAS_PLC BIT(29) + +/* + * Tag ID values for ERD data. + * Mikrotik used to pack all calibration data under a single tag id 0x1, but + * recently switched to a new scheme where each radio calibration gets a + * separate tag. The new scheme has tag id bit 15 always set and seems to be + * mutually exclusive with the old scheme. + */ +#define RB_WLAN_ERD_ID_SOLO 0x0001 +#define RB_WLAN_ERD_ID_MULTI_8001 0x8001 +#define RB_WLAN_ERD_ID_MULTI_8201 0x8201 + +static struct kobject *hc_kobj; +static u8 *hc_buf; // ro buffer after init(): no locking required +static size_t hc_buflen; + +/* + * For LZOR style WLAN data unpacking. + * This binary blob is prepended to the data encoded on some devices as + * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then + * finally RLE-decoded. + * This binary blob has been extracted from RouterOS by + * https://forum.openwrt.org/u/ius + */ +static const u8 hc_lzor_prefix[] = { + 0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe, + 0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c, + 0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2, + 0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a, + 0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46, + 0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36, + 0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04, + 0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28, + 0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24, + 0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21, + 0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00, + 0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23, + 0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21, + 0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22, + 0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00, + 0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb, + 0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff, + 0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00, + 0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe, + 0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff, + 0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff, + 0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe, + 0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff, + 0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08, + 0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08, + 0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe, + 0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e, + 0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41, + 0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff, + 0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f, + 0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08, + 0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22, + 0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4, + 0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff, + 0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff, + 0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74, + 0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a, + 0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07, + 0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00, + 0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11, + 0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54, + 0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe, + 0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22, + 0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8, + 0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02, + 0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04, + 0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d, + 0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07, + 0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66, + 0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1, + 0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18, + 0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe, + 0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f, + 0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed, + 0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09, + 0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70, + 0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70, + 0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02, + 0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26, + 0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00, + 0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11, + 0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11, + 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93, + 0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06, + 0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12, + 0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a, + 0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10, + 0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42, + 0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a, + 0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32, + 0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a, + 0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30, + 0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2, + 0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf, + 0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7, + 0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50, + 0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a, + 0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95, + 0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8, + 0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7, + 0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7, + 0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50, + 0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a, + 0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95, + 0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00, + 0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72, + 0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c, + 0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00, + 0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce, + 0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59, + 0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09, + 0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b, + 0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06, + 0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad, + 0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3, + 0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31, + 0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00, + 0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64, + 0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80, + 0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5, + 0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d, + 0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc, + 0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c, + 0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5, + 0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf, + 0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50, + 0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a, + 0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90, + 0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b, + 0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c, + 0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5, + 0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c, + 0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40, + 0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7, + 0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf, + 0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61, + 0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83, + 0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d, + 0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8, + 0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a, + 0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16, + 0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e, + 0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d, + 0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68, + 0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae, + 0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11, + 0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24, + 0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30, + 0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75, + 0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96, + 0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12, + 0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16, + 0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36, + 0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67, + 0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e, + 0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11, + 0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18, + 0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37, + 0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42, + 0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87, + 0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d, + 0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f, + 0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a, + 0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58, + 0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82, + 0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c, + 0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10, + 0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26, + 0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e, + 0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1, + 0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12, + 0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14, + 0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21, + 0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68, + 0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0, + 0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14, + 0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e, + 0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e, + 0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62, + 0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb, + 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75, + 0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3, + 0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03, + 0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d, + 0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00, + 0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00, + 0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02, + 0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46, + 0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00, + 0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01, + 0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02, + 0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01, + 0xf3, 0x2d, 0x00, 0x00 +}; + +/* Array of known hw_options bits with human-friendly parsing */ +static struct hc_hwopt { + const u32 bit; + const char *str; +} const hc_hwopts[] = { + { + .bit = RB_HW_OPT_NO_UART, + .str = "no UART\t\t", + }, { + .bit = RB_HW_OPT_HAS_VOLTAGE, + .str = "has Vreg\t", + }, { + .bit = RB_HW_OPT_HAS_USB, + .str = "has usb\t\t", + }, { + .bit = RB_HW_OPT_HAS_ATTINY, + .str = "has ATtiny\t", + }, { + .bit = RB_HW_OPT_NO_NAND, + .str = "no NAND\t\t", + }, { + .bit = RB_HW_OPT_HAS_LCD, + .str = "has LCD\t\t", + }, { + .bit = RB_HW_OPT_HAS_POE_OUT, + .str = "has POE out\t", + }, { + .bit = RB_HW_OPT_HAS_uSD, + .str = "has MicroSD\t", + }, { + .bit = RB_HW_OPT_HAS_SIM, + .str = "has SIM\t\t", + }, { + .bit = RB_HW_OPT_HAS_SFP, + .str = "has SFP\t\t", + }, { + .bit = RB_HW_OPT_HAS_WIFI, + .str = "has WiFi\t", + }, { + .bit = RB_HW_OPT_HAS_TS_FOR_ADC, + .str = "has TS ADC\t", + }, { + .bit = RB_HW_OPT_HAS_PLC, + .str = "has PLC\t\t", + }, +}; + +/* + * The MAC is stored network-endian on all devices, in 2 32-bit segments: + * . Kernel print has us covered. + */ +static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf) +{ + if (8 != pld_len) + return -EINVAL; + + return sprintf(buf, "%pM\n", pld); +} + +/* + * Print HW options in a human readable way: + * The raw number and in decoded form + */ +static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf) +{ + char *out = buf; + u32 data; // cpu-endian + int i; + + if (sizeof(data) != pld_len) + return -EINVAL; + + data = *(u32 *)pld; + out += sprintf(out, "raw\t\t: 0x%08x\n\n", data); + + for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++) + out += sprintf(out, "%s: %s\n", hc_hwopts[i].str, + (data & hc_hwopts[i].bit) ? "true" : "false"); + + return out - buf; +} + +static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count); + +static struct hc_wlan_attr { + const u16 erd_tag_id; + struct bin_attribute battr; + u16 pld_ofs; + u16 pld_len; +} hc_wd_multi_battrs[] = { + { + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001, + .battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), + }, { + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201, + .battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), + } +}; + +static struct hc_wlan_attr hc_wd_solo_battr = { + .erd_tag_id = RB_WLAN_ERD_ID_SOLO, + .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), +}; + +static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); + +/* Array of known tags to publish in sysfs */ +static struct hc_attr { + const u16 tag_id; + ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); + struct kobj_attribute kattr; + u16 pld_ofs; + u16 pld_len; +} hc_attrs[] = { + { + .tag_id = RB_ID_FLASH_INFO, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MAC_ADDRESS_PACK, + .tshow = hc_tag_show_mac, + .kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BOARD_PRODUCT_CODE, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BIOS_VERSION, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_SERIAL_NUMBER, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MEMORY_SIZE, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MAC_ADDRESS_COUNT, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_HW_OPTIONS, + .tshow = hc_tag_show_hwoptions, + .kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_WLAN_DATA, + .tshow = NULL, + }, { + .tag_id = RB_ID_BOARD_IDENTIFIER, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_PRODUCT_NAME, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_DEFCONF, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BOARD_REVISION, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_revision, S_IRUSR, hc_attr_show, NULL), + } +}; + +/* + * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past + * that magic number the payload itself contains a routerboot tag node + * locating the LZO-compressed calibration data. So far this scheme is only + * known to use a single tag at id 0x1. + */ +static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t inlen, + void *outbuf, size_t *outlen) +{ + u16 lzo_ofs, lzo_len; + int ret; + + /* Find embedded tag */ + ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len); + if (ret) { + pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id); + goto fail; + } + + if (lzo_len > inlen) { + pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n"); + ret = -EINVAL; + goto fail; + } + + ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); + +fail: + return ret; +} + +/* + * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past + * that magic number is a payload that must be appended to the hc_lzor_prefix, + * the resulting blob is LZO-compressed. + * If payload starts with RB_MAGIC_LZ77, a separate (bit level LZ77) + * decompression function needs to be used. In the decompressed result, + * the RB_MAGIC_ERD magic number (aligned) must be located. Following that + * magic, there is one or more routerboot tag node(s) locating the RLE-encoded + * calibration data payload. + */ +static int hc_wlan_data_unpack_lzor_lz77(const u16 tag_id, const u8 *inbuf, size_t inlen, + void *outbuf, size_t *outlen, u32 magic) +{ + u16 rle_ofs, rle_len; + const u32 *needle; + u8 *tempbuf; + size_t templen, lzo_len; + int ret; + const char lzor[] = "LZOR"; + const char lz77[] = "LZ77"; + const char *lz_type; + + /* Temporary buffer same size as the outbuf */ + templen = *outlen; + tempbuf = kmalloc(templen, GFP_KERNEL); + if (!tempbuf) + return -ENOMEM; + + lzo_len = inlen; + if (magic == RB_MAGIC_LZOR) + lzo_len += sizeof(hc_lzor_prefix); + if (lzo_len > *outlen) + return -EFBIG; + + switch (magic) { + case RB_MAGIC_LZOR: + lz_type = lzor; + + /* Concatenate into the outbuf */ + memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); + memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); + + /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ + ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); + if (ret) { + if (LZO_E_INPUT_NOT_CONSUMED == ret) { + /* + * The tag length is always aligned thus the LZO payload may be padded, + * which can trigger a spurious error which we ignore here. + */ + pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); + } else { + pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); + goto fail; + } + } + break; + case RB_MAGIC_LZ77: + lz_type = lz77; + /* LZO-decompress lzo_len bytes of inbuf into the tempbuf */ + ret = rb_lz77_decompress(inbuf, inlen, tempbuf, &templen); + if (ret) { + pr_err(RB_HC_PR_PFX "LZ77: LZ77 decompress error %d\n", ret); + goto fail; + } + + pr_debug(RB_HC_PR_PFX "LZ77: decompressed from %zu to %zu\n", + inlen, templen); + break; + default: + return -EINVAL; + break; + } + + /* + * Post decompression we have a blob (possibly byproduct of the lzo + * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to + * be 32bit-aligned in the decompression output. + */ + needle = (const u32 *)tempbuf; + while (RB_MAGIC_ERD != *needle++) { + if ((u8 *)needle >= tempbuf+templen) { + pr_warn(RB_HC_PR_PFX "%s: ERD magic not found. Decompressed first word: 0x%08x\n", lz_type, *(u32 *)tempbuf); + ret = -ENODATA; + goto fail; + } + }; + templen -= (u8 *)needle - tempbuf; + + /* Past magic. Look for tag node */ + ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, &rle_len); + if (ret) { + pr_debug(RB_HC_PR_PFX "%s: no RLE data for id 0x%04x\n", lz_type, tag_id); + goto fail; + } + + if (rle_len > templen) { + pr_debug(RB_HC_PR_PFX "%s: Invalid RLE data length\n", lz_type); + ret = -EINVAL; + goto fail; + } + + /* RLE-decode tempbuf from needle back into the outbuf */ + ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "%s: RLE decoding error (%d)\n", lz_type, ret); + +fail: + kfree(tempbuf); + return ret; +} + +static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t tlen, + void *outbuf, size_t *outlen) +{ + const u8 *lbuf; + u32 magic; + int ret; + + /* Caller ensure tlen > 0. tofs is aligned */ + if ((tofs + tlen) > hc_buflen) + return -EIO; + + lbuf = hc_buf + tofs; + magic = *(u32 *)lbuf; + + ret = -ENODATA; + switch (magic) { + case RB_MAGIC_LZ77: + /* no known instances of lz77 without 8001/8201 data, skip SOLO */ + if (tag_id == RB_WLAN_ERD_ID_SOLO) { + pr_debug(RB_HC_PR_PFX "skipped LZ77 decompress in search for SOLO tag\n"); + break; + } + fallthrough; + case RB_MAGIC_LZOR: + /* Skip magic */ + lbuf += sizeof(magic); + tlen -= sizeof(magic); + ret = hc_wlan_data_unpack_lzor_lz77(tag_id, lbuf, tlen, outbuf, outlen, magic); + break; + case RB_MAGIC_ERD: + /* Skip magic */ + lbuf += sizeof(magic); + tlen -= sizeof(magic); + ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, outlen); + break; + default: + /* + * If the RB_ID_WLAN_DATA payload doesn't start with a + * magic number, the payload itself is the raw RLE-encoded + * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here. + */ + if (RB_WLAN_ERD_ID_SOLO == tag_id) { + ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); + } + break; + } + + return ret; +} + +static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct hc_attr *hc_attr; + const u8 *pld; + u16 pld_len; + + hc_attr = container_of(attr, typeof(*hc_attr), kattr); + + if (!hc_attr->pld_len) + return -ENOENT; + + pld = hc_buf + hc_attr->pld_ofs; + pld_len = hc_attr->pld_len; + + return hc_attr->tshow(pld, pld_len, buf); +} + +/* + * This function will allocate and free memory every time it is called. This + * is not the fastest way to do this, but since the data is rarely read (mainly + * at boot time to load wlan caldata), this makes it possible to save memory for + * the system. + */ +static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct hc_wlan_attr *hc_wattr; + size_t outlen; + void *outbuf; + int ret; + + hc_wattr = container_of(attr, typeof(*hc_wattr), battr); + + if (!hc_wattr->pld_len) + return -ENOENT; + + outlen = RB_ART_SIZE; + + /* Don't bother unpacking if the source is already too large */ + if (hc_wattr->pld_len > outlen) + return -EFBIG; + + outbuf = kmalloc(outlen, GFP_KERNEL); + if (!outbuf) + return -ENOMEM; + + ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen); + if (ret) { + kfree(outbuf); + return ret; + } + + if (off >= outlen) { + kfree(outbuf); + return 0; + } + + if (off + count > outlen) + count = outlen - off; + + memcpy(buf, outbuf + off, count); + + kfree(outbuf); + return count; +} + +int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) +{ + struct kobject *hc_wlan_kobj; + size_t bytes_read, buflen, outlen; + const u8 *buf; + void *outbuf; + int i, j, ret; + u32 magic; + + hc_buf = NULL; + hc_kobj = NULL; + hc_wlan_kobj = NULL; + + ret = __get_mtd_device(mtd); + if (ret) + return -ENODEV; + + hc_buflen = mtd->size; + hc_buf = kmalloc(hc_buflen, GFP_KERNEL); + if (!hc_buf) { + __put_mtd_device(mtd); + return -ENOMEM; + } + + ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf); + __put_mtd_device(mtd); + + if (ret) + goto fail; + + if (bytes_read != hc_buflen) { + ret = -EIO; + goto fail; + } + + /* Check we have what we expect */ + magic = *(const u32 *)hc_buf; + if (RB_MAGIC_HARD != magic) { + ret = -EINVAL; + goto fail; + } + + /* Skip magic */ + buf = hc_buf + sizeof(magic); + buflen = hc_buflen - sizeof(magic); + + /* Populate sysfs */ + ret = -ENOMEM; + hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj); + if (!hc_kobj) + goto fail; + + /* Locate and publish all known tags */ + for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) { + ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id, + &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len); + if (ret) { + hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0; + continue; + } + + /* Account for skipped magic */ + hc_attrs[i].pld_ofs += sizeof(magic); + + /* + * Special case RB_ID_WLAN_DATA to prep and create the binary attribute. + * We first check if the data is "old style" within a single tag (or no tag at all): + * If it is we publish this single blob as a binary attribute child of hc_kobj to + * preserve backward compatibility. + * If it isn't and instead uses multiple ERD tags, we create a subfolder and + * publish the known ones there. + */ + if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) { + outlen = RB_ART_SIZE; + outbuf = kmalloc(outlen, GFP_KERNEL); + if (!outbuf) { + pr_warn(RB_HC_PR_PFX "Out of memory parsing WLAN tag\n"); + continue; + } + + /* Test ID_SOLO first, if found: done */ + ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); + if (!ret) { + hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs; + hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len; + + ret = sysfs_create_bin_file(hc_kobj, &hc_wd_solo_battr.battr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", + hc_wd_solo_battr.battr.attr.name, ret); + } + /* Otherwise, create "wlan_data" subtree and publish known data */ + else { + hc_wlan_kobj = kobject_create_and_add("wlan_data", hc_kobj); + if (!hc_wlan_kobj) { + kfree(outbuf); + pr_warn(RB_HC_PR_PFX "Could not create wlan_data sysfs folder\n"); + continue; + } + + for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); j++) { + outlen = RB_ART_SIZE; + ret = hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id, + hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); + if (ret) { + hc_wd_multi_battrs[j].pld_ofs = hc_wd_multi_battrs[j].pld_len = 0; + continue; + } + + hc_wd_multi_battrs[j].pld_ofs = hc_attrs[i].pld_ofs; + hc_wd_multi_battrs[j].pld_len = hc_attrs[i].pld_len; + + ret = sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create wlan_data/%s sysfs entry (%d)\n", + hc_wd_multi_battrs[j].battr.attr.name, ret); + } + } + + kfree(outbuf); + } + /* All other tags are published via standard attributes */ + else { + ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", + hc_attrs[i].kattr.attr.name, ret); + } + } + + pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n"); + + return 0; + +fail: + kfree(hc_buf); + hc_buf = NULL; + return ret; +} + +void rb_hardconfig_exit(void) +{ + kobject_put(hc_kobj); + hc_kobj = NULL; + kfree(hc_buf); + hc_buf = NULL; +} diff --git a/drivers/platform/mikrotik/rb_hardconfig.h b/drivers/platform/mikrotik/rb_hardconfig.h new file mode 100644 index 000000000000..328f4fe3c32a --- /dev/null +++ b/drivers/platform/mikrotik/rb_hardconfig.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common definitions for MikroTik RouterBoot hard config data. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos + * + */ + +#ifndef _ROUTERBOOT_HARD_CONFIG_H_ +#define _ROUTERBOOT_HARD_CONFIG_H_ + +/* ID values for hardware settings */ +#define RB_ID_FLASH_INFO 0x03 +#define RB_ID_MAC_ADDRESS_PACK 0x04 +#define RB_ID_BOARD_PRODUCT_CODE 0x05 +#define RB_ID_BIOS_VERSION 0x06 +#define RB_ID_SDRAM_TIMINGS 0x08 +#define RB_ID_DEVICE_TIMINGS 0x09 +#define RB_ID_SOFTWARE_ID 0x0A +#define RB_ID_SERIAL_NUMBER 0x0B +#define RB_ID_MEMORY_SIZE 0x0D +#define RB_ID_MAC_ADDRESS_COUNT 0x0E +#define RB_ID_HW_OPTIONS 0x15 +#define RB_ID_WLAN_DATA 0x16 +#define RB_ID_BOARD_IDENTIFIER 0x17 +#define RB_ID_PRODUCT_NAME 0x21 +#define RB_ID_DEFCONF 0x26 +#define RB_ID_BOARD_REVISION 0x27 + +#endif /* _ROUTERBOOT_HARD_CONFIG_H_ */ diff --git a/drivers/platform/mikrotik/rb_lz77.c b/drivers/platform/mikrotik/rb_lz77.c new file mode 100644 index 000000000000..d443adb128ee --- /dev/null +++ b/drivers/platform/mikrotik/rb_lz77.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 John Thomson + */ + +#include +#include +#include +#include +#include + +#include "rb_lz77.h" + +#define MIKRO_LZ77 "[rb lz77] " + +/* + * The maximum number of bits used in a counter. + * For the look behind window, long instruction match offsets + * up to 6449 have been seen in provided compressed caldata blobs + * (that would need 21 counter bits: 4 to 12 + 11 to 0). + * conservative value here: 27 provides offset up to 0x8000 bytes + * uses a u8 in this code + */ +#define MIKRO_LZ77_MAX_COUNT_BIT_LEN 27 + +enum rb_lz77_instruction { + INSTR_ERROR = -1, + INSTR_LITERAL_BYTE = 0, + /* a (non aligned) byte follows this instruction, + * which is directly copied into output + */ + INSTR_PREVIOUS_OFFSET = 1, + /* this group is a match, with a bytes length defined by + * following counter bits, starting at bitshift 0, + * less the built-in count of 1 + * using the previous offset as source + */ + INSTR_LONG = 2 + /* this group has two counters, + * the first counter starts at bitshift 4, + * if this counter == 0, this is a non-matching group + * the second counter (bytes length) starts at bitshift 4, + * less the built-in count of 11+1. + * The final match group has this count 0, + * and following bits which pad to byte-alignment. + * + * if this counter > 0, this is a matching group + * this first count is the match offset (in bytes) + * the second count is the match length (in bytes), + * less the built-in count of 2 + * these groups can source bytes that are part of this group + */ +}; + +struct rb_lz77_instr_opcodes { + /* group instruction */ + enum rb_lz77_instruction instruction; + /* if >0, a match group, + * which starts at byte output_position - 1*offset + */ + size_t offset; + /* how long the match group is, + * or how long the (following counter) non-match group is + */ + size_t length; + /* how many bits were used for this instruction + op code(s) */ + size_t bits_used; + /* input char */ + u8 *in; + /* offset where this instruction started */ + size_t in_pos; +}; + +/** + * rb_lz77_get_bit + * + * @in: compressed data ptr + * @in_offset_bit: bit offset to extract + * + * convert the bit offset to byte offset, + * shift to modulo of bits per bytes, so that wanted bit is lsb + * and to extract only that bit. + * Caller is responsible for ensuring that in_offset_bit/8 + * does not exceed input length + */ +static inline u8 rb_lz77_get_bit(const u8 *in, const size_t in_offset_bit) +{ + return ((in[in_offset_bit / BITS_PER_BYTE] >> + (in_offset_bit % BITS_PER_BYTE)) & + 1); +} + +/** + * rb_lz77_get_byte + * + * @in: compressed data + * @in_offset_bit: bit offset to extract byte + */ +static inline u8 rb_lz77_get_byte(const u8 *in, const size_t in_offset_bit) +{ + u8 buf = 0; + int i; + + /* built a reversed byte from (likely) unaligned bits */ + for (i = 0; i <= 7; ++i) + buf += rb_lz77_get_bit(in, in_offset_bit + i) << (7 - i); + return buf; +} + +/** + * rb_lz77_decode_count - decode bits at given offset as a count + * + * @in: compressed data + * @in_len: length of compressed data + * @in_offset_bit: bit offset where count starts + * @shift: left shift operand value of first count bit + * @count: initial count + * @bits_used: how many bits were consumed by this count + * @max_bits: maximum bit count for this counter + * + * Returns the decoded count + */ +static int rb_lz77_decode_count(const u8 *in, const size_t in_len, + const size_t in_offset_bit, u8 shift, + size_t count, u8 *bits_used, const u8 max_bits) +{ + size_t pos = in_offset_bit; + const size_t max_pos = min(pos + max_bits, in_len * BITS_PER_BYTE); + bool up = true; + + *bits_used = 0; + pr_debug(MIKRO_LZ77 + "decode_count inbit: %zu, start shift:%u, initial count:%zu\n", + in_offset_bit, shift, count); + + while (true) { + /* check the input offset bit does not overflow the minimum of + * a reasonable length for this encoded count, and + * the end of the input */ + if (unlikely(pos >= max_pos)) { + pr_err(MIKRO_LZ77 + "max bit index reached before count completed\n"); + return -EFBIG; + } + + /* if the bit value at offset is set */ + if (rb_lz77_get_bit(in, pos)) + count += (1 << shift); + + /* shift increases until we find an unsed bit */ + else if (up) + up = false; + + if (up) + ++shift; + else { + if (!shift) { + *bits_used = pos - in_offset_bit + 1; + return count; + } + --shift; + } + + ++pos; + } + + return -EINVAL; +} + +/** + * rb_lz77_decode_instruction + * + * @in: compressed data + * @in_offset_bit: bit offset where instruction starts + * @bits_used: how many bits were consumed by this count + * + * Returns the decoded instruction + */ +static enum rb_lz77_instruction +rb_lz77_decode_instruction(const u8 *in, size_t in_offset_bit, u8 *bits_used) +{ + if (rb_lz77_get_bit(in, in_offset_bit)) { + *bits_used = 2; + if (rb_lz77_get_bit(in, ++in_offset_bit)) + return INSTR_LONG; + else + return INSTR_PREVIOUS_OFFSET; + } else { + *bits_used = 1; + return INSTR_LITERAL_BYTE; + } + return INSTR_ERROR; +} + +/** + * rb_lz77_decode_instruction_operators + * + * @in: compressed data + * @in_len: length of compressed data + * @in_offset_bit: bit offset where instruction starts + * @previous_offset: last used match offset + * @opcode: struct to hold instruction & operators + * + * Returns error code + */ +static int rb_lz77_decode_instruction_operators( + const u8 *in, const size_t in_len, const size_t in_offset_bit, + const size_t previous_offset, struct rb_lz77_instr_opcodes *opcode) +{ + enum rb_lz77_instruction instruction; + u8 bit_count = 0; + u8 bits_used = 0; + int offset = 0; + int length = 0; + + instruction = rb_lz77_decode_instruction(in, in_offset_bit, &bit_count); + + /* skip bits used by instruction */ + bits_used += bit_count; + + switch (instruction) { + case INSTR_LITERAL_BYTE: + /* non-matching char */ + offset = 0; + length = 1; + break; + + case INSTR_PREVIOUS_OFFSET: + /* matching group uses previous offset */ + offset = previous_offset; + + length = rb_lz77_decode_count(in, in_len, + in_offset_bit + bits_used, 0, 1, + &bit_count, + MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by count */ + bits_used += bit_count; + break; + + case INSTR_LONG: + offset = rb_lz77_decode_count(in, in_len, + in_offset_bit + bits_used, 4, 0, + &bit_count, + MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(offset < 0)) + return offset; + + /* skip bits used by offset count */ + bits_used += bit_count; + + if (offset == 0) { + /* non-matching long group */ + length = rb_lz77_decode_count( + in, in_len, in_offset_bit + bits_used, 4, 12, + &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by length count */ + bits_used += bit_count; + } else { + /* matching group */ + length = rb_lz77_decode_count( + in, in_len, in_offset_bit + bits_used, 0, 2, + &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by length count */ + bits_used += bit_count; + } + + break; + + case INSTR_ERROR: + return -EINVAL; + } + + opcode->instruction = instruction; + opcode->offset = offset; + opcode->length = length; + opcode->bits_used = bits_used; + opcode->in = (u8 *)in; + opcode->in_pos = in_offset_bit; + return 0; +} + +/** + * rb_lz77_decompress + * + * @in: compressed data ptr + * @in_len: length of compressed data + * @out: buffer ptr to decompress into + * @out_len: length of decompressed buffer in input, + * length of decompressed data in success + * + * Returns 0 on success, or negative error + */ +int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len) +{ + u8 *output_ptr; + size_t input_bit = 0; + const u8 *output_end = out + *out_len; + struct rb_lz77_instr_opcodes *opcode; + size_t match_offset = 0; + int rc = 0; + size_t match_length, partial_count, i; + + output_ptr = out; + + if (unlikely((in_len * BITS_PER_BYTE) > SIZE_MAX)) { + pr_err(MIKRO_LZ77 "input longer than expected\n"); + return -EFBIG; + } + + opcode = kmalloc(sizeof(*opcode), GFP_KERNEL); + if (!opcode) + return -ENOMEM; + + while (true) { + if (unlikely(output_ptr > output_end)) { + pr_err(MIKRO_LZ77 "output overrun\n"); + rc = -EOVERFLOW; + goto free_lz77_struct; + } + if (unlikely(input_bit > in_len * BITS_PER_BYTE)) { + pr_err(MIKRO_LZ77 "input overrun\n"); + rc = -ENODATA; + goto free_lz77_struct; + } + + rc = rb_lz77_decode_instruction_operators(in, in_len, input_bit, + match_offset, opcode); + if (unlikely(rc < 0)) { + pr_err(MIKRO_LZ77 + "instruction operands decode error\n"); + goto free_lz77_struct; + } + + pr_debug(MIKRO_LZ77 "inbit:0x%zx->outbyte:0x%zx", input_bit, + output_ptr - out); + + input_bit += opcode->bits_used; + switch (opcode->instruction) { + case INSTR_LITERAL_BYTE: + pr_debug(" short"); + fallthrough; + case INSTR_LONG: + if (opcode->offset == 0) { + /* this is a non-matching group */ + pr_debug(" non-match, len: 0x%zx\n", + opcode->length); + /* test end marker */ + if (opcode->length == 0xc && + ((input_bit + + opcode->length * BITS_PER_BYTE) > + in_len)) { + *out_len = output_ptr - out; + pr_debug( + MIKRO_LZ77 + "lz77 decompressed from %zu to %zu\n", + in_len, *out_len); + rc = 0; + goto free_lz77_struct; + } + for (i = opcode->length; i > 0; --i) { + *output_ptr = + rb_lz77_get_byte(in, input_bit); + ++output_ptr; + input_bit += BITS_PER_BYTE; + } + /* do no fallthrough if a non-match group */ + break; + } + match_offset = opcode->offset; + fallthrough; + case INSTR_PREVIOUS_OFFSET: + match_length = opcode->length; + partial_count = 0; + + pr_debug(" match, offset: 0x%zx, len: 0x%zx", + opcode->offset, match_length); + + if (unlikely(opcode->offset == 0)) { + pr_err(MIKRO_LZ77 + "match group missing opcode->offset\n"); + rc = -EBADMSG; + goto free_lz77_struct; + } + + /* overflow */ + if (unlikely((output_ptr + match_length) > + output_end)) { + pr_err(MIKRO_LZ77 + "match group output overflow\n"); + rc = -ENOBUFS; + goto free_lz77_struct; + } + + /* underflow */ + if (unlikely((output_ptr - opcode->offset) < out)) { + pr_err(MIKRO_LZ77 + "match group offset underflow\n"); + rc = -ESPIPE; + goto free_lz77_struct; + } + + /* there are cases where the match (length) includes + * data that is a part of the same match + */ + while (opcode->offset < match_length) { + ++partial_count; + memcpy(output_ptr, output_ptr - opcode->offset, + opcode->offset); + output_ptr += opcode->offset; + match_length -= opcode->offset; + } + memcpy(output_ptr, output_ptr - opcode->offset, + match_length); + output_ptr += match_length; + if (partial_count) + pr_debug(" (%zu partial memcpy)", + partial_count); + pr_debug("\n"); + + break; + + case INSTR_ERROR: + rc = -EINVAL; + goto free_lz77_struct; + } + } + + pr_err(MIKRO_LZ77 "decode loop broken\n"); + rc = -EINVAL; + +free_lz77_struct: + kfree(opcode); + return rc; +} +EXPORT_SYMBOL_GPL(rb_lz77_decompress); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Mikrotik Wi-Fi caldata LZ77 decompressor"); +MODULE_AUTHOR("John Thomson"); diff --git a/drivers/platform/mikrotik/rb_lz77.h b/drivers/platform/mikrotik/rb_lz77.h new file mode 100644 index 000000000000..55179fcbc8e0 --- /dev/null +++ b/drivers/platform/mikrotik/rb_lz77.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 John Thomson + */ + +#ifndef __MIKROTIK_WLAN_LZ77_H__ +#define __MIKROTIK_WLAN_LZ77_H__ + +#include + +#ifdef CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 +/** + * rb_lz77_decompress + * + * @in: compressed data ptr + * @in_len: length of compressed data + * @out: buffer ptr to decompress into + * @out_len: length of decompressed buffer in input, + * length of decompressed data in success + * + * Returns 0 on success, or negative error + */ +int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len); + +#else /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ + +static inline int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ +#endif /* __MIKROTIK_WLAN_LZ77_H__ */ diff --git a/drivers/platform/mikrotik/rb_nvmem.c b/drivers/platform/mikrotik/rb_nvmem.c new file mode 100644 index 000000000000..6f785ce7d14d --- /dev/null +++ b/drivers/platform/mikrotik/rb_nvmem.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * NVMEM layout driver for MikroTik Routerboard hard config cells + * + * Copyright (C) 2024 Robert Marko + * Based on the sysfs hard config driver by Thibaut VARÈNE + * Comments documenting the format carried over from routerboot.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rb_hardconfig.h" +#include "routerboot.h" + +#define TLV_TAG_MASK GENMASK(15, 0) +#define TLV_LEN_MASK GENMASK(31, 16) + +static const char *rb_tlv_cell_name(u16 tag) +{ + switch (tag) { + case RB_ID_FLASH_INFO: + return "flash-info"; + case RB_ID_MAC_ADDRESS_PACK: + return "base-mac-address"; + case RB_ID_BOARD_PRODUCT_CODE: + return "board-product-code"; + case RB_ID_BIOS_VERSION: + return "booter-version"; + case RB_ID_SERIAL_NUMBER: + return "board-serial"; + case RB_ID_MEMORY_SIZE: + return "mem-size"; + case RB_ID_MAC_ADDRESS_COUNT: + return "mac-count"; + case RB_ID_HW_OPTIONS: + return "hw-options"; + case RB_ID_WLAN_DATA: + return "wlan-data"; + case RB_ID_BOARD_IDENTIFIER: + return "board-identifier"; + case RB_ID_PRODUCT_NAME: + return "product-name"; + case RB_ID_DEFCONF: + return "defconf"; + case RB_ID_BOARD_REVISION: + return "board-revision"; + default: + break; + } + + return NULL; +} + +static int rb_tlv_mac_read_cb(void *priv, const char *id, int index, + unsigned int offset, void *buf, + size_t bytes) +{ + if (index < 0) + return -EINVAL; + + if (!is_valid_ether_addr(buf)) + return -EINVAL; + + eth_addr_add(buf, index); + + return 0; +} + +static nvmem_cell_post_process_t rb_tlv_read_cb(u16 tag) +{ + switch (tag) { + case RB_ID_MAC_ADDRESS_PACK: + return &rb_tlv_mac_read_cb; + default: + break; + } + + return NULL; +} + +static int rb_add_cells(struct device *dev, struct nvmem_device *nvmem, + const size_t data_len, u8 *data) +{ + u32 node, offset = sizeof(RB_MAGIC_HARD); + struct nvmem_cell_info cell = {}; + struct device_node *layout; + u16 tlv_tag, tlv_len; + int ret; + + layout = of_nvmem_layout_get_container(nvmem); + if (!layout) + return -ENOENT; + + /* + * Routerboot tag nodes are u32 values: + * - The low nibble is the tag identification number, + * - The high nibble is the tag payload length (node excluded) in bytes. + * Tag nodes are CPU-endian. + * Tag nodes are 32bit-aligned. + * + * The payload immediately follows the tag node. + * Payload offset will always be aligned. while length may not end on 32bit + * boundary (the only known case is when parsing ERD data). + * The payload is CPU-endian when applicable. + * Tag nodes are not ordered (by ID) on flash. + */ + while ((offset + sizeof(node)) <= data_len) { + node = *((const u32 *) (data + offset)); + /* Tag list ends with null node */ + if (!node) + break; + + tlv_tag = FIELD_GET(TLV_TAG_MASK, node); + tlv_len = FIELD_GET(TLV_LEN_MASK, node); + + offset += sizeof(node); + if (offset + tlv_len > data_len) { + dev_err(dev, "Out of bounds field (0x%x bytes at 0x%x)\n", + tlv_len, offset); + break; + } + + cell.name = rb_tlv_cell_name(tlv_tag); + if (!cell.name) + goto skip; + + cell.offset = offset; + /* + * MikroTik stores MAC-s with length of 8 bytes, + * but kernel expects it to be ETH_ALEN (6 bytes), + * so we need to make sure that is the case. + */ + if (tlv_tag == RB_ID_MAC_ADDRESS_PACK) + cell.bytes = ETH_ALEN; + else + cell.bytes = tlv_len; + cell.np = of_get_child_by_name(layout, cell.name); + cell.read_post_process = rb_tlv_read_cb(tlv_tag); + + ret = nvmem_add_one_cell(nvmem, &cell); + if (ret) { + of_node_put(layout); + return ret; + } + + /* + * The only known situation where len may not end on 32bit + * boundary is within ERD data. Since we're only extracting + * one tag (the first and only one) from that data, we should + * never need to forcefully ALIGN(). Do it anyway, this is not a + * performance path. + */ +skip: + offset += ALIGN(tlv_len, sizeof(offset)); + } + + of_node_put(layout); + + return 0; +} + +static int rb_parse_table(struct nvmem_layout *layout) +{ + struct nvmem_device *nvmem = layout->nvmem; + struct device *dev = &layout->dev; + size_t mtd_size; + u8 *data; + u32 hdr; + int ret; + + ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); + if (ret < 0) + return ret; + + if (hdr != RB_MAGIC_HARD) { + dev_err(dev, "Invalid header\n"); + return -EINVAL; + } + + mtd_size = nvmem_dev_size(nvmem); + + data = devm_kmalloc(dev, mtd_size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = nvmem_device_read(nvmem, 0, mtd_size, data); + if (ret != mtd_size) + return ret; + + return rb_add_cells(dev, nvmem, mtd_size, data); +} + +static int rb_nvmem_probe(struct nvmem_layout *layout) +{ + layout->add_cells = rb_parse_table; + + return nvmem_layout_register(layout); +} + +static void rb_nvmem_remove(struct nvmem_layout *layout) +{ + nvmem_layout_unregister(layout); +} + +static const struct of_device_id rb_nvmem_of_match_table[] = { + { .compatible = "mikrotik,routerboot-nvmem", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rb_nvmem_of_match_table); + +static struct nvmem_layout_driver rb_nvmem_layout = { + .probe = rb_nvmem_probe, + .remove = rb_nvmem_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rb_nvmem", + .of_match_table = rb_nvmem_of_match_table, + }, +}; +module_nvmem_layout_driver(rb_nvmem_layout); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Marko "); +MODULE_DESCRIPTION("NVMEM layout driver for MikroTik Routerboard hard config cells"); diff --git a/drivers/platform/mikrotik/rb_softconfig.c b/drivers/platform/mikrotik/rb_softconfig.c new file mode 100644 index 000000000000..5acff6aa9184 --- /dev/null +++ b/drivers/platform/mikrotik/rb_softconfig.c @@ -0,0 +1,795 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot soft config. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This driver exposes the data encoded in the "soft_config" flash segment of + * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder + * named "soft_config". The data is presented in a user/machine-friendly way + * with just as much parsing as can be generalized across mikrotik platforms + * (as inferred from reverse-engineering). + * + * The known soft_config tags are presented in the "soft_config" sysfs folder, + * with the addition of one specific file named "commit", which is only + * available if the driver supports writes to the mtd device: no modifications + * made to any of the other attributes are actually written back to flash media + * until a true value is input into this file (e.g. [Yy1]). This is to avoid + * unnecessary flash wear, and to permit to revert all changes by issuing a + * false value ([Nn0]). Reading the content of this file shows the current + * status of the driver: if the data in sysfs matches the content of the + * soft_config partition, the file will read "clean". Otherwise, it will read + * "dirty". + * + * The writeable sysfs files presented by this driver will accept only inputs + * which are in a valid range for the given tag. As a design choice, the driver + * will not assess whether the inputs are identical to the existing data. + * + * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show + * routines need not check for output overflow. + * + * Some constant defines extracted from rbcfg.h by Gabor Juhos + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATH79 + #include +#endif + +#include "routerboot.h" + +#define RB_SOFTCONFIG_VER "0.05" +#define RB_SC_PR_PFX "[rb_softconfig] " + +#define RB_SC_HAS_WRITE_SUPPORT true +#define RB_SC_WMODE S_IWUSR +#define RB_SC_RMODE S_IRUSR + +/* ID values for software settings */ +#define RB_SCID_UART_SPEED 0x01 // u32*1 +#define RB_SCID_BOOT_DELAY 0x02 // u32*1 +#define RB_SCID_BOOT_DEVICE 0x03 // u32*1 +#define RB_SCID_BOOT_KEY 0x04 // u32*1 +#define RB_SCID_CPU_MODE 0x05 // u32*1 +#define RB_SCID_BIOS_VERSION 0x06 // str +#define RB_SCID_BOOT_PROTOCOL 0x09 // u32*1 +#define RB_SCID_CPU_FREQ_IDX 0x0C // u32*1 +#define RB_SCID_BOOTER 0x0D // u32*1 +#define RB_SCID_SILENT_BOOT 0x0F // u32*1 +/* + * protected_routerboot seems to use tag 0x1F. It only works in combination with + * RouterOS, resulting in a wiped board otherwise, so it's not implemented here. + * The tag values are as follows: + * - off: 0x0 + * - on: the lower halfword encodes the max value in s for the reset feature, + * the higher halfword encodes the min value in s for the reset feature. + * Default value when on: 0x00140258: 0x14 = 20s / 0x258= 600s + * See details here: https://wiki.mikrotik.com/wiki/Manual:RouterBOARD_settings#Protected_bootloader + */ + +/* Tag values */ + +#define RB_UART_SPEED_115200 0 +#define RB_UART_SPEED_57600 1 +#define RB_UART_SPEED_38400 2 +#define RB_UART_SPEED_19200 3 +#define RB_UART_SPEED_9600 4 +#define RB_UART_SPEED_4800 5 +#define RB_UART_SPEED_2400 6 +#define RB_UART_SPEED_1200 7 +#define RB_UART_SPEED_OFF 8 + +/* valid boot delay: 1 - 9s in 1s increment */ +#define RB_BOOT_DELAY_MIN 1 +#define RB_BOOT_DELAY_MAX 9 + +#define RB_BOOT_DEVICE_ETHER 0 // "boot over Ethernet" +#define RB_BOOT_DEVICE_NANDETH 1 // "boot from NAND, if fail then Ethernet" +#define RB_BOOT_DEVICE_CFCARD 2 // (not available in rbcfg) +#define RB_BOOT_DEVICE_ETHONCE 3 // "boot Ethernet once, then NAND" +#define RB_BOOT_DEVICE_NANDONLY 5 // "boot from NAND only" +#define RB_BOOT_DEVICE_FLASHCFG 7 // "boot in flash configuration mode" +#define RB_BOOT_DEVICE_FLSHONCE 8 // "boot in flash configuration mode once, then NAND" + +/* + * ATH79 9xxx CPU frequency indices. + * It is unknown if they apply to all ATH79 RBs, and some do not seem to feature + * the upper levels (QCA955x), while F is presumably AR9344-only. + */ +#define RB_CPU_FREQ_IDX_ATH79_9X_A (0 << 3) +#define RB_CPU_FREQ_IDX_ATH79_9X_B (1 << 3) // 0x8 +#define RB_CPU_FREQ_IDX_ATH79_9X_C (2 << 3) // 0x10 - factory freq for many devices +#define RB_CPU_FREQ_IDX_ATH79_9X_D (3 << 3) // 0x18 +#define RB_CPU_FREQ_IDX_ATH79_9X_E (4 << 3) // 0x20 +#define RB_CPU_FREQ_IDX_ATH79_9X_F (5 << 3) // 0x28 + +#define RB_CPU_FREQ_IDX_ATH79_9X_MIN 0 // all devices support lowest setting +#define RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX 5 // stops at F +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX 4 // stops at E +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX 2 // stops at C +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX 3 // stops at D + +/* ATH79 7xxx CPU frequency indices. */ +#define RB_CPU_FREQ_IDX_ATH79_7X_A ((0 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_B ((1 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_C ((2 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_D ((3 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_E ((4 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_F ((5 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_G ((6 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_H ((7 * 9) << 4) + +#define RB_CPU_FREQ_IDX_ATH79_7X_MIN 0 // all devices support lowest setting +#define RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX 3 // stops at D +#define RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX 7 // stops at H - check if applies to all AR71xx devices + +#define RB_SC_CRC32_OFFSET 4 // located right after magic + +static struct kobject *sc_kobj; +static u8 *sc_buf; +static size_t sc_buflen; +static rwlock_t sc_bufrwl; // rw lock to sc_buf + +/* MUST be used with lock held */ +#define RB_SC_CLRCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = 0 +#define RB_SC_GETCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) +#define RB_SC_SETCRC(_crc) *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = (_crc) + +struct sc_u32tvs { + const u32 val; + const char *str; +}; + +#define RB_SC_TVS(_val, _str) { \ + .val = (_val), \ + .str = (_str), \ +} + +static ssize_t sc_tag_show_u32tvs(const u8 *pld, u16 pld_len, char *buf, + const struct sc_u32tvs tvs[], const int tvselmts) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + int i; + + // fallback to raw hex output if we can't handle the input + if (tvselmts < 0) + return routerboot_tag_show_u32s(pld, pld_len, buf); + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + for (i = 0; i < tvselmts; i++) { + fmt = (tvs[i].val == data) ? "[%s] " : "%s "; + out += sprintf(out, fmt, tvs[i].str); + } + + out += sprintf(out, "\n"); + return out - buf; +} + +static ssize_t sc_tag_store_u32tvs(const u8 *pld, u16 pld_len, const char *buf, size_t count, + const struct sc_u32tvs tvs[], const int tvselmts) +{ + int i; + + if (tvselmts < 0) + return tvselmts; + + if (sizeof(u32) != pld_len) + return -EINVAL; + + for (i = 0; i < tvselmts; i++) { + if (sysfs_streq(buf, tvs[i].str)) { + write_lock(&sc_bufrwl); + *(u32 *)pld = tvs[i].val; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + return count; + } + } + + return -EINVAL; +} + +struct sc_boolts { + const char *strfalse; + const char *strtrue; +}; + +static ssize_t sc_tag_show_boolts(const u8 *pld, u16 pld_len, char *buf, + const struct sc_boolts *bts) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + fmt = (data) ? "%s [%s]\n" : "[%s] %s\n"; + out += sprintf(out, fmt, bts->strfalse, bts->strtrue); + + return out - buf; +} + +static ssize_t sc_tag_store_boolts(const u8 *pld, u16 pld_len, const char *buf, size_t count, + const struct sc_boolts *bts) +{ + u32 data; // cpu-endian + + if (sizeof(data) != pld_len) + return -EINVAL; + + if (sysfs_streq(buf, bts->strfalse)) + data = 0; + else if (sysfs_streq(buf, bts->strtrue)) + data = 1; + else + return -EINVAL; + + write_lock(&sc_bufrwl); + *(u32 *)pld = data; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + + return count; +} +static struct sc_u32tvs const sc_uartspeeds[] = { + RB_SC_TVS(RB_UART_SPEED_OFF, "off"), + RB_SC_TVS(RB_UART_SPEED_1200, "1200"), + RB_SC_TVS(RB_UART_SPEED_2400, "2400"), + RB_SC_TVS(RB_UART_SPEED_4800, "4800"), + RB_SC_TVS(RB_UART_SPEED_9600, "9600"), + RB_SC_TVS(RB_UART_SPEED_19200, "19200"), + RB_SC_TVS(RB_UART_SPEED_38400, "38400"), + RB_SC_TVS(RB_UART_SPEED_57600, "57600"), + RB_SC_TVS(RB_UART_SPEED_115200, "115200"), +}; + +/* + * While the defines are carried over from rbcfg, use strings that more clearly + * show the actual setting purpose (especially since the NAND* settings apply + * to both nand- and nor-based devices). "cfcard" was disabled in rbcfg: disable + * it here too. + */ +static struct sc_u32tvs const sc_bootdevices[] = { + RB_SC_TVS(RB_BOOT_DEVICE_ETHER, "eth"), + RB_SC_TVS(RB_BOOT_DEVICE_NANDETH, "flasheth"), + //RB_SC_TVS(RB_BOOT_DEVICE_CFCARD, "cfcard"), + RB_SC_TVS(RB_BOOT_DEVICE_ETHONCE, "ethonce"), + RB_SC_TVS(RB_BOOT_DEVICE_NANDONLY, "flash"), + RB_SC_TVS(RB_BOOT_DEVICE_FLASHCFG, "cfg"), + RB_SC_TVS(RB_BOOT_DEVICE_FLSHONCE, "cfgonce"), +}; + +static struct sc_boolts const sc_bootkey = { + .strfalse = "any", + .strtrue = "del", +}; + +static struct sc_boolts const sc_cpumode = { + .strfalse = "powersave", + .strtrue = "regular", +}; + +static struct sc_boolts const sc_bootproto = { + .strfalse = "bootp", + .strtrue = "dhcp", +}; + +static struct sc_boolts const sc_booter = { + .strfalse = "regular", + .strtrue = "backup", +}; + +static struct sc_boolts const sc_silent_boot = { + .strfalse = "off", + .strtrue = "on", +}; + +#define SC_TAG_SHOW_STORE_U32TVS_FUNCS(_name) \ +static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ +{ \ + return sc_tag_show_u32tvs(pld, pld_len, buf, sc_##_name, ARRAY_SIZE(sc_##_name)); \ +} \ +static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ +{ \ + return sc_tag_store_u32tvs(pld, pld_len, buf, count, sc_##_name, ARRAY_SIZE(sc_##_name)); \ +} + +#define SC_TAG_SHOW_STORE_BOOLTS_FUNCS(_name) \ +static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ +{ \ + return sc_tag_show_boolts(pld, pld_len, buf, &sc_##_name); \ +} \ +static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ +{ \ + return sc_tag_store_boolts(pld, pld_len, buf, count, &sc_##_name); \ +} + +SC_TAG_SHOW_STORE_U32TVS_FUNCS(uartspeeds) +SC_TAG_SHOW_STORE_U32TVS_FUNCS(bootdevices) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootkey) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(cpumode) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootproto) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(booter) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(silent_boot) + +static ssize_t sc_tag_show_bootdelays(const u8 *pld, u16 pld_len, char *buf) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + int i; + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + for (i = RB_BOOT_DELAY_MIN; i <= RB_BOOT_DELAY_MAX; i++) { + fmt = (i == data) ? "[%d] " : "%d "; + out += sprintf(out, fmt, i); + } + + out += sprintf(out, "\n"); + return out - buf; +} + +static ssize_t sc_tag_store_bootdelays(const u8 *pld, u16 pld_len, const char *buf, size_t count) +{ + u32 data; // cpu-endian + int ret; + + if (sizeof(data) != pld_len) + return -EINVAL; + + ret = kstrtou32(buf, 10, &data); + if (ret) + return ret; + + if ((data < RB_BOOT_DELAY_MIN) || (RB_BOOT_DELAY_MAX < data)) + return -EINVAL; + + write_lock(&sc_bufrwl); + *(u32 *)pld = data; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + + return count; +} + +/* Support CPU frequency accessors only when the tag format has been asserted */ +#if defined(CONFIG_ATH79) +/* Use the same letter-based nomenclature as RouterBOOT */ +static struct sc_u32tvs const sc_cpufreq_indexes_ath79_9x[] = { + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_A, "a"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_B, "b"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_C, "c"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_D, "d"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_E, "e"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_F, "f"), +}; + +static struct sc_u32tvs const sc_cpufreq_indexes_ath79_7x[] = { + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_A, "a"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_B, "b"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_C, "c"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_D, "d"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_E, "e"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_F, "f"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_G, "g"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_H, "h"), +}; + +static int sc_tag_cpufreq_ath79_arraysize(void) +{ + int idx_max; + + if (ATH79_SOC_AR7161 == ath79_soc) + idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX+1; + else if (soc_is_ar724x()) + idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX+1; + else if (soc_is_ar9344()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX+1; + else if (soc_is_qca953x()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX+1; + else if (soc_is_qca9556()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX+1; + else if (soc_is_qca9558()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX+1; + else + idx_max = -EOPNOTSUPP; + + return idx_max; +} + +static ssize_t sc_tag_show_cpufreq_indexes(const u8 *pld, u16 pld_len, char *buf) +{ + const struct sc_u32tvs *tvs; + + if (soc_is_ar71xx() || soc_is_ar724x()) + tvs = sc_cpufreq_indexes_ath79_7x; + else + tvs = sc_cpufreq_indexes_ath79_9x; + + return sc_tag_show_u32tvs(pld, pld_len, buf, tvs, sc_tag_cpufreq_ath79_arraysize()); +} + +static ssize_t sc_tag_store_cpufreq_indexes(const u8 *pld, u16 pld_len, const char *buf, size_t count) +{ + const struct sc_u32tvs *tvs; + + if (soc_is_ar71xx() || soc_is_ar724x()) + tvs = sc_cpufreq_indexes_ath79_7x; + else + tvs = sc_cpufreq_indexes_ath79_9x; + + return sc_tag_store_u32tvs(pld, pld_len, buf, count, tvs, sc_tag_cpufreq_ath79_arraysize()); +} +#else + /* By default we only show the raw value to help with reverse-engineering */ + #define sc_tag_show_cpufreq_indexes routerboot_tag_show_u32s + #define sc_tag_store_cpufreq_indexes NULL +#endif + +static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); +static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count); + +/* Array of known tags to publish in sysfs */ +static struct sc_attr { + const u16 tag_id; + /* sysfs tag show attribute. Must lock sc_buf when dereferencing pld */ + ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); + /* sysfs tag store attribute. Must lock sc_buf when dereferencing pld */ + ssize_t (* const tstore)(const u8 *pld, u16 pld_len, const char *buf, size_t count); + struct kobj_attribute kattr; + u16 pld_ofs; + u16 pld_len; +} sc_attrs[] = { + { + .tag_id = RB_SCID_UART_SPEED, + .tshow = sc_tag_show_uartspeeds, + .tstore = sc_tag_store_uartspeeds, + .kattr = __ATTR(uart_speed, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_DELAY, + .tshow = sc_tag_show_bootdelays, + .tstore = sc_tag_store_bootdelays, + .kattr = __ATTR(boot_delay, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_DEVICE, + .tshow = sc_tag_show_bootdevices, + .tstore = sc_tag_store_bootdevices, + .kattr = __ATTR(boot_device, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_KEY, + .tshow = sc_tag_show_bootkey, + .tstore = sc_tag_store_bootkey, + .kattr = __ATTR(boot_key, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_CPU_MODE, + .tshow = sc_tag_show_cpumode, + .tstore = sc_tag_store_cpumode, + .kattr = __ATTR(cpu_mode, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BIOS_VERSION, + .tshow = routerboot_tag_show_string, + .tstore = NULL, + .kattr = __ATTR(bios_version, RB_SC_RMODE, sc_attr_show, NULL), + }, { + .tag_id = RB_SCID_BOOT_PROTOCOL, + .tshow = sc_tag_show_bootproto, + .tstore = sc_tag_store_bootproto, + .kattr = __ATTR(boot_proto, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_CPU_FREQ_IDX, + .tshow = sc_tag_show_cpufreq_indexes, + .tstore = sc_tag_store_cpufreq_indexes, + .kattr = __ATTR(cpufreq_index, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOTER, + .tshow = sc_tag_show_booter, + .tstore = sc_tag_store_booter, + .kattr = __ATTR(booter, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_SILENT_BOOT, + .tshow = sc_tag_show_silent_boot, + .tstore = sc_tag_store_silent_boot, + .kattr = __ATTR(silent_boot, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, +}; + +static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct sc_attr *sc_attr; + const u8 *pld; + u16 pld_len; + + sc_attr = container_of(attr, typeof(*sc_attr), kattr); + + if (!sc_attr->pld_len) + return -ENOENT; + + pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! + pld_len = sc_attr->pld_len; + + return sc_attr->tshow(pld, pld_len, buf); +} + +static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + const struct sc_attr *sc_attr; + const u8 *pld; + u16 pld_len; + + if (!RB_SC_HAS_WRITE_SUPPORT) + return -EOPNOTSUPP; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + sc_attr = container_of(attr, typeof(*sc_attr), kattr); + + if (!sc_attr->tstore) + return -EOPNOTSUPP; + + if (!sc_attr->pld_len) + return -ENOENT; + + pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! + pld_len = sc_attr->pld_len; + + return sc_attr->tstore(pld, pld_len, buf, count); +} + +/* + * Shows the current buffer status: + * "clean": the buffer is in sync with the mtd data + * "dirty": the buffer is out of sync with the mtd data + */ +static ssize_t sc_commit_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const char *str; + char *out = buf; + u32 crc; + + read_lock(&sc_bufrwl); + crc = RB_SC_GETCRC(); + read_unlock(&sc_bufrwl); + + str = (crc) ? "clean" : "dirty"; + out += sprintf(out, "%s\n", str); + + return out - buf; +} + +/* + * Performs buffer flushing: + * This routine expects an input compatible with kstrtobool(). + * - a "false" input discards the current changes and reads data back from mtd. + * - a "true" input commits the current changes to mtd. + * If there is no pending changes, this routine is a no-op. + * Handling failures is left as an exercise to userspace. + */ +static ssize_t sc_commit_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct mtd_info *mtd; + struct erase_info ei; + size_t bytes_rw, ret = count; + bool flush; + u32 crc; + + if (!RB_SC_HAS_WRITE_SUPPORT) + return -EOPNOTSUPP; + + read_lock(&sc_bufrwl); + crc = RB_SC_GETCRC(); + read_unlock(&sc_bufrwl); + + if (crc) + return count; // NO-OP + + ret = kstrtobool(buf, &flush); + if (ret) + return ret; + + mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); // TODO allow override + if (IS_ERR(mtd)) + return -ENODEV; + + write_lock(&sc_bufrwl); + if (!flush) // reread + ret = mtd_read(mtd, 0, mtd->size, &bytes_rw, sc_buf); + else { // crc32 + commit + /* + * CRC32 is computed on the entire buffer, excluding the CRC + * value itself. CRC is already null when we reach this point, + * so we can compute the CRC32 on the buffer as is. + * The expected CRC32 is Ethernet FCS style, meaning the seed is + * ~0 and the final result is also bitflipped. + */ + + crc = ~crc32(~0, sc_buf, sc_buflen); + RB_SC_SETCRC(crc); + + /* + * The soft_config partition is assumed to be entirely contained + * in a single eraseblock. + */ + + ei.addr = 0; + ei.len = mtd->size; + ret = mtd_erase(mtd, &ei); + if (!ret) + ret = mtd_write(mtd, 0, mtd->size, &bytes_rw, sc_buf); + + /* + * Handling mtd_write() failure here is a tricky situation. The + * proposed approach is to let userspace deal with retrying, + * with the caveat that it must try to flush the buffer again as + * rereading the mtd contents could potentially read garbage. + * The rationale is: even if we keep a shadow buffer of the + * original content, there is no guarantee that we will ever be + * able to write it anyway. + * Regardless, it appears that RouterBOOT will ignore an invalid + * soft_config (including a completely wiped segment) and will + * write back factory defaults when it happens. + */ + } + write_unlock(&sc_bufrwl); + + put_mtd_device(mtd); + + if (ret) + goto mtdfail; + + if (bytes_rw != sc_buflen) { + ret = -EIO; + goto mtdfail; + } + + return count; + +mtdfail: + RB_SC_CLRCRC(); // mark buffer content as dirty/invalid + return ret; +} + +static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store); + +int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) +{ + size_t bytes_read, buflen; + const u8 *buf; + int i, ret; + u32 magic; + + sc_buf = NULL; + sc_kobj = NULL; + + ret = __get_mtd_device(mtd); + if (ret) + return -ENODEV; + + sc_buflen = mtd->size; + sc_buf = kmalloc(sc_buflen, GFP_KERNEL); + if (!sc_buf) { + __put_mtd_device(mtd); + return -ENOMEM; + } + + ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf); + __put_mtd_device(mtd); + + if (ret) + goto fail; + + if (bytes_read != sc_buflen) { + ret = -EIO; + goto fail; + } + + /* Check we have what we expect */ + magic = *(const u32 *)sc_buf; + if (RB_MAGIC_SOFT != magic) { + ret = -EINVAL; + goto fail; + } + + /* Skip magic and 32bit CRC located immediately after */ + buf = sc_buf + (sizeof(magic) + sizeof(u32)); + buflen = sc_buflen - (sizeof(magic) + sizeof(u32)); + + /* Populate sysfs */ + ret = -ENOMEM; + sc_kobj = kobject_create_and_add(RB_MTD_SOFT_CONFIG, rb_kobj); + if (!sc_kobj) + goto fail; + + rwlock_init(&sc_bufrwl); + + /* Locate and publish all known tags */ + for (i = 0; i < ARRAY_SIZE(sc_attrs); i++) { + ret = routerboot_tag_find(buf, buflen, sc_attrs[i].tag_id, + &sc_attrs[i].pld_ofs, &sc_attrs[i].pld_len); + if (ret) { + sc_attrs[i].pld_ofs = sc_attrs[i].pld_len = 0; + continue; + } + + /* Account for skipped magic and crc32 */ + sc_attrs[i].pld_ofs += sizeof(magic) + sizeof(u32); + + ret = sysfs_create_file(sc_kobj, &sc_attrs[i].kattr.attr); + if (ret) + pr_warn(RB_SC_PR_PFX "Could not create %s sysfs entry (%d)\n", + sc_attrs[i].kattr.attr.name, ret); + } + + /* Finally add the 'commit' attribute */ + if (RB_SC_HAS_WRITE_SUPPORT) { + ret = sysfs_create_file(sc_kobj, &sc_kattrcommit.attr); + if (ret) { + pr_err(RB_SC_PR_PFX "Could not create %s sysfs entry (%d), aborting!\n", + sc_kattrcommit.attr.name, ret); + goto sysfsfail; // required attribute + } + } + + pr_info("MikroTik RouterBOARD software configuration sysfs driver v" RB_SOFTCONFIG_VER "\n"); + + return 0; + +sysfsfail: + kobject_put(sc_kobj); + sc_kobj = NULL; +fail: + kfree(sc_buf); + sc_buf = NULL; + return ret; +} + +void rb_softconfig_exit(void) +{ + kobject_put(sc_kobj); + sc_kobj = NULL; + kfree(sc_buf); + sc_buf = NULL; +} diff --git a/drivers/platform/mikrotik/routerboot.c b/drivers/platform/mikrotik/routerboot.c new file mode 100644 index 000000000000..96f24609161b --- /dev/null +++ b/drivers/platform/mikrotik/routerboot.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot flash data. Common routines. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include "routerboot.h" + +static struct kobject *rb_kobj; + +/** + * routerboot_tag_find() - Locate a given tag in routerboot config data. + * @bufhead: the buffer to look into. Must start with a tag node. + * @buflen: size of bufhead + * @tag_id: the tag identifier to look for + * @pld_ofs: will be updated with tag payload offset in bufhead, if tag found + * @pld_len: will be updated with tag payload size, if tag found + * + * This incarnation of tag_find() does only that: it finds a specific routerboot + * tag node in the input buffer. Routerboot tag nodes are u32 values: + * - The low nibble is the tag identification number, + * - The high nibble is the tag payload length (node excluded) in bytes. + * The payload immediately follows the tag node. Tag nodes are 32bit-aligned. + * The returned pld_ofs will always be aligned. pld_len may not end on 32bit + * boundary (the only known case is when parsing ERD data). + * The nodes are cpu-endian on the flash media. The payload is cpu-endian when + * applicable. Tag nodes are not ordered (by ID) on flash. + * + * Return: 0 on success (tag found) or errno + */ +int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, + u16 *pld_ofs, u16 *pld_len) +{ + const u32 *datum, *bufend; + u32 node; + u16 id, len; + int ret; + + if (!bufhead || !tag_id) + return -EINVAL; + + ret = -ENOENT; + datum = (const u32 *)bufhead; + bufend = (const u32 *)(bufhead + buflen); + + while (datum < bufend) { + node = *datum++; + + /* Tag list ends with null node */ + if (!node) + break; + + id = node & 0xFFFF; + len = node >> 16; + + if (tag_id == id) { + if (datum >= bufend) + break; + + if (pld_ofs) + *pld_ofs = (u16)((u8 *)datum - bufhead); + if (pld_len) + *pld_len = len; + + ret = 0; + break; + } + + /* + * The only known situation where len may not end on 32bit + * boundary is within ERD data. Since we're only extracting + * one tag (the first and only one) from that data, we should + * never need to forcefully ALIGN(). Do it anyway, this is not a + * performance path. + */ + len = ALIGN(len, sizeof(*datum)); + datum += len / sizeof(*datum); + } + + return ret; +} + +/** + * routerboot_rle_decode() - Simple RLE (MikroTik variant) decoding routine. + * @in: input buffer to decode + * @inlen: size of in + * @out: output buffer to write decoded data to + * @outlen: pointer to out size when function is called, will be updated with + * size of decoded output on return + * + * MikroTik's variant of RLE operates as follows, considering a signed run byte: + * - positive run => classic RLE + * - negative run => the next - bytes must be copied verbatim + * The API is matched to the lzo1x routines for convenience. + * + * NB: The output buffer cannot overlap with the input buffer. + * + * Return: 0 on success or errno + */ +int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen) +{ + int ret, run, nbytes; // use native types for speed + u8 byte; + + if (!in || (inlen < 2) || !out) + return -EINVAL; + + ret = -ENOSPC; + nbytes = 0; + while (inlen >= 2) { + run = *in++; + inlen--; + + /* Verbatim copies */ + if (run & 0x80) { + /* Invert run byte sign */ + run = ~run & 0xFF; + run++; + + if (run > inlen) + goto fail; + + inlen -= run; + + nbytes += run; + if (nbytes > *outlen) + goto fail; + + /* Basic memcpy */ + while (run-- > 0) + *out++ = *in++; + } + /* Stream of half-words RLE: . run == 0 is ignored */ + else { + byte = *in++; + inlen--; + + nbytes += run; + if (nbytes > *outlen) + goto fail; + + while (run-- > 0) + *out++ = byte; + } + } + + ret = 0; +fail: + *outlen = nbytes; + return ret; +} + +static void routerboot_mtd_notifier_add(struct mtd_info *mtd) +{ + /* Currently routerboot is only known to live on NOR flash */ + if (mtd->type != MTD_NORFLASH) + return; + + /* + * We ignore the following return values and always register. + * These init() routines are designed so that their failed state is + * always manageable by the corresponding exit() calls. + * Notifier is called with MTD mutex held: use __get/__put variants. + * TODO: allow partition names override + */ + if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) + rb_hardconfig_init(rb_kobj, mtd); + else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) + rb_softconfig_init(rb_kobj, mtd); +} + +static void routerboot_mtd_notifier_remove(struct mtd_info *mtd) +{ + if (mtd->type != MTD_NORFLASH) + return; + + if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) + rb_hardconfig_exit(); + else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) + rb_softconfig_exit(); +} + +/* Note: using a notifier prevents qualifying init()/exit() functions with __init/__exit */ +static struct mtd_notifier routerboot_mtd_notifier = { + .add = routerboot_mtd_notifier_add, + .remove = routerboot_mtd_notifier_remove, +}; + +static int __init routerboot_init(void) +{ + rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj); + if (!rb_kobj) + return -ENOMEM; + + register_mtd_user(&routerboot_mtd_notifier); + + return 0; +} + +static void __exit routerboot_exit(void) +{ + unregister_mtd_user(&routerboot_mtd_notifier); + /* Exit routines are idempotent */ + rb_softconfig_exit(); + rb_hardconfig_exit(); + kobject_put(rb_kobj); // recursive afaict +} + +/* Common routines */ + +ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf) +{ + return scnprintf(buf, pld_len+1, "%s\n", pld); +} + +ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf) +{ + char *out = buf; + u32 *data; // cpu-endian + + /* Caller ensures pld_len > 0 */ + if (pld_len % sizeof(*data)) + return -EINVAL; + + data = (u32 *)pld; + + do { + out += sprintf(out, "0x%08x\n", *data); + data++; + } while ((pld_len -= sizeof(*data))); + + return out - buf; +} + +module_init(routerboot_init); +module_exit(routerboot_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MikroTik RouterBoot sysfs support"); +MODULE_AUTHOR("Thibaut VARENE"); diff --git a/drivers/platform/mikrotik/routerboot.h b/drivers/platform/mikrotik/routerboot.h new file mode 100644 index 000000000000..723f993eebe2 --- /dev/null +++ b/drivers/platform/mikrotik/routerboot.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common definitions for MikroTik RouterBoot data. + * + * Copyright (C) 2020 Thibaut VARÈNE + */ + + +#ifndef _ROUTERBOOT_H_ +#define _ROUTERBOOT_H_ + +#include + +// these magic values are stored in cpu-endianness on flash +#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) +#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) +#define RB_MAGIC_LZOR (('L') | ('Z' << 8) | ('O' << 16) | ('R' << 24)) +#define RB_MAGIC_LZ77 (('L' << 24) | ('Z' << 16) | ('7' << 8) | ('7')) +#define RB_MAGIC_ERD (('E' << 16) | ('R' << 8) | ('D')) + +#define RB_ART_SIZE 0x10000 + +#define RB_MTD_HARD_CONFIG "hard_config" +#define RB_MTD_SOFT_CONFIG "soft_config" + +int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len); +int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen); + +int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); +void rb_hardconfig_exit(void); + +int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); +void rb_softconfig_exit(void); + +ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf); +ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf); + +#endif /* _ROUTERBOOT_H_ */ diff --git a/drivers/ssb/fallback-sprom.c b/drivers/ssb/fallback-sprom.c new file mode 100644 index 000000000000..9c2511febe18 --- /dev/null +++ b/drivers/ssb/fallback-sprom.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * SSB Fallback SPROM Driver + * + * Copyright (C) 2020 Álvaro Fernández Rojas + * Copyright (C) 2014 Jonas Gorski + * Copyright (C) 2008 Maxime Bizon + * Copyright (C) 2008 Florian Fainelli + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "fallback-sprom.h" + +#define SSB_FBS_MAX_SIZE 440 + +/* Get the word-offset for a SSB_SPROM_XXX define. */ +#define SPOFF(offset) ((offset) / sizeof(u16)) +/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */ +#define SPEX16(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift)) +#define SPEX32(_outvar, _offset, _mask, _shift) \ + out->_outvar = ((((u32)in[SPOFF((_offset)+2)] << 16 | \ + in[SPOFF(_offset)]) & (_mask)) >> (_shift)) +#define SPEX(_outvar, _offset, _mask, _shift) \ + SPEX16(_outvar, _offset, _mask, _shift) + +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + +struct ssb_fbs { + struct device *dev; + struct list_head list; + struct ssb_sprom sprom; + u32 pci_bus; + u32 pci_dev; + bool devid_override; +}; + +static DEFINE_SPINLOCK(ssb_fbs_lock); +static struct list_head ssb_fbs_list = LIST_HEAD_INIT(ssb_fbs_list); + +int ssb_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +{ + struct ssb_fbs *pos; + u32 pci_bus, pci_dev; + + if (bus->bustype != SSB_BUSTYPE_PCI) + return -ENOENT; + + pci_bus = bus->host_pci->bus->number; + pci_dev = PCI_SLOT(bus->host_pci->devfn); + + list_for_each_entry(pos, &ssb_fbs_list, list) { + if (pos->pci_bus != pci_bus || + pos->pci_dev != pci_dev) + continue; + + if (pos->devid_override) + bus->host_pci->device = pos->sprom.dev_id; + + memcpy(out, &pos->sprom, sizeof(struct ssb_sprom)); + dev_info(pos->dev, "requested by [%x:%x]", + pos->pci_bus, pos->pci_dev); + + return 0; + } + + pr_err("unable to fill SPROM for [%x:%x]\n", pci_bus, pci_dev); + + return -EINVAL; +} + +static s8 sprom_extract_antgain(u8 sprom_revision, const u16 *in, u16 offset, + u16 mask, u16 shift) +{ + u16 v; + u8 gain; + + v = in[SPOFF(offset)]; + gain = (v & mask) >> shift; + if (gain == 0xFF) + gain = 2; /* If unset use 2dBm */ + if (sprom_revision == 1) { + /* Convert to Q5.2 */ + gain <<= 2; + } else { + /* Q5.2 Fractional part is stored in 0xC0 */ + gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); + } + + return (s8)gain; +} + +static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in) +{ + SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); + SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); + SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); + SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, + SSB_SPROM2_MAXP_A_LO_SHIFT); +} + +static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) +{ + SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); + SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, + SSB_SPROM1_ETHPHY_ET1A_SHIFT); + SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); + SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); + SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); + SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); + if (out->revision == 1) + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); + SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, + SSB_SPROM1_BINF_ANTA_SHIFT); + SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, + SSB_SPROM1_BINF_ANTBG_SHIFT); + SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0); + SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1, + SSB_SPROM1_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3, + SSB_SPROM1_GPIOB_P3_SHIFT); + SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A, + SSB_SPROM1_MAXPWR_A_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0); + SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A, + SSB_SPROM1_ITSSI_A_SHIFT); + SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); + SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); + + SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); + + /* Extract the antenna gain values. */ + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN, + SSB_SPROM1_AGAIN_BG, + SSB_SPROM1_AGAIN_BG_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN, + SSB_SPROM1_AGAIN_A, + SSB_SPROM1_AGAIN_A_SHIFT); + if (out->revision >= 2) + sprom_extract_r23(out, in); +} + +/* Revs 4 5 and 8 have partially shared layout */ +static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in) +{ + SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, + SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT); + SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01, + SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT); + SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23, + SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT); + SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23, + SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT); + + SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01, + SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT); + SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01, + SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT); + SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23, + SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT); + SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23, + SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT); + + SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01, + SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT); + SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01, + SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT); + SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23, + SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT); + SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23, + SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT); + + SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01, + SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT); + SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01, + SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT); + SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23, + SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT); + SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23, + SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT); +} + +static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) +{ + static const u16 pwr_info_offset[] = { + SSB_SPROM4_PWR_INFO_CORE0, SSB_SPROM4_PWR_INFO_CORE1, + SSB_SPROM4_PWR_INFO_CORE2, SSB_SPROM4_PWR_INFO_CORE3 + }; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != + ARRAY_SIZE(out->core_pwr_info)); + + SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); + SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, + SSB_SPROM4_ETHPHY_ET1A_SHIFT); + SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); + SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); + if (out->revision == 4) { + SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); + SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); + SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); + SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); + } else { + SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); + SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); + SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); + SPEX(boardflags2_hi, SSB_SPROM5_BFL2HI, 0xFFFF, 0); + } + SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, + SSB_SPROM4_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, + SSB_SPROM4_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, + SSB_SPROM4_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, + SSB_SPROM4_ITSSI_A_SHIFT); + if (out->revision == 4) { + SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, + SSB_SPROM4_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, + SSB_SPROM4_GPIOB_P3_SHIFT); + } else { + SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, + SSB_SPROM5_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, + SSB_SPROM5_GPIOB_P3_SHIFT); + } + + /* Extract the antenna gain values. */ + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN0, + SSB_SPROM4_AGAIN0_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN1, + SSB_SPROM4_AGAIN1_SHIFT); + out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN2, + SSB_SPROM4_AGAIN2_SHIFT); + out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, + SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN3, + SSB_SPROM4_AGAIN3_SHIFT); + + /* Extract cores power info info */ + for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { + u16 o = pwr_info_offset[i]; + + SPEX(core_pwr_info[i].itssi_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, + SSB_SPROM4_2G_ITSSI, SSB_SPROM4_2G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SPROM4_2G_MAXP_ITSSI, + SSB_SPROM4_2G_MAXP, 0); + + SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SPROM4_2G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SPROM4_2G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SPROM4_2G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[3], o + SSB_SPROM4_2G_PA_3, ~0, 0); + + SPEX(core_pwr_info[i].itssi_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, + SSB_SPROM4_5G_ITSSI, SSB_SPROM4_5G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SPROM4_5G_MAXP_ITSSI, + SSB_SPROM4_5G_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM4_5GHL_MAXP, + SSB_SPROM4_5GH_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM4_5GHL_MAXP, + SSB_SPROM4_5GL_MAXP, SSB_SPROM4_5GL_MAXP_SHIFT); + + SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SPROM4_5GL_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SPROM4_5GL_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SPROM4_5GL_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[3], o + SSB_SPROM4_5GL_PA_3, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SPROM4_5G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SPROM4_5G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SPROM4_5G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[3], o + SSB_SPROM4_5G_PA_3, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SPROM4_5GH_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SPROM4_5GH_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SPROM4_5GH_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[3], o + SSB_SPROM4_5GH_PA_3, ~0, 0); + } + + sprom_extract_r458(out, in); + + /* TODO - get remaining rev 4 stuff needed */ +} + +static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) +{ + int i; + u16 o; + static const u16 pwr_info_offset[] = { + SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1, + SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3 + }; + BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != + ARRAY_SIZE(out->core_pwr_info)); + + SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); + SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); + SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); + SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); + SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, 0xFFFF, 0); + SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, + SSB_SPROM8_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, + SSB_SPROM8_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, + SSB_SPROM8_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, + SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); + SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, + SSB_SPROM8_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, + SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, 0); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + SPEX(pa0b0, SSB_SPROM8_PA0B0, 0xFFFF, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, 0xFFFF, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, 0xFFFF, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, 0xFFFF, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, 0xFFFF, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, 0xFFFF, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, 0xFFFF, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, 0xFFFF, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, 0xFFFF, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, 0xFFFF, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, 0xFFFF, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, 0xFFFF, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, 0xFFFF, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, 0xFFFFFFFF, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, 0xFFFFFFFF, 0); + + /* Extract the antenna gain values. */ + out->antenna_gain.a0 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, + SSB_SPROM8_AGAIN0_SHIFT); + out->antenna_gain.a1 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, + SSB_SPROM8_AGAIN1_SHIFT); + out->antenna_gain.a2 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, + SSB_SPROM8_AGAIN2_SHIFT); + out->antenna_gain.a3 = sprom_extract_antgain(out->revision, in, + SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, + SSB_SPROM8_AGAIN3_SHIFT); + + /* Extract cores power info info */ + for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { + o = pwr_info_offset[i]; + SPEX(core_pwr_info[i].itssi_2g, o + SSB_SROM8_2G_MAXP_ITSSI, + SSB_SPROM8_2G_ITSSI, SSB_SPROM8_2G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_2g, o + SSB_SROM8_2G_MAXP_ITSSI, + SSB_SPROM8_2G_MAXP, 0); + + SPEX(core_pwr_info[i].pa_2g[0], o + SSB_SROM8_2G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[1], o + SSB_SROM8_2G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_2g[2], o + SSB_SROM8_2G_PA_2, ~0, 0); + + SPEX(core_pwr_info[i].itssi_5g, o + SSB_SROM8_5G_MAXP_ITSSI, + SSB_SPROM8_5G_ITSSI, SSB_SPROM8_5G_ITSSI_SHIFT); + SPEX(core_pwr_info[i].maxpwr_5g, o + SSB_SROM8_5G_MAXP_ITSSI, + SSB_SPROM8_5G_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gh, o + SSB_SPROM8_5GHL_MAXP, + SSB_SPROM8_5GH_MAXP, 0); + SPEX(core_pwr_info[i].maxpwr_5gl, o + SSB_SPROM8_5GHL_MAXP, + SSB_SPROM8_5GL_MAXP, SSB_SPROM8_5GL_MAXP_SHIFT); + + SPEX(core_pwr_info[i].pa_5gl[0], o + SSB_SROM8_5GL_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[1], o + SSB_SROM8_5GL_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gl[2], o + SSB_SROM8_5GL_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[0], o + SSB_SROM8_5G_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[1], o + SSB_SROM8_5G_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5g[2], o + SSB_SROM8_5G_PA_2, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[0], o + SSB_SROM8_5GH_PA_0, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[1], o + SSB_SROM8_5GH_PA_1, ~0, 0); + SPEX(core_pwr_info[i].pa_5gh[2], o + SSB_SROM8_5GH_PA_2, ~0, 0); + } + + /* Extract FEM info */ + SPEX(fem.ghz2.tssipos, SSB_SPROM8_FEM2G, + SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); + SPEX(fem.ghz2.extpa_gain, SSB_SPROM8_FEM2G, + SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); + SPEX(fem.ghz2.pdet_range, SSB_SPROM8_FEM2G, + SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); + SPEX(fem.ghz2.tr_iso, SSB_SPROM8_FEM2G, + SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); + SPEX(fem.ghz2.antswlut, SSB_SPROM8_FEM2G, + SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(fem.ghz5.tssipos, SSB_SPROM8_FEM5G, + SSB_SROM8_FEM_TSSIPOS, SSB_SROM8_FEM_TSSIPOS_SHIFT); + SPEX(fem.ghz5.extpa_gain, SSB_SPROM8_FEM5G, + SSB_SROM8_FEM_EXTPA_GAIN, SSB_SROM8_FEM_EXTPA_GAIN_SHIFT); + SPEX(fem.ghz5.pdet_range, SSB_SPROM8_FEM5G, + SSB_SROM8_FEM_PDET_RANGE, SSB_SROM8_FEM_PDET_RANGE_SHIFT); + SPEX(fem.ghz5.tr_iso, SSB_SPROM8_FEM5G, + SSB_SROM8_FEM_TR_ISO, SSB_SROM8_FEM_TR_ISO_SHIFT); + SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, + SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); + sprom_extract_r458(out, in); + + /* TODO - get remaining rev 8 stuff needed */ +} + +static int sprom_extract(struct ssb_fbs *priv, const u16 *in, u16 size) +{ + struct ssb_sprom *out = &priv->sprom; + + memset(out, 0, sizeof(*out)); + + out->revision = in[size - 1] & 0x00FF; + + switch (out->revision) { + case 1: + case 2: + case 3: + sprom_extract_r123(out, in); + break; + case 4: + case 5: + sprom_extract_r45(out, in); + break; + case 8: + sprom_extract_r8(out, in); + break; + default: + dev_warn(priv->dev, + "Unsupported SPROM revision %d detected." + " Will extract v1\n", + out->revision); + out->revision = 1; + sprom_extract_r123(out, in); + } + + if (out->boardflags_lo == 0xFFFF) + out->boardflags_lo = 0; /* per specs */ + if (out->boardflags_hi == 0xFFFF) + out->boardflags_hi = 0; /* per specs */ + + return 0; +} + +static void ssb_fbs_fixup(struct ssb_fbs *priv, u16 *sprom) +{ + struct device_node *node = priv->dev->of_node; + u32 fixups, off, val; + int i = 0; + + if (!of_get_property(node, "brcm,sprom-fixups", &fixups)) + return; + + fixups /= sizeof(u32); + + dev_info(priv->dev, "patching SPROM with %u fixups...\n", fixups >> 1); + + while (i < fixups) { + if (of_property_read_u32_index(node, "brcm,sprom-fixups", + i++, &off)) { + dev_err(priv->dev, "error reading fixup[%u] offset\n", + i - 1); + return; + } + + if (of_property_read_u32_index(node, "brcm,sprom-fixups", + i++, &val)) { + dev_err(priv->dev, "error reading fixup[%u] value\n", + i - 1); + return; + } + + dev_dbg(priv->dev, "fixup[%d]=0x%04x\n", off, val); + + sprom[off] = val; + } +} + +static bool sprom_override_devid(struct ssb_fbs *priv, struct ssb_sprom *out, + const u16 *in) +{ + SPEX(dev_id, SSB_SPROM1_PID, 0xFFFF, 0); + return !!out->dev_id; +} + +static int ssb_fbs_set(struct ssb_fbs *priv, struct device_node *node) +{ + struct ssb_sprom *sprom = &priv->sprom; + const struct firmware *fw; + const char *sprom_name; + int err; + + if (of_property_read_string(node, "brcm,sprom", &sprom_name)) + sprom_name = NULL; + + if (sprom_name) { + err = request_firmware_direct(&fw, sprom_name, priv->dev); + if (err) + dev_err(priv->dev, "%s load error\n", sprom_name); + } else { + err = -ENOENT; + } + + if (err) { + sprom->revision = 0x02; + sprom->board_rev = 0x0017; + sprom->country_code = 0x00; + sprom->ant_available_bg = 0x03; + sprom->pa0b0 = 0x15ae; + sprom->pa0b1 = 0xfa85; + sprom->pa0b2 = 0xfe8d; + sprom->pa1b0 = 0xffff; + sprom->pa1b1 = 0xffff; + sprom->pa1b2 = 0xffff; + sprom->gpio0 = 0xff; + sprom->gpio1 = 0xff; + sprom->gpio2 = 0xff; + sprom->gpio3 = 0xff; + sprom->maxpwr_bg = 0x4c; + sprom->itssi_bg = 0x00; + sprom->boardflags_lo = 0x2848; + sprom->boardflags_hi = 0x0000; + priv->devid_override = false; + + dev_warn(priv->dev, "using basic SPROM\n"); + } else { + size_t size = min(fw->size, (size_t) SSB_FBS_MAX_SIZE); + u16 tmp_sprom[SSB_FBS_MAX_SIZE >> 1]; + u32 i, j; + + for (i = 0, j = 0; i < size; i += 2, j++) + tmp_sprom[j] = (fw->data[i] << 8) | fw->data[i + 1]; + + release_firmware(fw); + ssb_fbs_fixup(priv, tmp_sprom); + sprom_extract(priv, tmp_sprom, size >> 1); + + priv->devid_override = sprom_override_devid(priv, sprom, + tmp_sprom); + } + + return 0; +} + +static int ssb_fbs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct ssb_fbs *priv; + unsigned long flags; + u8 mac[ETH_ALEN]; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + ssb_fbs_set(priv, node); + + of_property_read_u32(node, "pci-bus", &priv->pci_bus); + of_property_read_u32(node, "pci-dev", &priv->pci_dev); + + of_get_mac_address(node, mac); + if (is_valid_ether_addr(mac)) { + dev_info(dev, "mtd mac %pM\n", mac); + } else { + eth_random_addr(mac); + dev_info(dev, "random mac %pM\n", mac); + } + + memcpy(priv->sprom.il0mac, mac, ETH_ALEN); + memcpy(priv->sprom.et0mac, mac, ETH_ALEN); + memcpy(priv->sprom.et1mac, mac, ETH_ALEN); + memcpy(priv->sprom.et2mac, mac, ETH_ALEN); + + spin_lock_irqsave(&ssb_fbs_lock, flags); + list_add(&priv->list, &ssb_fbs_list); + spin_unlock_irqrestore(&ssb_fbs_lock, flags); + + dev_info(dev, "registered SPROM for [%x:%x]\n", + priv->pci_bus, priv->pci_dev); + + return 0; +} + +static const struct of_device_id ssb_fbs_of_match[] = { + { .compatible = "brcm,ssb-sprom", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ssb_fbs_of_match); + +static struct platform_driver ssb_fbs_driver = { + .probe = ssb_fbs_probe, + .driver = { + .name = "ssb-sprom", + .of_match_table = ssb_fbs_of_match, + }, +}; + +int __init ssb_fbs_register(void) +{ + return platform_driver_register(&ssb_fbs_driver); +} diff --git a/drivers/ssb/fallback-sprom.h b/drivers/ssb/fallback-sprom.h new file mode 100644 index 000000000000..3966a18b86de --- /dev/null +++ b/drivers/ssb/fallback-sprom.h @@ -0,0 +1,7 @@ +#ifndef _FALLBACK_SPROM_H +#define _FALLBACK_SPROM_H + +int __init ssb_fbs_register(void); +int ssb_get_fallback_sprom(struct ssb_bus *dev, struct ssb_sprom *out); + +#endif /* _FALLBACK_SPROM_H */ diff --git a/include/dt-bindings/mtd/partitions/uimage.h b/include/dt-bindings/mtd/partitions/uimage.h new file mode 100644 index 000000000000..43d5f7b5da87 --- /dev/null +++ b/include/dt-bindings/mtd/partitions/uimage.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Based on image.h from U-Boot which is + * (C) Copyright 2008 Semihalf + * (C) Copyright 2000-2005 Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#ifndef __UIMAGE_H__ +#define __UIMAGE_H__ + +/* + * Operating System Codes + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ +#define IH_OS_INTEGRITY 21 /* INTEGRITY */ +#define IH_OS_OSE 22 /* OSE */ +#define IH_OS_PLAN9 23 /* Plan 9 */ +#define IH_OS_OPENRTOS 24 /* OpenRTOS */ +#define IH_OS_ARM_TRUSTED_FIRMWARE 25 /* ARM Trusted Firmware */ +#define IH_OS_TEE 26 /* Trusted Execution Environment */ +#define IH_OS_OPENSBI 27 /* RISC-V OpenSBI */ +#define IH_OS_EFI 28 /* EFI Firmware (e.g. GRUB2) */ + +/* + * CPU Architecture Codes (supported by Linux) + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_ARCH_INVALID 0 /* Invalid CPU */ +#define IH_ARCH_ALPHA 1 /* Alpha */ +#define IH_ARCH_ARM 2 /* ARM */ +#define IH_ARCH_I386 3 /* Intel x86 */ +#define IH_ARCH_IA64 4 /* IA64 */ +#define IH_ARCH_MIPS 5 /* MIPS */ +#define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ +#define IH_ARCH_PPC 7 /* PowerPC */ +#define IH_ARCH_S390 8 /* IBM S390 */ +#define IH_ARCH_SH 9 /* SuperH */ +#define IH_ARCH_SPARC 10 /* Sparc */ +#define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ +#define IH_ARCH_M68K 12 /* M68K */ +#define IH_ARCH_NIOS 13 /* Nios-32 */ +#define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ +#define IH_ARCH_NIOS2 15 /* Nios-II */ +#define IH_ARCH_BLACKFIN 16 /* Blackfin */ +#define IH_ARCH_AVR32 17 /* AVR32 */ +#define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ +#define IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */ +#define IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */ +#define IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */ +#define IH_ARCH_ARM64 22 /* ARM64 */ +#define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ +#define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ +#define IH_ARCH_XTENSA 25 /* Xtensa */ +#define IH_ARCH_RISCV 26 /* RISC-V */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ +#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ +#define IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */ +#define IH_TYPE_IMXIMAGE 10 /* Freescale IMXBoot Image */ +#define IH_TYPE_UBLIMAGE 11 /* Davinci UBL Image */ +#define IH_TYPE_OMAPIMAGE 12 /* TI OMAP Config Header Image */ +#define IH_TYPE_AISIMAGE 13 /* TI Davinci AIS Image */ + /* OS Kernel Image, can run from any load address */ +#define IH_TYPE_KERNEL_NOLOAD 14 +#define IH_TYPE_PBLIMAGE 15 /* Freescale PBL Boot Image */ +#define IH_TYPE_MXSIMAGE 16 /* Freescale MXSBoot Image */ +#define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image */ +#define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ +#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA CV/AV Preloader */ +#define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */ +#define IH_TYPE_LPC32XXIMAGE 21 /* x86 setup.bin Image */ +#define IH_TYPE_LOADABLE 22 /* A list of typeless images */ +#define IH_TYPE_RKIMAGE 23 /* Rockchip Boot Image */ +#define IH_TYPE_RKSD 24 /* Rockchip SD card */ +#define IH_TYPE_RKSPI 25 /* Rockchip SPI image */ +#define IH_TYPE_ZYNQIMAGE 26 /* Xilinx Zynq Boot Image */ +#define IH_TYPE_ZYNQMPIMAGE 27 /* Xilinx ZynqMP Boot Image */ +#define IH_TYPE_ZYNQMPBIF 28 /* Xilinx ZynqMP Boot Image (bif) */ +#define IH_TYPE_FPGA 29 /* FPGA Image */ +#define IH_TYPE_VYBRIDIMAGE 30 /* VYBRID .vyb Image */ +#define IH_TYPE_TEE 31 /* Trusted Execution Environment OS Image */ +#define IH_TYPE_FIRMWARE_IVT 32 /* Firmware Image with HABv4 IVT */ +#define IH_TYPE_PMMC 33 /* TI Power Management Micro-Controller Firmware */ +#define IH_TYPE_STM32IMAGE 34 /* STMicroelectronics STM32 Image */ +#define IH_TYPE_SOCFPGAIMAGE_V1 35 /* Altera SOCFPGA A10 Preloader */ +#define IH_TYPE_MTKIMAGE 36 /* MediaTek BootROM loadable Image */ +#define IH_TYPE_IMX8MIMAGE 37 /* Freescale IMX8MBoot Image */ +#define IH_TYPE_IMX8IMAGE 38 /* Freescale IMX8Boot Image */ +#define IH_TYPE_COPRO 39 /* Coprocessor Image for remoteproc*/ + + +/* + * Compression Types + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ +#define IH_COMP_LZMA 3 /* lzma Compression Used */ +#define IH_COMP_LZO 4 /* lzo Compression Used */ +#define IH_COMP_LZ4 5 /* lz4 Compression Used */ + + +#define LZ4F_MAGIC 0x184D2204 /* LZ4 Magic Number */ +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +/* + * Magic values specific to "openwrt,uimage" partitions + */ +#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */ +#define FW_EDIMAX_OFFSET 20 /* Edimax Firmware Offset */ +#define FW_MAGIC_EDIMAX 0x43535953 /* Edimax Firmware Magic Number */ + +#endif /* __UIMAGE_H__ */ diff --git a/include/linux/ar8216_platform.h b/include/linux/ar8216_platform.h new file mode 100644 index 000000000000..fff05ffb5c16 --- /dev/null +++ b/include/linux/ar8216_platform.h @@ -0,0 +1,134 @@ +/* + * AR8216 switch driver platform data + * + * Copyright (C) 2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef AR8216_PLATFORM_H +#define AR8216_PLATFORM_H + +enum ar8327_pad_mode { + AR8327_PAD_NC = 0, + AR8327_PAD_MAC2MAC_MII, + AR8327_PAD_MAC2MAC_GMII, + AR8327_PAD_MAC_SGMII, + AR8327_PAD_MAC2PHY_MII, + AR8327_PAD_MAC2PHY_GMII, + AR8327_PAD_MAC_RGMII, + AR8327_PAD_PHY_GMII, + AR8327_PAD_PHY_RGMII, + AR8327_PAD_PHY_MII, +}; + +enum ar8327_clk_delay_sel { + AR8327_CLK_DELAY_SEL0 = 0, + AR8327_CLK_DELAY_SEL1, + AR8327_CLK_DELAY_SEL2, + AR8327_CLK_DELAY_SEL3, +}; + +struct ar8327_pad_cfg { + enum ar8327_pad_mode mode; + bool rxclk_sel; + bool txclk_sel; + bool pipe_rxclk_sel; + bool txclk_delay_en; + bool rxclk_delay_en; + bool sgmii_delay_en; + enum ar8327_clk_delay_sel txclk_delay_sel; + enum ar8327_clk_delay_sel rxclk_delay_sel; + bool mac06_exchange_dis; +}; + +enum ar8327_port_speed { + AR8327_PORT_SPEED_10 = 0, + AR8327_PORT_SPEED_100, + AR8327_PORT_SPEED_1000, +}; + +struct ar8327_port_cfg { + int force_link:1; + enum ar8327_port_speed speed; + int txpause:1; + int rxpause:1; + int duplex:1; +}; + +struct ar8327_sgmii_cfg { + u32 sgmii_ctrl; + bool serdes_aen; +}; + +struct ar8327_led_cfg { + u32 led_ctrl0; + u32 led_ctrl1; + u32 led_ctrl2; + u32 led_ctrl3; + bool open_drain; +}; + +enum ar8327_led_num { + AR8327_LED_PHY0_0 = 0, + AR8327_LED_PHY0_1, + AR8327_LED_PHY0_2, + AR8327_LED_PHY1_0, + AR8327_LED_PHY1_1, + AR8327_LED_PHY1_2, + AR8327_LED_PHY2_0, + AR8327_LED_PHY2_1, + AR8327_LED_PHY2_2, + AR8327_LED_PHY3_0, + AR8327_LED_PHY3_1, + AR8327_LED_PHY3_2, + AR8327_LED_PHY4_0, + AR8327_LED_PHY4_1, + AR8327_LED_PHY4_2, +}; + +enum ar8327_led_mode { + AR8327_LED_MODE_HW = 0, + AR8327_LED_MODE_SW, +}; + +struct ar8327_led_info { + const char *name; + const char *default_trigger; + bool active_low; + enum ar8327_led_num led_num; + enum ar8327_led_mode mode; + struct fwnode_handle *fwnode; +}; + +#define AR8327_LED_INFO(_led, _mode, _name) { \ + .name = (_name), \ + .led_num = AR8327_LED_ ## _led, \ + .mode = AR8327_LED_MODE_ ## _mode \ +} + +struct ar8327_platform_data { + struct ar8327_pad_cfg *pad0_cfg; + struct ar8327_pad_cfg *pad5_cfg; + struct ar8327_pad_cfg *pad6_cfg; + struct ar8327_sgmii_cfg *sgmii_cfg; + struct ar8327_port_cfg port0_cfg; + struct ar8327_port_cfg port6_cfg; + struct ar8327_led_cfg *led_cfg; + + int (*get_port_link)(unsigned port); + + unsigned num_leds; + const struct ar8327_led_info *leds; +}; + +#endif /* AR8216_PLATFORM_H */ + diff --git a/include/linux/ath5k_platform.h b/include/linux/ath5k_platform.h new file mode 100644 index 000000000000..ec8522452879 --- /dev/null +++ b/include/linux/ath5k_platform.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * Copyright (c) 2010 Daniel Golle + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_ATH5K_PLATFORM_H +#define _LINUX_ATH5K_PLATFORM_H + +#define ATH5K_PLAT_EEP_MAX_WORDS 2048 + +struct ath5k_platform_data { + u16 *eeprom_data; + u8 *macaddr; +}; + +#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/include/linux/mfd/airoha-an8855-mfd.h b/include/linux/mfd/airoha-an8855-mfd.h new file mode 100644 index 000000000000..56061566a079 --- /dev/null +++ b/include/linux/mfd/airoha-an8855-mfd.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MFD driver for Airoha AN8855 Switch + */ +#ifndef _LINUX_INCLUDE_MFD_AIROHA_AN8855_MFD_H +#define _LINUX_INCLUDE_MFD_AIROHA_AN8855_MFD_H + +#include + +/* MII Registers */ +#define AN8855_PHY_SELECT_PAGE 0x1f +#define AN8855_PHY_PAGE GENMASK(2, 0) +#define AN8855_PHY_PAGE_STANDARD FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x0) +#define AN8855_PHY_PAGE_EXTENDED_1 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x1) +#define AN8855_PHY_PAGE_EXTENDED_4 FIELD_PREP_CONST(AN8855_PHY_PAGE, 0x4) + +/* MII Registers Page 4 */ +#define AN8855_PBUS_MODE 0x10 +#define AN8855_PBUS_MODE_ADDR_FIXED 0x0 +#define AN8855_PBUS_MODE_ADDR_INCR BIT(15) +#define AN8855_PBUS_WR_ADDR_HIGH 0x11 +#define AN8855_PBUS_WR_ADDR_LOW 0x12 +#define AN8855_PBUS_WR_DATA_HIGH 0x13 +#define AN8855_PBUS_WR_DATA_LOW 0x14 +#define AN8855_PBUS_RD_ADDR_HIGH 0x15 +#define AN8855_PBUS_RD_ADDR_LOW 0x16 +#define AN8855_PBUS_RD_DATA_HIGH 0x17 +#define AN8855_PBUS_RD_DATA_LOW 0x18 + +struct an8855_mfd_priv { + struct device *dev; + struct mii_bus *bus; + + unsigned int switch_addr; + u16 current_page; +}; + +int an8855_mii_set_page(struct an8855_mfd_priv *priv, u8 phy_id, + u8 page); + +#endif diff --git a/include/linux/mtd/mtk_bmt.h b/include/linux/mtd/mtk_bmt.h new file mode 100644 index 000000000000..cbb6d04d8952 --- /dev/null +++ b/include/linux/mtd/mtk_bmt.h @@ -0,0 +1,18 @@ +#ifndef __MTK_BMT_H +#define __MTK_BMT_H + +#ifdef CONFIG_MTD_NAND_MTK_BMT +int mtk_bmt_attach(struct mtd_info *mtd); +void mtk_bmt_detach(struct mtd_info *mtd); +#else +static inline int mtk_bmt_attach(struct mtd_info *mtd) +{ + return 0; +} + +static inline void mtk_bmt_detach(struct mtd_info *mtd) +{ +} +#endif + +#endif diff --git a/include/linux/myloader.h b/include/linux/myloader.h new file mode 100644 index 000000000000..d89e415fba6c --- /dev/null +++ b/include/linux/myloader.h @@ -0,0 +1,121 @@ +/* + * Compex's MyLoader specific definitions + * + * Copyright (C) 2006-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#ifndef _MYLOADER_H_ +#define _MYLOADER_H_ + +/* Myloader specific magic numbers */ +#define MYLO_MAGIC_SYS_PARAMS 0x20021107 +#define MYLO_MAGIC_PARTITIONS 0x20021103 +#define MYLO_MAGIC_BOARD_PARAMS 0x20021103 + +/* Vendor ID's (seems to be same as the PCI vendor ID's) */ +#define VENID_COMPEX 0x11F6 + +/* Devices based on the ADM5120 */ +#define DEVID_COMPEX_NP27G 0x0078 +#define DEVID_COMPEX_NP28G 0x044C +#define DEVID_COMPEX_NP28GHS 0x044E +#define DEVID_COMPEX_WP54Gv1C 0x0514 +#define DEVID_COMPEX_WP54G 0x0515 +#define DEVID_COMPEX_WP54AG 0x0546 +#define DEVID_COMPEX_WPP54AG 0x0550 +#define DEVID_COMPEX_WPP54G 0x0555 + +/* Devices based on the Atheros AR2317 */ +#define DEVID_COMPEX_NP25G 0x05E6 +#define DEVID_COMPEX_WPE53G 0x05DC + +/* Devices based on the Atheros AR71xx */ +#define DEVID_COMPEX_WP543 0x0640 +#define DEVID_COMPEX_WPE72 0x0672 + +/* Devices based on the IXP422 */ +#define DEVID_COMPEX_WP18 0x047E +#define DEVID_COMPEX_NP18A 0x0489 + +/* Other devices */ +#define DEVID_COMPEX_NP26G8M 0x03E8 +#define DEVID_COMPEX_NP26G16M 0x03E9 + +struct mylo_partition { + uint16_t flags; /* partition flags */ + uint16_t type; /* type of the partition */ + uint32_t addr; /* relative address of the partition from the + flash start */ + uint32_t size; /* size of the partition in bytes */ + uint32_t param; /* if this is the active partition, the + MyLoader load code to this address */ +}; + +#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, + * MyLoader loads firmware from here */ +#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ +#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ +#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM + * before decompression */ +#define PARTITION_FLAG_LZMA 0x0100 /* partition data compressed by LZMA */ +#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ + +#define PARTITION_TYPE_FREE 0 +#define PARTITION_TYPE_USED 1 + +#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the + partition table */ + +struct mylo_partition_table { + uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ + uint32_t res0; /* unknown/unused */ + uint32_t res1; /* unknown/unused */ + uint32_t res2; /* unknown/unused */ + struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; +}; + +struct mylo_partition_header { + uint32_t len; /* length of the partition data */ + uint32_t crc; /* CRC value of the partition data */ +}; + +struct mylo_system_params { + uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t mylo_ver; + uint16_t vid; /* Vendor ID */ + uint16_t did; /* Device ID */ + uint16_t svid; /* Sub Vendor ID */ + uint16_t sdid; /* Sub Device ID */ + uint32_t rev; /* device revision */ + uint32_t fwhi; + uint32_t fwlo; + uint32_t tftp_addr; + uint32_t prog_start; + uint32_t flash_size; /* size of boot FLASH in bytes */ + uint32_t dram_size; /* size of onboard RAM in bytes */ +}; + +struct mylo_eth_addr { + uint8_t mac[6]; + uint8_t csum[2]; +}; + +#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address + in the board parameters */ + +struct mylo_board_params { + uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t res2; + struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; +}; + +#endif /* _MYLOADER_H_*/ diff --git a/include/linux/platform_data/adm6996-gpio.h b/include/linux/platform_data/adm6996-gpio.h new file mode 100644 index 000000000000..d5af9bbf6e55 --- /dev/null +++ b/include/linux/platform_data/adm6996-gpio.h @@ -0,0 +1,29 @@ +/* + * ADM6996 GPIO platform data + * + * Copyright (C) 2013 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#ifndef __PLATFORM_ADM6996_GPIO_H +#define __PLATFORM_ADM6996_GPIO_H + +#include + +enum adm6996_model { + ADM6996FC = 1, + ADM6996M = 2, + ADM6996L = 3, +}; + +struct adm6996_gpio_platform_data { + u8 eecs; + u8 eesk; + u8 eedi; + enum adm6996_model model; +}; + +#endif diff --git a/include/linux/routerboot.h b/include/linux/routerboot.h new file mode 100644 index 000000000000..3cda858cf9c2 --- /dev/null +++ b/include/linux/routerboot.h @@ -0,0 +1,106 @@ +/* + * Mikrotik's RouterBOOT definitions + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#ifndef _ROUTERBOOT_H +#define _ROUTERBOOT_H + +#define RB_MAC_SIZE 6 + +/* + * Magic numbers + */ +#define RB_MAGIC_HARD 0x64726148 /* "Hard" */ +#define RB_MAGIC_SOFT 0x74666F53 /* "Soft" */ +#define RB_MAGIC_DAWN 0x6E776144 /* "Dawn" */ + +#define RB_ID_TERMINATOR 0 + +/* + * ID values for Hardware settings + */ +#define RB_ID_HARD_01 1 +#define RB_ID_HARD_02 2 +#define RB_ID_FLASH_INFO 3 +#define RB_ID_MAC_ADDRESS_PACK 4 +#define RB_ID_BOARD_NAME 5 +#define RB_ID_BIOS_VERSION 6 +#define RB_ID_HARD_07 7 +#define RB_ID_SDRAM_TIMINGS 8 +#define RB_ID_DEVICE_TIMINGS 9 +#define RB_ID_SOFTWARE_ID 10 +#define RB_ID_SERIAL_NUMBER 11 +#define RB_ID_HARD_12 12 +#define RB_ID_MEMORY_SIZE 13 +#define RB_ID_MAC_ADDRESS_COUNT 14 +#define RB_ID_HW_OPTIONS 21 +#define RB_ID_WLAN_DATA 22 + +/* + * ID values for Software settings + */ +#define RB_ID_UART_SPEED 1 +#define RB_ID_BOOT_DELAY 2 +#define RB_ID_BOOT_DEVICE 3 +#define RB_ID_BOOT_KEY 4 +#define RB_ID_CPU_MODE 5 +#define RB_ID_FW_VERSION 6 +#define RB_ID_SOFT_07 7 +#define RB_ID_SOFT_08 8 +#define RB_ID_BOOT_PROTOCOL 9 +#define RB_ID_SOFT_10 10 +#define RB_ID_SOFT_11 11 + +/* + * UART_SPEED values + */ +#define RB_UART_SPEED_115200 0 +#define RB_UART_SPEED_57600 1 +#define RB_UART_SPEED_38400 2 +#define RB_UART_SPEED_19200 3 +#define RB_UART_SPEED_9600 4 +#define RB_UART_SPEED_4800 5 +#define RB_UART_SPEED_2400 6 +#define RB_UART_SPEED_1200 7 + +/* + * BOOT_DELAY values + */ +#define RB_BOOT_DELAY_0SEC 0 +#define RB_BOOT_DELAY_1SEC 1 +#define RB_BOOT_DELAY_2SEC 2 + +/* + * BOOT_DEVICE values + */ +#define RB_BOOT_DEVICE_ETHER 0 +#define RB_BOOT_DEVICE_NANDETH 1 +#define RB_BOOT_DEVICE_ETHONCE 2 +#define RB_BOOT_DEVICE_NANDONLY 3 + +/* + * BOOT_KEY values + */ +#define RB_BOOT_KEY_ANY 0 +#define RB_BOOT_KEY_DEL 1 + +/* + * CPU_MODE values + */ +#define RB_CPU_MODE_POWERSAVE 0 +#define RB_CPU_MODE_REGULAR 1 + +/* + * BOOT_PROTOCOL values + */ +#define RB_BOOT_PROTOCOL_BOOTP 0 +#define RB_BOOT_PROTOCOL_DHCP 1 + +#endif /* _ROUTERBOOT_H */ diff --git a/include/linux/rtl8366.h b/include/linux/rtl8366.h new file mode 100644 index 000000000000..e3ce8f5361eb --- /dev/null +++ b/include/linux/rtl8366.h @@ -0,0 +1,42 @@ +/* + * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _RTL8366_H +#define _RTL8366_H + +#define RTL8366_DRIVER_NAME "rtl8366" +#define RTL8366S_DRIVER_NAME "rtl8366s" +#define RTL8366RB_DRIVER_NAME "rtl8366rb" + +struct rtl8366_smi; + +enum rtl8366_type { + RTL8366_TYPE_UNKNOWN, + RTL8366_TYPE_S, + RTL8366_TYPE_RB, +}; + +struct rtl8366_initval { + unsigned reg; + u16 val; +}; + +struct rtl8366_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(struct rtl8366_smi *smi, bool active); + + unsigned num_initvals; + struct rtl8366_initval *initvals; +}; + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata); + +#endif /* _RTL8366_H */ diff --git a/include/linux/rtl8367.h b/include/linux/rtl8367.h new file mode 100644 index 000000000000..14150393e280 --- /dev/null +++ b/include/linux/rtl8367.h @@ -0,0 +1,63 @@ +/* + * Platform data definition for the Realtek RTL8367 ethernet switch driver + * + * Copyright (C) 2011 Gabor Juhos + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef _RTL8367_H +#define _RTL8367_H + +#define RTL8367_DRIVER_NAME "rtl8367" +#define RTL8367B_DRIVER_NAME "rtl8367b" + +enum rtl8367_port_speed { + RTL8367_PORT_SPEED_10 = 0, + RTL8367_PORT_SPEED_100, + RTL8367_PORT_SPEED_1000, +}; + +struct rtl8367_port_ability { + int force_mode; + int nway; + int txpause; + int rxpause; + int link; + int duplex; + enum rtl8367_port_speed speed; +}; + +enum rtl8367_extif_mode { + RTL8367_EXTIF_MODE_DISABLED = 0, + RTL8367_EXTIF_MODE_RGMII, + RTL8367_EXTIF_MODE_MII_MAC, + RTL8367_EXTIF_MODE_MII_PHY, + RTL8367_EXTIF_MODE_TMII_MAC, + RTL8367_EXTIF_MODE_TMII_PHY, + RTL8367_EXTIF_MODE_GMII, + RTL8367_EXTIF_MODE_RGMII_33V, + RTL8367B_EXTIF_MODE_RMII_MAC = 7, + RTL8367B_EXTIF_MODE_RMII_PHY, + RTL8367B_EXTIF_MODE_RGMII_33V, +}; + +struct rtl8367_extif_config { + unsigned int txdelay; + unsigned int rxdelay; + enum rtl8367_extif_mode mode; + struct rtl8367_port_ability ability; +}; + +struct rtl8367_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(bool active); + + struct rtl8367_extif_config *extif0_cfg; + struct rtl8367_extif_config *extif1_cfg; +}; + +#endif /* _RTL8367_H */ diff --git a/include/linux/switch.h b/include/linux/switch.h new file mode 100644 index 000000000000..4e6238470d30 --- /dev/null +++ b/include/linux/switch.h @@ -0,0 +1,179 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _LINUX_SWITCH_H +#define _LINUX_SWITCH_H + +#include +#include + +struct switch_dev; +struct switch_op; +struct switch_val; +struct switch_attr; +struct switch_attrlist; +struct switch_led_trigger; + +int register_switch(struct switch_dev *dev, struct net_device *netdev); +void unregister_switch(struct switch_dev *dev); + +/** + * struct switch_attrlist - attribute list + * + * @n_attr: number of attributes + * @attr: pointer to the attributes array + */ +struct switch_attrlist { + int n_attr; + const struct switch_attr *attr; +}; + +enum switch_port_speed { + SWITCH_PORT_SPEED_UNKNOWN = 0, + SWITCH_PORT_SPEED_10 = 10, + SWITCH_PORT_SPEED_100 = 100, + SWITCH_PORT_SPEED_1000 = 1000, +}; + +struct switch_port_link { + bool link; + bool duplex; + bool aneg; + bool tx_flow; + bool rx_flow; + enum switch_port_speed speed; + /* in ethtool adv_t format */ + u32 eee; +}; + +struct switch_port_stats { + unsigned long long tx_bytes; + unsigned long long rx_bytes; +}; + +/** + * struct switch_dev_ops - switch driver operations + * + * @attr_global: global switch attribute list + * @attr_port: port attribute list + * @attr_vlan: vlan attribute list + * + * Callbacks: + * + * @get_vlan_ports: read the port list of a VLAN + * @set_vlan_ports: set the port list of a VLAN + * + * @get_port_pvid: get the primary VLAN ID of a port + * @set_port_pvid: set the primary VLAN ID of a port + * + * @apply_config: apply all changed settings to the switch + * @reset_switch: resetting the switch + */ +struct switch_dev_ops { + struct switch_attrlist attr_global, attr_port, attr_vlan; + + int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + + int (*get_port_pvid)(struct switch_dev *dev, int port, int *val); + int (*set_port_pvid)(struct switch_dev *dev, int port, int val); + + int (*apply_config)(struct switch_dev *dev); + int (*reset_switch)(struct switch_dev *dev); + + int (*get_port_link)(struct switch_dev *dev, int port, + struct switch_port_link *link); + int (*set_port_link)(struct switch_dev *dev, int port, + struct switch_port_link *link); + int (*get_port_stats)(struct switch_dev *dev, int port, + struct switch_port_stats *stats); + + int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value); + int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value); +}; + +struct switch_dev { + struct device_node *of_node; + const struct switch_dev_ops *ops; + /* will be automatically filled */ + char devname[IFNAMSIZ]; + + const char *name; + /* NB: either alias or netdev must be set */ + const char *alias; + struct net_device *netdev; + + unsigned int ports; + unsigned int vlans; + unsigned int cpu_port; + + /* the following fields are internal for swconfig */ + unsigned int id; + struct list_head dev_list; + unsigned long def_global, def_port, def_vlan; + + struct mutex sw_mutex; + struct switch_port *portbuf; + struct switch_portmap *portmap; + struct switch_port_link linkbuf; + + char buf[128]; + +#ifdef CONFIG_SWCONFIG_LEDS + struct switch_led_trigger *led_trigger; +#endif +}; + +struct switch_port { + u32 id; + u32 flags; +}; + +struct switch_portmap { + u32 virt; + const char *s; +}; + +struct switch_val { + const struct switch_attr *attr; + unsigned int port_vlan; + unsigned int len; + union { + const char *s; + u32 i; + struct switch_port *ports; + struct switch_port_link *link; + } value; +}; + +struct switch_attr { + int disabled; + int type; + const char *name; + const char *description; + + int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + + /* for driver internal use */ + int id; + int ofs; + int max; +}; + +int switch_generic_set_link(struct switch_dev *dev, int port, + struct switch_port_link *link); + +#endif /* _LINUX_SWITCH_H */ diff --git a/include/uapi/linux/switch.h b/include/uapi/linux/switch.h new file mode 100644 index 000000000000..ea449653fafa --- /dev/null +++ b/include/uapi/linux/switch.h @@ -0,0 +1,119 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UAPI_LINUX_SWITCH_H +#define _UAPI_LINUX_SWITCH_H + +#include +#include +#include +#include +#ifndef __KERNEL__ +#include +#include +#include +#endif + +/* main attributes */ +enum { + SWITCH_ATTR_UNSPEC, + /* global */ + SWITCH_ATTR_TYPE, + /* device */ + SWITCH_ATTR_ID, + SWITCH_ATTR_DEV_NAME, + SWITCH_ATTR_ALIAS, + SWITCH_ATTR_NAME, + SWITCH_ATTR_VLANS, + SWITCH_ATTR_PORTS, + SWITCH_ATTR_PORTMAP, + SWITCH_ATTR_CPU_PORT, + /* attributes */ + SWITCH_ATTR_OP_ID, + SWITCH_ATTR_OP_TYPE, + SWITCH_ATTR_OP_NAME, + SWITCH_ATTR_OP_PORT, + SWITCH_ATTR_OP_VLAN, + SWITCH_ATTR_OP_VALUE_INT, + SWITCH_ATTR_OP_VALUE_STR, + SWITCH_ATTR_OP_VALUE_PORTS, + SWITCH_ATTR_OP_VALUE_LINK, + SWITCH_ATTR_OP_DESCRIPTION, + /* port lists */ + SWITCH_ATTR_PORT, + SWITCH_ATTR_MAX +}; + +enum { + /* port map */ + SWITCH_PORTMAP_PORTS, + SWITCH_PORTMAP_SEGMENT, + SWITCH_PORTMAP_VIRT, + SWITCH_PORTMAP_MAX +}; + +/* commands */ +enum { + SWITCH_CMD_UNSPEC, + SWITCH_CMD_GET_SWITCH, + SWITCH_CMD_NEW_ATTR, + SWITCH_CMD_LIST_GLOBAL, + SWITCH_CMD_GET_GLOBAL, + SWITCH_CMD_SET_GLOBAL, + SWITCH_CMD_LIST_PORT, + SWITCH_CMD_GET_PORT, + SWITCH_CMD_SET_PORT, + SWITCH_CMD_LIST_VLAN, + SWITCH_CMD_GET_VLAN, + SWITCH_CMD_SET_VLAN +}; + +/* data types */ +enum switch_val_type { + SWITCH_TYPE_UNSPEC, + SWITCH_TYPE_INT, + SWITCH_TYPE_STRING, + SWITCH_TYPE_PORTS, + SWITCH_TYPE_LINK, + SWITCH_TYPE_NOVAL, +}; + +/* port nested attributes */ +enum { + SWITCH_PORT_UNSPEC, + SWITCH_PORT_ID, + SWITCH_PORT_FLAG_TAGGED, + SWITCH_PORT_ATTR_MAX +}; + +/* link nested attributes */ +enum { + SWITCH_LINK_UNSPEC, + SWITCH_LINK_FLAG_LINK, + SWITCH_LINK_FLAG_DUPLEX, + SWITCH_LINK_FLAG_ANEG, + SWITCH_LINK_FLAG_TX_FLOW, + SWITCH_LINK_FLAG_RX_FLOW, + SWITCH_LINK_SPEED, + SWITCH_LINK_FLAG_EEE_100BASET, + SWITCH_LINK_FLAG_EEE_1000BASET, + SWITCH_LINK_ATTR_MAX, +}; + +#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 + + +#endif /* _UAPI_LINUX_SWITCH_H */ -- 2.51.0 From 99a7ee0f062c7ea20d18a364a824e63cd95c637a Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Wed, 30 Oct 2024 17:47:35 +0000 Subject: [PATCH 002/517] jiffies: Define secs_to_jiffies() secs_to_jiffies() is defined in hci_event.c and cannot be reused by other call sites. Hoist it into the core code to allow conversion of the ~1150 usages of msecs_to_jiffies() that either: - use a multiplier value of 1000 or equivalently MSEC_PER_SEC, or - have timeouts that are denominated in seconds (i.e. end in 000) It's implemented as a macro to allow usage in static initializers. This will also allow conversion of yet more sites that use (sec * HZ) directly, and improve their readability. Suggested-by: Michael Kelley Signed-off-by: Easwar Hariharan Signed-off-by: Thomas Gleixner Reviewed-by: Luiz Augusto von Dentz Link: https://lore.kernel.org/all/20241030-open-coded-timeouts-v3-1-9ba123facf88@linux.microsoft.com --- include/linux/jiffies.h | 13 +++++++++++++ net/bluetooth/hci_event.c | 2 -- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 5d21dacd62bc..ed945f42e064 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -526,6 +526,19 @@ static __always_inline unsigned long msecs_to_jiffies(const unsigned int m) } } +/** + * secs_to_jiffies: - convert seconds to jiffies + * @_secs: time in seconds + * + * Conversion is done by simple multiplication with HZ + * + * secs_to_jiffies() is defined as a macro rather than a static inline + * function so it can be used in static initializers. + * + * Return: jiffies value + */ +#define secs_to_jiffies(_secs) ((_secs) * HZ) + extern unsigned long __usecs_to_jiffies(const unsigned int u); #if !(USEC_PER_SEC % HZ) static inline unsigned long _usecs_to_jiffies(const unsigned int u) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1e537ed83ba4..fdaaaf541cac 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -42,8 +42,6 @@ #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \ "\x00\x00\x00\x00\x00\x00\x00\x00" -#define secs_to_jiffies(_secs) msecs_to_jiffies((_secs) * 1000) - /* Handle HCI Event packets */ static void *hci_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb, -- 2.51.0 From 53a192c572edbbdfc84567d1e5d6c9b443186755 Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Thu, 30 Jan 2025 19:26:58 +0000 Subject: [PATCH 003/517] jiffies: Cast to unsigned long in secs_to_jiffies() conversion While converting users of msecs_to_jiffies(), lkp reported that some range checks would always be true because of the mismatch between the implied int value of secs_to_jiffies() vs the unsigned long return value of the msecs_to_jiffies() calls it was replacing. Fix this by casting the secs_to_jiffies() input value to unsigned long. Fixes: b35108a51cf7ba ("jiffies: Define secs_to_jiffies()") Reported-by: kernel test robot Signed-off-by: Easwar Hariharan Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20250130192701.99626-1-eahariha@linux.microsoft.com Closes: https://lore.kernel.org/oe-kbuild-all/202501301334.NB6NszQR-lkp@intel.com/ --- include/linux/jiffies.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index ed945f42e064..0ea8c9887429 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -537,7 +537,7 @@ static __always_inline unsigned long msecs_to_jiffies(const unsigned int m) * * Return: jiffies value */ -#define secs_to_jiffies(_secs) ((_secs) * HZ) +#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ) extern unsigned long __usecs_to_jiffies(const unsigned int u); #if !(USEC_PER_SEC % HZ) -- 2.51.0 From 49b181f4b38d468ce212fe2926334a12260893d9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Oct 2024 02:20:02 +0000 Subject: [PATCH 004/517] of: property: add of_graph_get_next_port() We have endpoint base functions - of_graph_get_next_endpoint() - of_graph_get_endpoint_count() - for_each_endpoint_of_node() Here, for_each_endpoint_of_node() loop finds each endpoints ports { port@0 { (1) endpoint {...}; }; port@1 { (2) endpoint {...}; }; ... }; In above case, it finds endpoint as (1) -> (2) -> ... Basically, user/driver knows which port is used for what, but not in all cases. For example on flexible/generic driver case, how many ports are used is not fixed. For example Sound Generic Card driver which is very flexible/generic and used from many venders can't know how many ports are used, and used for what, because it depends on each vender SoC and/or its used board. And more, the port can have multi endpoints. For example Generic Sound Card case, it supports many type of connection between CPU / Codec, and some of them uses multi endpoint in one port. see below. ports { (A) port@0 { (1) endpoint@0 {...}; (2) endpoint@1 {...}; }; (B) port@1 { (3) endpoint {...}; }; ... }; Generic Sound Card want to handle each connection via "port" base instead of "endpoint" base. But, it is very difficult to handle each "port" via existing for_each_endpoint_of_node(). Because getting each "port" via of_get_parent() from each "endpoint" doesn't work. For example in above case, both (1) (2) endpoint has same "port" (= A). Add "port" base functions. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ldyeb5t9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Rob Herring (Arm) --- drivers/of/property.c | 54 ++++++++++++++++++++++++++++++++++++++++ include/linux/of_graph.h | 28 +++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/drivers/of/property.c b/drivers/of/property.c index 906a33ae717f..7c8fb5dd4cb1 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -630,6 +630,43 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) } EXPORT_SYMBOL(of_graph_get_port_by_id); +/** + * of_graph_get_next_port() - get next port node. + * @parent: pointer to the parent device node, or parent ports node + * @prev: previous port node, or NULL to get first + * + * Parent device node can be used as @parent whether device node has ports node + * or not. It will work same as ports@0 node. + * + * Return: A 'port' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_port(const struct device_node *parent, + struct device_node *prev) +{ + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node __free(device_node) = + of_get_child_by_name(parent, "ports"); + + if (node) + parent = node; + + return of_get_child_by_name(parent, "port"); + } + + do { + prev = of_get_next_child(parent, prev); + if (!prev) + break; + } while (!of_node_name_eq(prev, "port")); + + return prev; +} +EXPORT_SYMBOL(of_graph_get_next_port); + /** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node @@ -823,6 +860,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) } EXPORT_SYMBOL(of_graph_get_endpoint_count); +/** + * of_graph_get_port_count() - get the number of port in a device or ports node + * @np: pointer to the device or ports node + * + * Return: count of port of this device or ports node + */ +unsigned int of_graph_get_port_count(struct device_node *np) +{ + unsigned int num = 0; + + for_each_of_graph_port(np, port) + num++; + + return num; +} +EXPORT_SYMBOL(of_graph_get_port_count); + /** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h index a4bea62bfa29..44518f3583a4 100644 --- a/include/linux/of_graph.h +++ b/include/linux/of_graph.h @@ -11,6 +11,7 @@ #ifndef __LINUX_OF_GRAPH_H #define __LINUX_OF_GRAPH_H +#include #include #include @@ -37,14 +38,29 @@ struct of_endpoint { for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \ child = of_graph_get_next_endpoint(parent, child)) +/** + * for_each_of_graph_port - iterate over every port in a device or ports node + * @parent: parent device or ports node containing port + * @child: loop variable pointing to the current port node + * + * When breaking out of the loop, and continue to use the @child, you need to + * use return_ptr(@child) or no_free_ptr(@child) not to call __free() for it. + */ +#define for_each_of_graph_port(parent, child) \ + for (struct device_node *child __free(device_node) = of_graph_get_next_port(parent, NULL);\ + child != NULL; child = of_graph_get_next_port(parent, child)) + #ifdef CONFIG_OF bool of_graph_is_present(const struct device_node *node); int of_graph_parse_endpoint(const struct device_node *node, struct of_endpoint *endpoint); unsigned int of_graph_get_endpoint_count(const struct device_node *np); +unsigned int of_graph_get_port_count(struct device_node *np); struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id); struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, struct device_node *previous); +struct device_node *of_graph_get_next_port(const struct device_node *parent, + struct device_node *port); struct device_node *of_graph_get_endpoint_by_regs( const struct device_node *parent, int port_reg, int reg); struct device_node *of_graph_get_remote_endpoint( @@ -73,6 +89,11 @@ static inline unsigned int of_graph_get_endpoint_count(const struct device_node return 0; } +static inline unsigned int of_graph_get_port_count(struct device_node *np) +{ + return 0; +} + static inline struct device_node *of_graph_get_port_by_id( struct device_node *node, u32 id) { @@ -86,6 +107,13 @@ static inline struct device_node *of_graph_get_next_endpoint( return NULL; } +static inline struct device_node *of_graph_get_next_port( + const struct device_node *parent, + struct device_node *previous) +{ + return NULL; +} + static inline struct device_node *of_graph_get_endpoint_by_regs( const struct device_node *parent, int port_reg, int reg) { -- 2.51.0 From 380cec7c796666f368f79a4059b3b7533bc5afd9 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Sat, 19 Oct 2024 14:16:00 +0300 Subject: [PATCH 005/517] clk: Provide devm_clk_bulk_get_all_enabled() helper Commit 265b07df758a ("clk: Provide managed helper to get and enable bulk clocks") added devm_clk_bulk_get_all_enable() function, but missed to return the number of clocks stored in the clk_bulk_data table referenced by the clks argument. Without knowing the number, it's not possible to iterate these clocks when needed, hence the argument is useless and could have been simply removed. Introduce devm_clk_bulk_get_all_enabled() variant, which is consistent with devm_clk_bulk_get_all() in terms of the returned value: > 0 if one or more clocks have been stored = 0 if there are no clocks < 0 if an error occurred Moreover, the naming is consistent with devm_clk_get_enabled(), i.e. use the past form of 'enable'. To reduce code duplication and improve patch readability, make devm_clk_bulk_get_all_enable() use the new helper, as suggested by Stephen Boyd. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Manivannan Sadhasivam Signed-off-by: Cristian Ciocaltea Link: https://lore.kernel.org/r/20241019-clk_bulk_ena_fix-v4-1-57f108f64e70@collabora.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-devres.c | 9 +++++---- include/linux/clk.h | 21 ++++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index 82ae1f26e634..5368d92d9b39 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_enable(struct device *dev, void *res) clk_bulk_put_all(devres->num_clks, devres->clks); } -int __must_check devm_clk_bulk_get_all_enable(struct device *dev, - struct clk_bulk_data **clks) +int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, + struct clk_bulk_data **clks) { struct clk_bulk_devres *devres; int ret; @@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_enable(struct device *dev, } else { clk_bulk_put_all(devres->num_clks, devres->clks); devres_free(devres); + return ret; } - return ret; + return devres->num_clks; } -EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable); +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled); static int devm_clk_match(struct device *dev, void *res, void *data) { diff --git a/include/linux/clk.h b/include/linux/clk.h index 851a0f2cf42c..1dcee6d701e4 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -496,11 +496,13 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks); /** - * devm_clk_bulk_get_all_enable - Get and enable all clocks of the consumer (managed) + * devm_clk_bulk_get_all_enabled - Get and enable all clocks of the consumer (managed) * @dev: device for clock "consumer" * @clks: pointer to the clk_bulk_data table of consumer * - * Returns success (0) or negative errno. + * Returns a positive value for the number of clocks obtained while the + * clock references are stored in the clk_bulk_data table in @clks field. + * Returns 0 if there're none and a negative value if something failed. * * This helper function allows drivers to get all clocks of the * consumer and enables them in one operation with management. @@ -508,8 +510,8 @@ int __must_check devm_clk_bulk_get_all(struct device *dev, * is unbound. */ -int __must_check devm_clk_bulk_get_all_enable(struct device *dev, - struct clk_bulk_data **clks); +int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, + struct clk_bulk_data **clks); /** * devm_clk_get - lookup and obtain a managed reference to a clock producer. @@ -1034,7 +1036,7 @@ static inline int __must_check devm_clk_bulk_get_all(struct device *dev, return 0; } -static inline int __must_check devm_clk_bulk_get_all_enable(struct device *dev, +static inline int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, struct clk_bulk_data **clks) { return 0; @@ -1136,6 +1138,15 @@ static inline void clk_restore_context(void) {} #endif +/* Deprecated. Use devm_clk_bulk_get_all_enabled() */ +static inline int __must_check +devm_clk_bulk_get_all_enable(struct device *dev, struct clk_bulk_data **clks) +{ + int ret = devm_clk_bulk_get_all_enabled(dev, clks); + + return ret > 0 ? 0 : ret; +} + /* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ static inline int clk_prepare_enable(struct clk *clk) { -- 2.51.0 From 15d25ea31ecbcaa422e8a49831e06e0b78af0037 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 12 Dec 2024 17:28:06 -0800 Subject: [PATCH 006/517] fortify: Hide run-time copy size from value range tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC performs value range tracking for variables as a way to provide better diagnostics. One place this is regularly seen is with warnings associated with bounds-checking, e.g. -Wstringop-overflow, -Wstringop-overread, -Warray-bounds, etc. In order to keep the signal-to-noise ratio high, warnings aren't emitted when a value range spans the entire value range representable by a given variable. For example: unsigned int len; char dst[8]; ... memcpy(dst, src, len); If len's value is unknown, it has the full "unsigned int" range of [0, UINT_MAX], and GCC's compile-time bounds checks against memcpy() will be ignored. However, when a code path has been able to narrow the range: if (len > 16) return; memcpy(dst, src, len); Then the range will be updated for the execution path. Above, len is now [0, 16] when reading memcpy(), so depending on other optimizations, we might see a -Wstringop-overflow warning like: error: '__builtin_memcpy' writing between 9 and 16 bytes into region of size 8 [-Werror=stringop-overflow] When building with CONFIG_FORTIFY_SOURCE, the fortified run-time bounds checking can appear to narrow value ranges of lengths for memcpy(), depending on how the compiler constructs the execution paths during optimization passes, due to the checks against the field sizes. For example: if (p_size_field != SIZE_MAX && p_size != p_size_field && p_size_field < size) As intentionally designed, these checks only affect the kernel warnings emitted at run-time and do not block the potentially overflowing memcpy(), so GCC thinks it needs to produce a warning about the resulting value range that might be reaching the memcpy(). We have seen this manifest a few times now, with the most recent being with cpumasks: In function ‘bitmap_copy’, inlined from ‘cpumask_copy’ at ./include/linux/cpumask.h:839:2, inlined from ‘__padata_set_cpumasks’ at kernel/padata.c:730:2: ./include/linux/fortify-string.h:114:33: error: ‘__builtin_memcpy’ reading between 257 and 536870904 bytes from a region of size 256 [-Werror=stringop-overread] 114 | #define __underlying_memcpy __builtin_memcpy | ^ ./include/linux/fortify-string.h:633:9: note: in expansion of macro ‘__underlying_memcpy’ 633 | __underlying_##op(p, q, __fortify_size); \ | ^~~~~~~~~~~~~ ./include/linux/fortify-string.h:678:26: note: in expansion of macro ‘__fortify_memcpy_chk’ 678 | #define memcpy(p, q, s) __fortify_memcpy_chk(p, q, s, \ | ^~~~~~~~~~~~~~~~~~~~ ./include/linux/bitmap.h:259:17: note: in expansion of macro ‘memcpy’ 259 | memcpy(dst, src, len); | ^~~~~~ kernel/padata.c: In function ‘__padata_set_cpumasks’: kernel/padata.c:713:48: note: source object ‘pcpumask’ of size [0, 256] 713 | cpumask_var_t pcpumask, | ~~~~~~~~~~~~~~^~~~~~~~ This warning is _not_ emitted when CONFIG_FORTIFY_SOURCE is disabled, and with the recent -fdiagnostics-details we can confirm the origin of the warning is due to FORTIFY's bounds checking: ../include/linux/bitmap.h:259:17: note: in expansion of macro 'memcpy' 259 | memcpy(dst, src, len); | ^~~~~~ '__padata_set_cpumasks': events 1-2 ../include/linux/fortify-string.h:613:36: 612 | if (p_size_field != SIZE_MAX && | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 613 | p_size != p_size_field && p_size_field < size) | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~ | | | (1) when the condition is evaluated to false | (2) when the condition is evaluated to true '__padata_set_cpumasks': event 3 114 | #define __underlying_memcpy __builtin_memcpy | ^ | | | (3) out of array bounds here Note that the cpumask warning started appearing since bitmap functions were recently marked __always_inline in commit ed8cd2b3bd9f ("bitmap: Switch from inline to __always_inline"), which allowed GCC to gain visibility into the variables as they passed through the FORTIFY implementation. In order to silence these false positives but keep otherwise deterministic compile-time warnings intact, hide the length variable from GCC with OPTIMIZE_HIDE_VAR() before calling the builtin memcpy. Additionally add a comment about why all the macro args have copies with const storage. Reported-by: "Thomas Weißschuh" Closes: https://lore.kernel.org/all/db7190c8-d17f-4a0d-bc2f-5903c79f36c2@t-8ch.de/ Reported-by: Nilay Shroff Closes: https://lore.kernel.org/all/20241112124127.1666300-1-nilay@linux.ibm.com/ Tested-by: Nilay Shroff Acked-by: Yury Norov Acked-by: Greg Kroah-Hartman Signed-off-by: Kees Cook --- include/linux/fortify-string.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 71f9dcf56128..b3b53f8c1b28 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -616,6 +616,12 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, return false; } +/* + * To work around what seems to be an optimizer bug, the macro arguments + * need to have const copies or the values end up changed by the time they + * reach fortify_warn_once(). See commit 6f7630b1b5bc ("fortify: Capture + * __bos() results in const temp vars") for more details. + */ #define __fortify_memcpy_chk(p, q, size, p_size, q_size, \ p_size_field, q_size_field, op) ({ \ const size_t __fortify_size = (size_t)(size); \ @@ -623,6 +629,8 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, const size_t __q_size = (q_size); \ const size_t __p_size_field = (p_size_field); \ const size_t __q_size_field = (q_size_field); \ + /* Keep a mutable version of the size for the final copy. */ \ + size_t __copy_size = __fortify_size; \ fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \ __q_size, __p_size_field, \ __q_size_field, FORTIFY_FUNC_ ##op), \ @@ -630,7 +638,11 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size, __fortify_size, \ "field \"" #p "\" at " FILE_LINE, \ __p_size_field); \ - __underlying_##op(p, q, __fortify_size); \ + /* Hide only the run-time size from value range tracking to */ \ + /* silence compile-time false positive bounds warnings. */ \ + if (!__builtin_constant_p(__copy_size)) \ + OPTIMIZER_HIDE_VAR(__copy_size); \ + __underlying_##op(p, q, __copy_size); \ }) /* -- 2.51.0 From 377e4603cc60869e907fd2e5c1a16d6749cf0cc0 Mon Sep 17 00:00:00 2001 From: Bohdan Chubuk Date: Sun, 10 Nov 2024 22:50:47 +0200 Subject: [PATCH 007/517] mtd: spinand: add support for FORESEE F35SQA001G Add support for FORESEE F35SQA001G SPI NAND. Similar to F35SQA002G, but differs in capacity. Datasheet: - https://cdn.ozdisan.com/ETicaret_Dosya/704795_871495.pdf Tested on Xiaomi AX3000T flashed with OpenWRT. Signed-off-by: Bohdan Chubuk Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/foresee.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c index e0d2d9257045..8a01582c0f53 100644 --- a/drivers/mtd/nand/spi/foresee.c +++ b/drivers/mtd/nand/spi/foresee.c @@ -81,6 +81,16 @@ static const struct spinand_info foresee_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&f35sqa002g_ooblayout, f35sqa002g_ecc_get_status)), + SPINAND_INFO("F35SQA001G", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&f35sqa002g_ooblayout, + f35sqa002g_ecc_get_status)), }; static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = { -- 2.51.0 From 747b700acdaf801e23257c4de2457df42706bbdb Mon Sep 17 00:00:00 2001 From: Tianling Shen Date: Mon, 25 Aug 2025 01:00:13 +0800 Subject: [PATCH 008/517] mtd: spinand: add support for FudanMicro FM25S01A Add support for FudanMicro FM25S01A SPI NAND. Datasheet: http://eng.fmsh.com/nvm/FM25S01A_ds_eng.pdf Signed-off-by: Tianling Shen Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20250824170013.3328777-1-cnsztl@gmail.com --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/fmsh.c | 74 +++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/fmsh.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 19cc77288ebb..32a696055d9f 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o +spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index c523a1a22c2b..8e4c825b9789 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1115,6 +1115,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, + &fmsh_spinand_manufacturer, &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c new file mode 100644 index 000000000000..71922d94f218 --- /dev/null +++ b/drivers/mtd/nand/spi/fmsh.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * Author: Dingqiang Lin + */ + +#include +#include +#include + +#define SPINAND_MFR_FMSH 0xA1 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + +static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { + .ecc = fm25s01a_ooblayout_ecc, + .free = fm25s01a_ooblayout_free, +}; + +static const struct spinand_info fmsh_spinand_table[] = { + SPINAND_INFO("FM25S01A", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer fmsh_spinand_manufacturer = { + .id = SPINAND_MFR_FMSH, + .name = "Fudan Micro", + .chips = fmsh_spinand_table, + .nchips = ARRAY_SIZE(fmsh_spinand_table), + .ops = &fmsh_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 702e5fb13dae..ba7b73c9675e 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -263,6 +263,7 @@ struct spinand_manufacturer { extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; +extern const struct spinand_manufacturer fmsh_spinand_manufacturer; extern const struct spinand_manufacturer foresee_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; -- 2.51.0 From ac22dde59c9dc55647118463603931a1ac92c942 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Wed, 10 Sep 2025 14:32:58 -0400 Subject: [PATCH 009/517] mtd: nand: move nand_check_erased_ecc_chunk() to nand/core The check function for bitflips in erased blocks will be needed by the Realtek ECC engine driver (which is currently under development). Right now it is located in raw/nand_base.c. While this is sufficient for the current usecases, there is no real dependency for an ECC engine on the raw nand library. Move the function over to a more generic place in core library. Suggested-by: Miquel Raynal Signed-off-by: Markus Stockhausen Signed-off-by: Miquel Raynal --- drivers/mtd/nand/core.c | 131 +++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/nand_base.c | 131 ------------------------------- include/linux/mtd/nand.h | 5 ++ include/linux/mtd/rawnand.h | 5 -- 4 files changed, 136 insertions(+), 136 deletions(-) diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c index 7737b1a4a177..3e76d127715f 100644 --- a/drivers/mtd/nand/core.c +++ b/drivers/mtd/nand/core.c @@ -12,6 +12,137 @@ #include #include +/** + * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data + * @buf: buffer to test + * @len: buffer length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a buffer contains only 0xff, which means the underlying region + * has been erased and is ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region is not erased. + * Note: The logic of this function has been extracted from the memweight + * implementation, except that nand_check_erased_buf function exit before + * testing the whole buffer if the number of bitflips exceed the + * bitflips_threshold value. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. + */ +static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) +{ + const unsigned char *bitmap = buf; + int bitflips = 0; + int weight; + + for (; len && ((uintptr_t)bitmap) % sizeof(long); + len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len >= sizeof(long); + len -= sizeof(long), bitmap += sizeof(long)) { + unsigned long d = *((unsigned long *)bitmap); + if (d == ~0UL) + continue; + weight = hweight_long(d); + bitflips += BITS_PER_LONG - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + for (; len > 0; len--, bitmap++) { + weight = hweight8(*bitmap); + bitflips += BITS_PER_BYTE - weight; + if (unlikely(bitflips > bitflips_threshold)) + return -EBADMSG; + } + + return bitflips; +} + +/** + * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only + * 0xff data + * @data: data buffer to test + * @datalen: data length + * @ecc: ECC buffer + * @ecclen: ECC length + * @extraoob: extra OOB buffer + * @extraooblen: extra OOB length + * @bitflips_threshold: maximum number of bitflips + * + * Check if a data buffer and its associated ECC and OOB data contains only + * 0xff pattern, which means the underlying region has been erased and is + * ready to be programmed. + * The bitflips_threshold specify the maximum number of bitflips before + * considering the region as not erased. + * + * Note: + * 1/ ECC algorithms are working on pre-defined block sizes which are usually + * different from the NAND page size. When fixing bitflips, ECC engines will + * report the number of errors per chunk, and the NAND core infrastructure + * expect you to return the maximum number of bitflips for the whole page. + * This is why you should always use this function on a single chunk and + * not on the whole page. After checking each chunk you should update your + * max_bitflips value accordingly. + * 2/ When checking for bitflips in erased pages you should not only check + * the payload data but also their associated ECC data, because a user might + * have programmed almost all bits to 1 but a few. In this case, we + * shouldn't consider the chunk as erased, and checking ECC bytes prevent + * this case. + * 3/ The extraoob argument is optional, and should be used if some of your OOB + * data are protected by the ECC engine. + * It could also be used if you support subpages and want to attach some + * extra OOB data to an ECC chunk. + * + * Returns a positive number of bitflips less than or equal to + * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the + * threshold. In case of success, the passed buffers are filled with 0xff. + */ +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int bitflips_threshold) +{ + int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; + + data_bitflips = nand_check_erased_buf(data, datalen, + bitflips_threshold); + if (data_bitflips < 0) + return data_bitflips; + + bitflips_threshold -= data_bitflips; + + ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); + if (ecc_bitflips < 0) + return ecc_bitflips; + + bitflips_threshold -= ecc_bitflips; + + extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, + bitflips_threshold); + if (extraoob_bitflips < 0) + return extraoob_bitflips; + + if (data_bitflips) + memset(data, 0xff, datalen); + + if (ecc_bitflips) + memset(ecc, 0xff, ecclen); + + if (extraoob_bitflips) + memset(extraoob, 0xff, extraooblen); + + return data_bitflips + ecc_bitflips + extraoob_bitflips; +} +EXPORT_SYMBOL(nand_check_erased_ecc_chunk); + /** * nanddev_isbad() - Check if a block is bad * @nand: NAND device diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 53e16d39af4b..c1f785a8b7e5 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2783,137 +2783,6 @@ int nand_set_features(struct nand_chip *chip, int addr, return nand_set_features_op(chip, addr, subfeature_param); } -/** - * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data - * @buf: buffer to test - * @len: buffer length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a buffer contains only 0xff, which means the underlying region - * has been erased and is ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region is not erased. - * Note: The logic of this function has been extracted from the memweight - * implementation, except that nand_check_erased_buf function exit before - * testing the whole buffer if the number of bitflips exceed the - * bitflips_threshold value. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. - */ -static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold) -{ - const unsigned char *bitmap = buf; - int bitflips = 0; - int weight; - - for (; len && ((uintptr_t)bitmap) % sizeof(long); - len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len >= sizeof(long); - len -= sizeof(long), bitmap += sizeof(long)) { - unsigned long d = *((unsigned long *)bitmap); - if (d == ~0UL) - continue; - weight = hweight_long(d); - bitflips += BITS_PER_LONG - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - for (; len > 0; len--, bitmap++) { - weight = hweight8(*bitmap); - bitflips += BITS_PER_BYTE - weight; - if (unlikely(bitflips > bitflips_threshold)) - return -EBADMSG; - } - - return bitflips; -} - -/** - * nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only - * 0xff data - * @data: data buffer to test - * @datalen: data length - * @ecc: ECC buffer - * @ecclen: ECC length - * @extraoob: extra OOB buffer - * @extraooblen: extra OOB length - * @bitflips_threshold: maximum number of bitflips - * - * Check if a data buffer and its associated ECC and OOB data contains only - * 0xff pattern, which means the underlying region has been erased and is - * ready to be programmed. - * The bitflips_threshold specify the maximum number of bitflips before - * considering the region as not erased. - * - * Note: - * 1/ ECC algorithms are working on pre-defined block sizes which are usually - * different from the NAND page size. When fixing bitflips, ECC engines will - * report the number of errors per chunk, and the NAND core infrastructure - * expect you to return the maximum number of bitflips for the whole page. - * This is why you should always use this function on a single chunk and - * not on the whole page. After checking each chunk you should update your - * max_bitflips value accordingly. - * 2/ When checking for bitflips in erased pages you should not only check - * the payload data but also their associated ECC data, because a user might - * have programmed almost all bits to 1 but a few. In this case, we - * shouldn't consider the chunk as erased, and checking ECC bytes prevent - * this case. - * 3/ The extraoob argument is optional, and should be used if some of your OOB - * data are protected by the ECC engine. - * It could also be used if you support subpages and want to attach some - * extra OOB data to an ECC chunk. - * - * Returns a positive number of bitflips less than or equal to - * bitflips_threshold, or -ERROR_CODE for bitflips in excess of the - * threshold. In case of success, the passed buffers are filled with 0xff. - */ -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int bitflips_threshold) -{ - int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0; - - data_bitflips = nand_check_erased_buf(data, datalen, - bitflips_threshold); - if (data_bitflips < 0) - return data_bitflips; - - bitflips_threshold -= data_bitflips; - - ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold); - if (ecc_bitflips < 0) - return ecc_bitflips; - - bitflips_threshold -= ecc_bitflips; - - extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen, - bitflips_threshold); - if (extraoob_bitflips < 0) - return extraoob_bitflips; - - if (data_bitflips) - memset(data, 0xff, datalen); - - if (ecc_bitflips) - memset(ecc, 0xff, ecclen); - - if (extraoob_bitflips) - memset(extraoob, 0xff, extraooblen); - - return data_bitflips + ecc_bitflips + extraoob_bitflips; -} -EXPORT_SYMBOL(nand_check_erased_ecc_chunk); - /** * nand_read_page_raw_notsupp - dummy read raw page function * @chip: nand chip info structure diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 1e4208040956..f4ee1e4bc18f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1136,4 +1136,9 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand) int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo); int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len); +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int threshold); + #endif /* __LINUX_MTD_NAND_H */ diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index e84522e31301..d30bdc3fcfd7 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1519,11 +1519,6 @@ int rawnand_sw_bch_correct(struct nand_chip *chip, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc); void rawnand_sw_bch_cleanup(struct nand_chip *chip); -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int threshold); - int nand_ecc_choose_conf(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail); -- 2.51.0 From 7b26769b0e737b7f7ecb5b0201a0cbf5a72ed150 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 20 Nov 2024 14:45:00 +0530 Subject: [PATCH 010/517] mtd: rawnand: qcom: cleanup qcom_nandc driver Perform a global cleanup of the Qualcomm NAND controller driver with the following improvements: - Remove register value indirection API - Remove set_reg() API - Convert read_loc_first & read_loc_last macro to functions - Rename multiple variables Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/qcom_nandc.c | 520 ++++++++++++++---------------- 1 file changed, 236 insertions(+), 284 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 275d34119acd..94a57a0de067 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -189,17 +189,6 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) -#define nandc_set_read_loc_first(chip, reg, cw_offset, read_size, is_last_read_loc) \ -nandc_set_reg(chip, reg, \ - ((cw_offset) << READ_LOCATION_OFFSET) | \ - ((read_size) << READ_LOCATION_SIZE) | \ - ((is_last_read_loc) << READ_LOCATION_LAST)) - -#define nandc_set_read_loc_last(chip, reg, cw_offset, read_size, is_last_read_loc) \ -nandc_set_reg(chip, reg, \ - ((cw_offset) << READ_LOCATION_OFFSET) | \ - ((read_size) << READ_LOCATION_SIZE) | \ - ((is_last_read_loc) << READ_LOCATION_LAST)) /* * Returns the actual register address for all NAND_DEV_ registers * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) @@ -257,8 +246,6 @@ nandc_set_reg(chip, reg, \ * @tx_sgl_start - start index in data sgl for tx. * @rx_sgl_pos - current index in data sgl for rx. * @rx_sgl_start - start index in data sgl for rx. - * @wait_second_completion - wait for second DMA desc completion before making - * the NAND transfer completion. */ struct bam_transaction { struct bam_cmd_element *bam_ce; @@ -275,7 +262,6 @@ struct bam_transaction { u32 tx_sgl_start; u32 rx_sgl_pos; u32 rx_sgl_start; - bool wait_second_completion; }; /* @@ -471,9 +457,9 @@ struct qcom_op { unsigned int data_instr_idx; unsigned int rdy_timeout_ms; unsigned int rdy_delay_ns; - u32 addr1_reg; - u32 addr2_reg; - u32 cmd_reg; + __le32 addr1_reg; + __le32 addr2_reg; + __le32 cmd_reg; u8 flag; }; @@ -549,17 +535,17 @@ struct qcom_nand_host { * among different NAND controllers. * @ecc_modes - ecc mode for NAND * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset - * @is_bam - whether NAND controller is using BAM - * @is_qpic - whether NAND CTRL is part of qpic IP - * @qpic_v2 - flag to indicate QPIC IP version 2 + * @supports_bam - whether NAND controller is using Bus Access Manager (BAM) + * @nandc_part_of_qpic - whether NAND controller is part of qpic IP + * @qpic_version2 - flag to indicate QPIC IP version 2 * @use_codeword_fixup - whether NAND has different layout for boot partitions */ struct qcom_nandc_props { u32 ecc_modes; u32 dev_cmd_reg_start; - bool is_bam; - bool is_qpic; - bool qpic_v2; + bool supports_bam; + bool nandc_part_of_qpic; + bool qpic_version2; bool use_codeword_fixup; }; @@ -613,19 +599,11 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc) { struct bam_transaction *bam_txn = nandc->bam_txn; - if (!nandc->props->is_bam) + if (!nandc->props->supports_bam) return; - bam_txn->bam_ce_pos = 0; - bam_txn->bam_ce_start = 0; - bam_txn->cmd_sgl_pos = 0; - bam_txn->cmd_sgl_start = 0; - bam_txn->tx_sgl_pos = 0; - bam_txn->tx_sgl_start = 0; - bam_txn->rx_sgl_pos = 0; - bam_txn->rx_sgl_start = 0; + memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); bam_txn->last_data_desc = NULL; - bam_txn->wait_second_completion = false; sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * QPIC_PER_CW_CMD_SGL); @@ -640,46 +618,35 @@ static void qpic_bam_dma_done(void *data) { struct bam_transaction *bam_txn = data; - /* - * In case of data transfer with NAND, 2 callbacks will be generated. - * One for command channel and another one for data channel. - * If current transaction has data descriptors - * (i.e. wait_second_completion is true), then set this to false - * and wait for second DMA descriptor completion. - */ - if (bam_txn->wait_second_completion) - bam_txn->wait_second_completion = false; - else - complete(&bam_txn->txn_done); + complete(&bam_txn->txn_done); } -static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) +static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); } -static inline struct qcom_nand_controller * +static struct qcom_nand_controller * get_qcom_nand_controller(struct nand_chip *chip) { return container_of(chip->controller, struct qcom_nand_controller, controller); } -static inline u32 nandc_read(struct qcom_nand_controller *nandc, int offset) +static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) { return ioread32(nandc->base + offset); } -static inline void nandc_write(struct qcom_nand_controller *nandc, int offset, - u32 val) +static void nandc_write(struct qcom_nand_controller *nandc, int offset, + u32 val) { iowrite32(val, nandc->base + offset); } -static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, - bool is_cpu) +static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) { - if (!nandc->props->is_bam) + if (!nandc->props->supports_bam) return; if (is_cpu) @@ -694,93 +661,90 @@ static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, DMA_FROM_DEVICE); } -static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) -{ - switch (offset) { - case NAND_FLASH_CMD: - return ®s->cmd; - case NAND_ADDR0: - return ®s->addr0; - case NAND_ADDR1: - return ®s->addr1; - case NAND_FLASH_CHIP_SELECT: - return ®s->chip_sel; - case NAND_EXEC_CMD: - return ®s->exec; - case NAND_FLASH_STATUS: - return ®s->clrflashstatus; - case NAND_DEV0_CFG0: - return ®s->cfg0; - case NAND_DEV0_CFG1: - return ®s->cfg1; - case NAND_DEV0_ECC_CFG: - return ®s->ecc_bch_cfg; - case NAND_READ_STATUS: - return ®s->clrreadstatus; - case NAND_DEV_CMD1: - return ®s->cmd1; - case NAND_DEV_CMD1_RESTORE: - return ®s->orig_cmd1; - case NAND_DEV_CMD_VLD: - return ®s->vld; - case NAND_DEV_CMD_VLD_RESTORE: - return ®s->orig_vld; - case NAND_EBI2_ECC_BUF_CFG: - return ®s->ecc_buf_cfg; - case NAND_READ_LOCATION_0: - return ®s->read_location0; - case NAND_READ_LOCATION_1: - return ®s->read_location1; - case NAND_READ_LOCATION_2: - return ®s->read_location2; - case NAND_READ_LOCATION_3: - return ®s->read_location3; - case NAND_READ_LOCATION_LAST_CW_0: - return ®s->read_location_last0; - case NAND_READ_LOCATION_LAST_CW_1: - return ®s->read_location_last1; - case NAND_READ_LOCATION_LAST_CW_2: - return ®s->read_location_last2; - case NAND_READ_LOCATION_LAST_CW_3: - return ®s->read_location_last3; - default: - return NULL; - } +/* Helper to check whether this is the last CW or not */ +static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) +{ + return cw == (ecc->steps - 1); } -static void nandc_set_reg(struct nand_chip *chip, int offset, - u32 val) +/** + * nandc_set_read_loc_first() - to set read location first register + * @chip: NAND Private Flash Chip Data + * @reg_base: location register base + * @cw_offset: code word offset + * @read_size: code word read length + * @is_last_read_loc: is this the last read location + * + * This function will set location register value + */ +static void nandc_set_read_loc_first(struct nand_chip *chip, + int reg_base, u32 cw_offset, + u32 read_size, u32 is_last_read_loc) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - struct nandc_regs *regs = nandc->regs; - __le32 *reg; - - reg = offset_to_nandc_reg(regs, offset); + __le32 locreg_val; + u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | + ((read_size) << READ_LOCATION_SIZE) | + ((is_last_read_loc) << READ_LOCATION_LAST)); + + locreg_val = cpu_to_le32(val); + + if (reg_base == NAND_READ_LOCATION_0) + nandc->regs->read_location0 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_1) + nandc->regs->read_location1 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_2) + nandc->regs->read_location2 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_3) + nandc->regs->read_location3 = locreg_val; +} + +/** + * nandc_set_read_loc_last - to set read location last register + * @chip: NAND Private Flash Chip Data + * @reg_base: location register base + * @cw_offset: code word offset + * @read_size: code word read length + * @is_last_read_loc: is this the last read location + * + * This function will set location last register value + */ +static void nandc_set_read_loc_last(struct nand_chip *chip, + int reg_base, u32 cw_offset, + u32 read_size, u32 is_last_read_loc) +{ + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + __le32 locreg_val; + u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | + ((read_size) << READ_LOCATION_SIZE) | + ((is_last_read_loc) << READ_LOCATION_LAST)); - if (reg) - *reg = cpu_to_le32(val); -} + locreg_val = cpu_to_le32(val); -/* Helper to check the code word, whether it is last cw or not */ -static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) -{ - return cw == (ecc->steps - 1); + if (reg_base == NAND_READ_LOCATION_LAST_CW_0) + nandc->regs->read_location_last0 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_LAST_CW_1) + nandc->regs->read_location_last1 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_LAST_CW_2) + nandc->regs->read_location_last2 = locreg_val; + else if (reg_base == NAND_READ_LOCATION_LAST_CW_3) + nandc->regs->read_location_last3 = locreg_val; } /* helper to configure location register values */ static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg, - int cw_offset, int read_size, int is_last_read_loc) + u32 cw_offset, u32 read_size, u32 is_last_read_loc) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int reg_base = NAND_READ_LOCATION_0; - if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) + if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) reg_base = NAND_READ_LOCATION_LAST_CW_0; reg_base += reg * 4; - if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) + if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) return nandc_set_read_loc_last(chip, reg_base, cw_offset, read_size, is_last_read_loc); else @@ -792,12 +756,13 @@ static void nandc_set_read_loc(struct nand_chip *chip, int cw, int reg, static void set_address(struct qcom_nand_host *host, u16 column, int page) { struct nand_chip *chip = &host->chip; + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); if (chip->options & NAND_BUSWIDTH_16) column >>= 1; - nandc_set_reg(chip, NAND_ADDR0, page << 16 | column); - nandc_set_reg(chip, NAND_ADDR1, page >> 16 & 0xff); + nandc->regs->addr0 = cpu_to_le32(page << 16 | column); + nandc->regs->addr1 = cpu_to_le32(page >> 16 & 0xff); } /* @@ -811,41 +776,43 @@ static void set_address(struct qcom_nand_host *host, u16 column, int page) static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, int cw) { struct nand_chip *chip = &host->chip; - u32 cmd, cfg0, cfg1, ecc_bch_cfg; + __le32 cmd, cfg0, cfg1, ecc_bch_cfg; struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); if (read) { if (host->use_ecc) - cmd = OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE; + cmd = cpu_to_le32(OP_PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE); else - cmd = OP_PAGE_READ | PAGE_ACC | LAST_PAGE; + cmd = cpu_to_le32(OP_PAGE_READ | PAGE_ACC | LAST_PAGE); } else { - cmd = OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE; + cmd = cpu_to_le32(OP_PROGRAM_PAGE | PAGE_ACC | LAST_PAGE); } if (host->use_ecc) { - cfg0 = (host->cfg0 & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = cpu_to_le32((host->cfg0 & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE); - cfg1 = host->cfg1; - ecc_bch_cfg = host->ecc_bch_cfg; + cfg1 = cpu_to_le32(host->cfg1); + ecc_bch_cfg = cpu_to_le32(host->ecc_bch_cfg); } else { - cfg0 = (host->cfg0_raw & ~(7U << CW_PER_PAGE)) | - (num_cw - 1) << CW_PER_PAGE; + cfg0 = cpu_to_le32((host->cfg0_raw & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE); - cfg1 = host->cfg1_raw; - ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; + cfg1 = cpu_to_le32(host->cfg1_raw); + ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); } - nandc_set_reg(chip, NAND_FLASH_CMD, cmd); - nandc_set_reg(chip, NAND_DEV0_CFG0, cfg0); - nandc_set_reg(chip, NAND_DEV0_CFG1, cfg1); - nandc_set_reg(chip, NAND_DEV0_ECC_CFG, ecc_bch_cfg); - if (!nandc->props->qpic_v2) - nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, host->ecc_buf_cfg); - nandc_set_reg(chip, NAND_FLASH_STATUS, host->clrflashstatus); - nandc_set_reg(chip, NAND_READ_STATUS, host->clrreadstatus); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc->regs->cmd = cmd; + nandc->regs->cfg0 = cfg0; + nandc->regs->cfg1 = cfg1; + nandc->regs->ecc_bch_cfg = ecc_bch_cfg; + + if (!nandc->props->qpic_version2) + nandc->regs->ecc_buf_cfg = cpu_to_le32(host->ecc_buf_cfg); + + nandc->regs->clrflashstatus = cpu_to_le32(host->clrflashstatus); + nandc->regs->clrreadstatus = cpu_to_le32(host->clrreadstatus); + nandc->regs->exec = cpu_to_le32(1); if (read) nandc_set_read_loc(chip, cw, 0, 0, host->use_ecc ? @@ -1121,7 +1088,7 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) first = dev_cmd_reg_addr(nandc, first); - if (nandc->props->is_bam) + if (nandc->props->supports_bam) return prep_bam_dma_desc_cmd(nandc, true, first, vaddr, num_regs, flags); @@ -1136,25 +1103,16 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, * write_reg_dma: prepares a descriptor to write a given number of * contiguous registers * + * @vaddr: contiguous memory from where register value will + * be written * @first: offset of the first register in the contiguous block * @num_regs: number of registers to write * @flags: flags to control DMA descriptor preparation */ -static int write_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs, unsigned int flags) +static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, + int first, int num_regs, unsigned int flags) { bool flow_control = false; - struct nandc_regs *regs = nandc->regs; - void *vaddr; - - vaddr = offset_to_nandc_reg(regs, first); - - if (first == NAND_ERASED_CW_DETECT_CFG) { - if (flags & NAND_ERASED_CW_SET) - vaddr = ®s->erased_cw_detect_cfg_set; - else - vaddr = ®s->erased_cw_detect_cfg_clr; - } if (first == NAND_EXEC_CMD) flags |= NAND_BAM_NWD; @@ -1165,7 +1123,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); - if (nandc->props->is_bam) + if (nandc->props->supports_bam) return prep_bam_dma_desc_cmd(nandc, false, first, vaddr, num_regs, flags); @@ -1188,7 +1146,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { - if (nandc->props->is_bam) + if (nandc->props->supports_bam) return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); @@ -1206,7 +1164,7 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { - if (nandc->props->is_bam) + if (nandc->props->supports_bam) return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); @@ -1220,13 +1178,14 @@ static void config_nand_page_read(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, NAND_ADDR0, 2, 0); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); - if (!nandc->props->qpic_v2) - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); - write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0); - write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, - NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + if (!nandc->props->qpic_version2) + write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); + write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); } /* @@ -1239,16 +1198,16 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; - int reg = NAND_READ_LOCATION_0; + __le32 *reg = &nandc->regs->read_location0; - if (nandc->props->qpic_v2 && qcom_nandc_is_last_cw(ecc, cw)) - reg = NAND_READ_LOCATION_LAST_CW_0; + if (nandc->props->qpic_version2 && qcom_nandc_is_last_cw(ecc, cw)) + reg = &nandc->regs->read_location_last0; - if (nandc->props->is_bam) - write_reg_dma(nandc, reg, 4, NAND_BAM_NEXT_SGL); + if (nandc->props->supports_bam) + write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); if (use_ecc) { read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); @@ -1279,10 +1238,10 @@ static void config_nand_page_write(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, NAND_ADDR0, 2, 0); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); - if (!nandc->props->qpic_v2) - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, + write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + if (!nandc->props->qpic_version2) + write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, NAND_BAM_NEXT_SGL); } @@ -1294,13 +1253,13 @@ static void config_nand_cw_write(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); - write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); + write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); } /* helpers to submit/free our list of dma descriptors */ @@ -1311,7 +1270,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) struct bam_transaction *bam_txn = nandc->bam_txn; int ret = 0; - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); if (ret) @@ -1336,14 +1295,9 @@ static int submit_descs(struct qcom_nand_controller *nandc) list_for_each_entry(desc, &nandc->desc_list, node) cookie = dmaengine_submit(desc->dma_desc); - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { bam_txn->last_cmd_desc->callback = qpic_bam_dma_done; bam_txn->last_cmd_desc->callback_param = bam_txn; - if (bam_txn->last_data_desc) { - bam_txn->last_data_desc->callback = qpic_bam_dma_done; - bam_txn->last_data_desc->callback_param = bam_txn; - bam_txn->wait_second_completion = true; - } dma_async_issue_pending(nandc->tx_chan); dma_async_issue_pending(nandc->rx_chan); @@ -1365,7 +1319,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { list_del(&desc->node); - if (nandc->props->is_bam) + if (nandc->props->supports_bam) dma_unmap_sg(nandc->dev, desc->bam_sgl, desc->sgl_cnt, desc->dir); else @@ -1382,7 +1336,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) static void clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; - nandc_read_buffer_sync(nandc, false); + nandc_dev_to_mem(nandc, false); } /* @@ -1446,7 +1400,7 @@ static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int i; - nandc_read_buffer_sync(nandc, true); + nandc_dev_to_mem(nandc, true); for (i = 0; i < cw_cnt; i++) { u32 flash = le32_to_cpu(nandc->reg_read_buf[i]); @@ -1476,7 +1430,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, clear_read_regs(nandc); host->use_ecc = false; - if (nandc->props->qpic_v2) + if (nandc->props->qpic_version2) raw_cw = ecc->steps - 1; clear_bam_transaction(nandc); @@ -1497,7 +1451,7 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { nandc_set_read_loc(chip, cw, 0, read_loc, data_size1, 0); read_loc += data_size1; @@ -1621,7 +1575,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; buf = (struct read_stats *)nandc->reg_read_buf; - nandc_read_buffer_sync(nandc, true); + nandc_dev_to_mem(nandc, true); for (i = 0; i < ecc->steps; i++, buf++) { u32 flash, buffer, erased_cw; @@ -1734,7 +1688,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_size = host->ecc_bytes_hw + host->spare_bytes; } - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { if (data_buf && oob_buf) { nandc_set_read_loc(chip, i, 0, 0, data_size, 0); nandc_set_read_loc(chip, i, 1, data_size, @@ -2455,14 +2409,14 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); /* Free the initially allocated BAM transaction for reading the ONFI params */ - if (nandc->props->is_bam) + if (nandc->props->supports_bam) free_bam_transaction(nandc); nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, cwperpage); /* Now allocate the BAM transaction based on updated max_cwperpage */ - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { nandc->bam_txn = alloc_bam_transaction(nandc); if (!nandc->bam_txn) { dev_err(nandc->dev, @@ -2522,7 +2476,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) | ecc_mode << ECC_MODE | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH; - if (!nandc->props->qpic_v2) + if (!nandc->props->qpic_version2) host->ecc_buf_cfg = 0x203 << NUM_STEPS; host->clrflashstatus = FS_READY_BSY_N; @@ -2556,7 +2510,7 @@ static int qcom_op_cmd_mapping(struct nand_chip *chip, u8 opcode, cmd = OP_FETCH_ID; break; case NAND_CMD_PARAM: - if (nandc->props->qpic_v2) + if (nandc->props->qpic_version2) cmd = OP_PAGE_READ_ONFI_READ; else cmd = OP_PAGE_READ; @@ -2609,7 +2563,7 @@ static int qcom_parse_instructions(struct nand_chip *chip, if (ret < 0) return ret; - q_op->cmd_reg = ret; + q_op->cmd_reg = cpu_to_le32(ret); q_op->rdy_delay_ns = instr->delay_ns; break; @@ -2619,10 +2573,10 @@ static int qcom_parse_instructions(struct nand_chip *chip, addrs = &instr->ctx.addr.addrs[offset]; for (i = 0; i < min_t(unsigned int, 4, naddrs); i++) - q_op->addr1_reg |= addrs[i] << (i * 8); + q_op->addr1_reg |= cpu_to_le32(addrs[i] << (i * 8)); if (naddrs > 4) - q_op->addr2_reg |= addrs[4]; + q_op->addr2_reg |= cpu_to_le32(addrs[4]); q_op->rdy_delay_ns = instr->delay_ns; break; @@ -2663,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) unsigned long start = jiffies + msecs_to_jiffies(time_ms); u32 flash; - nandc_read_buffer_sync(nandc, true); + nandc_dev_to_mem(nandc, true); do { flash = le32_to_cpu(nandc->reg_read_buf[0]); @@ -2706,11 +2660,11 @@ static int qcom_read_status_exec(struct nand_chip *chip, clear_read_regs(nandc); clear_bam_transaction(nandc); - nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ret = submit_descs(nandc); @@ -2719,7 +2673,7 @@ static int qcom_read_status_exec(struct nand_chip *chip, goto err_out; } - nandc_read_buffer_sync(nandc, true); + nandc_dev_to_mem(nandc, true); for (i = 0; i < num_cw; i++) { flash_status = le32_to_cpu(nandc->reg_read_buf[i]); @@ -2763,16 +2717,14 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo clear_read_regs(nandc); clear_bam_transaction(nandc); - nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); - nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); - nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); - nandc_set_reg(chip, NAND_FLASH_CHIP_SELECT, - nandc->props->is_bam ? 0 : DM_EN); - - nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->addr0 = q_op.addr1_reg; + nandc->regs->addr1 = q_op.addr2_reg; + nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN); + nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); @@ -2786,7 +2738,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo op_id = q_op.data_instr_idx; len = nand_subop_get_data_len(subop, op_id); - nandc_read_buffer_sync(nandc, true); + nandc_dev_to_mem(nandc, true); memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); err_out: @@ -2807,15 +2759,14 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub if (q_op.flag == OP_PROGRAM_PAGE) { goto wait_rdy; - } else if (q_op.cmd_reg == OP_BLOCK_ERASE) { - q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; - nandc_set_reg(chip, NAND_ADDR0, q_op.addr1_reg); - nandc_set_reg(chip, NAND_ADDR1, q_op.addr2_reg); - nandc_set_reg(chip, NAND_DEV0_CFG0, - host->cfg0_raw & ~(7 << CW_PER_PAGE)); - nandc_set_reg(chip, NAND_DEV0_CFG1, host->cfg1_raw); + } else if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) { + q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE); + nandc->regs->addr0 = q_op.addr1_reg; + nandc->regs->addr1 = q_op.addr2_reg; + nandc->regs->cfg0 = cpu_to_le32(host->cfg0_raw & ~(7 << CW_PER_PAGE)); + nandc->regs->cfg1 = cpu_to_le32(host->cfg1_raw); instrs = 3; - } else if (q_op.cmd_reg != OP_RESET_DEVICE) { + } else if (q_op.cmd_reg != cpu_to_le32(OP_RESET_DEVICE)) { return 0; } @@ -2826,14 +2777,14 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub clear_read_regs(nandc); clear_bam_transaction(nandc); - nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); - nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); - if (q_op.cmd_reg == OP_BLOCK_ERASE) - write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); + if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) + write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); ret = submit_descs(nandc); @@ -2862,14 +2813,14 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ reg_base = NAND_READ_LOCATION_0; - if (nandc->props->qpic_v2) + if (nandc->props->qpic_version2) reg_base = NAND_READ_LOCATION_LAST_CW_0; ret = qcom_parse_instructions(chip, subop, &q_op); if (ret) return ret; - q_op.cmd_reg |= PAGE_ACC | LAST_PAGE; + q_op.cmd_reg |= cpu_to_le32(PAGE_ACC | LAST_PAGE); nandc->buf_count = 0; nandc->buf_start = 0; @@ -2877,52 +2828,52 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ clear_read_regs(nandc); clear_bam_transaction(nandc); - nandc_set_reg(chip, NAND_FLASH_CMD, q_op.cmd_reg); - - nandc_set_reg(chip, NAND_ADDR0, 0); - nandc_set_reg(chip, NAND_ADDR1, 0); - nandc_set_reg(chip, NAND_DEV0_CFG0, 0 << CW_PER_PAGE - | 512 << UD_SIZE_BYTES - | 5 << NUM_ADDR_CYCLES - | 0 << SPARE_SIZE_BYTES); - nandc_set_reg(chip, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES - | 0 << CS_ACTIVE_BSY - | 17 << BAD_BLOCK_BYTE_NUM - | 1 << BAD_BLOCK_IN_SPARE_AREA - | 2 << WR_RD_BSY_GAP - | 0 << WIDE_FLASH - | 1 << DEV0_CFG1_ECC_DISABLE); - if (!nandc->props->qpic_v2) - nandc_set_reg(chip, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE); + nandc->regs->cmd = q_op.cmd_reg; + nandc->regs->addr0 = 0; + nandc->regs->addr1 = 0; + + nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE | + 512 << UD_SIZE_BYTES | + 5 << NUM_ADDR_CYCLES | + 0 << SPARE_SIZE_BYTES); + + nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES | + 0 << CS_ACTIVE_BSY | + 17 << BAD_BLOCK_BYTE_NUM | + 1 << BAD_BLOCK_IN_SPARE_AREA | + 2 << WR_RD_BSY_GAP | + 0 << WIDE_FLASH | + 1 << DEV0_CFG1_ECC_DISABLE); + + if (!nandc->props->qpic_version2) + nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ - if (!nandc->props->qpic_v2) { - nandc_set_reg(chip, NAND_DEV_CMD_VLD, - (nandc->vld & ~READ_START_VLD)); - nandc_set_reg(chip, NAND_DEV_CMD1, - (nandc->cmd1 & ~(0xFF << READ_ADDR)) - | NAND_CMD_PARAM << READ_ADDR); + if (!nandc->props->qpic_version2) { + nandc->regs->vld = cpu_to_le32((nandc->vld & ~READ_START_VLD)); + nandc->regs->cmd1 = cpu_to_le32((nandc->cmd1 & ~(0xFF << READ_ADDR)) + | NAND_CMD_PARAM << READ_ADDR); } - nandc_set_reg(chip, NAND_EXEC_CMD, 1); + nandc->regs->exec = cpu_to_le32(1); - if (!nandc->props->qpic_v2) { - nandc_set_reg(chip, NAND_DEV_CMD1_RESTORE, nandc->cmd1); - nandc_set_reg(chip, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); + if (!nandc->props->qpic_version2) { + nandc->regs->orig_cmd1 = cpu_to_le32(nandc->cmd1); + nandc->regs->orig_vld = cpu_to_le32(nandc->vld); } instr = q_op.data_instr; op_id = q_op.data_instr_idx; len = nand_subop_get_data_len(subop, op_id); - if (nandc->props->qpic_v2) + if (nandc->props->qpic_version2) nandc_set_read_loc_last(chip, reg_base, 0, len, 1); else nandc_set_read_loc_first(chip, reg_base, 0, len, 1); - if (!nandc->props->qpic_v2) { - write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); - write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + if (!nandc->props->qpic_version2) { + write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); + write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); } nandc->buf_count = 512; @@ -2934,9 +2885,10 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ nandc->buf_count, 0); /* restore CMD1 and VLD regs */ - if (!nandc->props->qpic_v2) { - write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); - write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); + if (!nandc->props->qpic_version2) { + write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); + write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, + NAND_BAM_NEXT_SGL); } ret = submit_descs(nandc); @@ -3025,7 +2977,7 @@ static const struct nand_controller_ops qcom_nandc_ops = { static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) { - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) dma_unmap_single(nandc->dev, nandc->reg_read_dma, MAX_REG_RD * @@ -3078,7 +3030,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) if (!nandc->reg_read_buf) return -ENOMEM; - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { nandc->reg_read_dma = dma_map_single(nandc->dev, nandc->reg_read_buf, MAX_REG_RD * @@ -3159,15 +3111,15 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) u32 nand_ctrl; /* kill onenand */ - if (!nandc->props->is_qpic) + if (!nandc->props->nandc_part_of_qpic) nandc_write(nandc, SFLASHC_BURST_CFG, 0); - if (!nandc->props->qpic_v2) + if (!nandc->props->qpic_version2) nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), NAND_DEV_CMD_VLD_VAL); /* enable ADM or BAM DMA */ - if (nandc->props->is_bam) { + if (nandc->props->supports_bam) { nand_ctrl = nandc_read(nandc, NAND_CTRL); /* @@ -3184,7 +3136,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) } /* save the original values of these registers */ - if (!nandc->props->qpic_v2) { + if (!nandc->props->qpic_version2) { nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1)); nandc->vld = NAND_DEV_CMD_VLD_VAL; } @@ -3357,7 +3309,7 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) struct device_node *np = nandc->dev->of_node; int ret; - if (!nandc->props->is_bam) { + if (!nandc->props->supports_bam) { ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci); if (ret) { @@ -3482,30 +3434,30 @@ static void qcom_nandc_remove(struct platform_device *pdev) static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), - .is_bam = false, + .supports_bam = false, .use_codeword_fixup = true, .dev_cmd_reg_start = 0x0, }; static const struct qcom_nandc_props ipq4019_nandc_props = { .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), - .is_bam = true, - .is_qpic = true, + .supports_bam = true, + .nandc_part_of_qpic = true, .dev_cmd_reg_start = 0x0, }; static const struct qcom_nandc_props ipq8074_nandc_props = { .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), - .is_bam = true, - .is_qpic = true, + .supports_bam = true, + .nandc_part_of_qpic = true, .dev_cmd_reg_start = 0x7000, }; static const struct qcom_nandc_props sdx55_nandc_props = { .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), - .is_bam = true, - .is_qpic = true, - .qpic_v2 = true, + .supports_bam = true, + .nandc_part_of_qpic = true, + .qpic_version2 = true, .dev_cmd_reg_start = 0x7000, }; -- 2.51.0 From 3eb84d95e970b09e7ceeff3bcae17bd351aeabe0 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 20 Nov 2024 14:45:01 +0530 Subject: [PATCH 011/517] mtd: rawnand: qcom: Add qcom prefix to common api Add qcom prefix to all the api which will be commonly used by spi nand driver and raw nand driver. Reviewed-by: Konrad Dybcio Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/qcom_nandc.c | 320 +++++++++++++++--------------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 94a57a0de067..ee73876f7244 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -53,7 +53,7 @@ #define NAND_READ_LOCATION_LAST_CW_2 0xf48 #define NAND_READ_LOCATION_LAST_CW_3 0xf4c -/* dummy register offsets, used by write_reg_dma */ +/* dummy register offsets, used by qcom_write_reg_dma */ #define NAND_DEV_CMD1_RESTORE 0xdead #define NAND_DEV_CMD_VLD_RESTORE 0xbeef @@ -211,7 +211,7 @@ /* * Flags used in DMA descriptor preparation helper functions - * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma) + * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) */ /* Don't set the EOT in current tx BAM sgl */ #define NAND_BAM_NO_EOT BIT(0) @@ -550,7 +550,7 @@ struct qcom_nandc_props { }; /* Frees the BAM transaction memory */ -static void free_bam_transaction(struct qcom_nand_controller *nandc) +static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) { struct bam_transaction *bam_txn = nandc->bam_txn; @@ -559,7 +559,7 @@ static void free_bam_transaction(struct qcom_nand_controller *nandc) /* Allocates and Initializes the BAM transaction */ static struct bam_transaction * -alloc_bam_transaction(struct qcom_nand_controller *nandc) +qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) { struct bam_transaction *bam_txn; size_t bam_txn_size; @@ -595,7 +595,7 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) } /* Clears the BAM transaction indexes */ -static void clear_bam_transaction(struct qcom_nand_controller *nandc) +static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) { struct bam_transaction *bam_txn = nandc->bam_txn; @@ -614,7 +614,7 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc) } /* Callback for DMA descriptor completion */ -static void qpic_bam_dma_done(void *data) +static void qcom_qpic_bam_dma_done(void *data) { struct bam_transaction *bam_txn = data; @@ -644,7 +644,7 @@ static void nandc_write(struct qcom_nand_controller *nandc, int offset, iowrite32(val, nandc->base + offset); } -static void nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) +static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) { if (!nandc->props->supports_bam) return; @@ -824,9 +824,9 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i * for BAM. This descriptor will be added in the NAND DMA descriptor queue * which will be submitted to DMA engine. */ -static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, - struct dma_chan *chan, - unsigned long flags) +static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, + struct dma_chan *chan, + unsigned long flags) { struct desc_info *desc; struct scatterlist *sgl; @@ -903,9 +903,9 @@ static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, * NAND_BAM_NEXT_SGL will be used for starting the separate SGL * after the current command element. */ -static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, - int size, unsigned int flags) +static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, + int size, unsigned int flags) { int bam_ce_size; int i, ret; @@ -943,9 +943,9 @@ static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, bam_txn->bam_ce_start = bam_txn->bam_ce_pos; if (flags & NAND_BAM_NWD) { - ret = prepare_bam_async_desc(nandc, nandc->cmd_chan, - DMA_PREP_FENCE | - DMA_PREP_CMD); + ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, + DMA_PREP_FENCE | + DMA_PREP_CMD); if (ret) return ret; } @@ -958,9 +958,8 @@ static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, * Prepares the data descriptor for BAM DMA which will be used for NAND * data reads and writes. */ -static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, - const void *vaddr, - int size, unsigned int flags) +static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + const void *vaddr, int size, unsigned int flags) { int ret; struct bam_transaction *bam_txn = nandc->bam_txn; @@ -979,8 +978,8 @@ static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, * is not set, form the DMA descriptor */ if (!(flags & NAND_BAM_NO_EOT)) { - ret = prepare_bam_async_desc(nandc, nandc->tx_chan, - DMA_PREP_INTERRUPT); + ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); if (ret) return ret; } @@ -989,9 +988,9 @@ static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, return 0; } -static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, int size, - bool flow_control) +static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, int size, + bool flow_control) { struct desc_info *desc; struct dma_async_tx_descriptor *dma_desc; @@ -1069,15 +1068,15 @@ static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, } /* - * read_reg_dma: prepares a descriptor to read a given number of + * qcom_read_reg_dma: prepares a descriptor to read a given number of * contiguous registers to the reg_read_buf pointer * * @first: offset of the first register in the contiguous block * @num_regs: number of registers to read * @flags: flags to control DMA descriptor preparation */ -static int read_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs, unsigned int flags) +static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, + int num_regs, unsigned int flags) { bool flow_control = false; void *vaddr; @@ -1089,18 +1088,18 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, first = dev_cmd_reg_addr(nandc, first); if (nandc->props->supports_bam) - return prep_bam_dma_desc_cmd(nandc, true, first, vaddr, + return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, num_regs, flags); if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) flow_control = true; - return prep_adm_dma_desc(nandc, true, first, vaddr, + return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, num_regs * sizeof(u32), flow_control); } /* - * write_reg_dma: prepares a descriptor to write a given number of + * qcom_write_reg_dma: prepares a descriptor to write a given number of * contiguous registers * * @vaddr: contiguous memory from where register value will @@ -1109,8 +1108,8 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, * @num_regs: number of registers to write * @flags: flags to control DMA descriptor preparation */ -static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, - int first, int num_regs, unsigned int flags) +static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, + int first, int num_regs, unsigned int flags) { bool flow_control = false; @@ -1124,18 +1123,18 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); if (nandc->props->supports_bam) - return prep_bam_dma_desc_cmd(nandc, false, first, vaddr, + return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, num_regs, flags); if (first == NAND_FLASH_CMD) flow_control = true; - return prep_adm_dma_desc(nandc, false, first, vaddr, + return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, num_regs * sizeof(u32), flow_control); } /* - * read_data_dma: prepares a DMA descriptor to transfer data from the + * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the * controller's internal buffer to the buffer 'vaddr' * * @reg_off: offset within the controller's data buffer @@ -1143,17 +1142,17 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, * @size: DMA transaction size in bytes * @flags: flags to control DMA descriptor preparation */ -static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size, unsigned int flags) +static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) { if (nandc->props->supports_bam) - return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); - return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); + return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } /* - * write_data_dma: prepares a DMA descriptor to transfer data from + * qcom_write_data_dma: prepares a DMA descriptor to transfer data from * 'vaddr' to the controller's internal buffer * * @reg_off: offset within the controller's data buffer @@ -1161,13 +1160,13 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, * @size: DMA transaction size in bytes * @flags: flags to control DMA descriptor preparation */ -static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size, unsigned int flags) +static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) { if (nandc->props->supports_bam) - return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); - return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); + return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } /* @@ -1178,14 +1177,14 @@ static void config_nand_page_read(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); - write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); if (!nandc->props->qpic_version2) - write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); - write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, - NAND_ERASED_CW_DETECT_CFG, 1, 0); - write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, - NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); } /* @@ -1204,17 +1203,17 @@ config_nand_cw_read(struct nand_chip *chip, bool use_ecc, int cw) reg = &nandc->regs->read_location_last0; if (nandc->props->supports_bam) - write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); if (use_ecc) { - read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); - read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, - NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); + qcom_read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, + NAND_BAM_NEXT_SGL); } else { - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); } } @@ -1238,11 +1237,11 @@ static void config_nand_page_write(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); - write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(nandc, &nandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); if (!nandc->props->qpic_version2) - write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, - NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, + NAND_BAM_NEXT_SGL); } /* @@ -1253,17 +1252,18 @@ static void config_nand_cw_write(struct nand_chip *chip) { struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); - write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->clrreadstatus, NAND_READ_STATUS, 1, + NAND_BAM_NEXT_SGL); } /* helpers to submit/free our list of dma descriptors */ -static int submit_descs(struct qcom_nand_controller *nandc) +static int qcom_submit_descs(struct qcom_nand_controller *nandc) { struct desc_info *desc, *n; dma_cookie_t cookie = 0; @@ -1272,21 +1272,21 @@ static int submit_descs(struct qcom_nand_controller *nandc) if (nandc->props->supports_bam) { if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { - ret = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); if (ret) goto err_unmap_free_desc; } if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { - ret = prepare_bam_async_desc(nandc, nandc->tx_chan, - DMA_PREP_INTERRUPT); + ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); if (ret) goto err_unmap_free_desc; } if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { - ret = prepare_bam_async_desc(nandc, nandc->cmd_chan, - DMA_PREP_CMD); + ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, + DMA_PREP_CMD); if (ret) goto err_unmap_free_desc; } @@ -1296,7 +1296,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) cookie = dmaengine_submit(desc->dma_desc); if (nandc->props->supports_bam) { - bam_txn->last_cmd_desc->callback = qpic_bam_dma_done; + bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; bam_txn->last_cmd_desc->callback_param = bam_txn; dma_async_issue_pending(nandc->tx_chan); @@ -1314,7 +1314,7 @@ static int submit_descs(struct qcom_nand_controller *nandc) err_unmap_free_desc: /* * Unmap the dma sg_list and free the desc allocated by both - * prepare_bam_async_desc() and prep_adm_dma_desc() functions. + * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. */ list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { list_del(&desc->node); @@ -1333,10 +1333,10 @@ static int submit_descs(struct qcom_nand_controller *nandc) } /* reset the register read buffer for next NAND operation */ -static void clear_read_regs(struct qcom_nand_controller *nandc) +static void qcom_clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; - nandc_dev_to_mem(nandc, false); + qcom_nandc_dev_to_mem(nandc, false); } /* @@ -1400,7 +1400,7 @@ static int check_flash_errors(struct qcom_nand_host *host, int cw_cnt) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int i; - nandc_dev_to_mem(nandc, true); + qcom_nandc_dev_to_mem(nandc, true); for (i = 0; i < cw_cnt; i++) { u32 flash = le32_to_cpu(nandc->reg_read_buf[i]); @@ -1427,13 +1427,13 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, nand_read_page_op(chip, page, 0, NULL, 0); nandc->buf_count = 0; nandc->buf_start = 0; - clear_read_regs(nandc); + qcom_clear_read_regs(nandc); host->use_ecc = false; if (nandc->props->qpic_version2) raw_cw = ecc->steps - 1; - clear_bam_transaction(nandc); + qcom_clear_bam_transaction(nandc); set_address(host, host->cw_size * cw, page); update_rw_regs(host, 1, true, raw_cw); config_nand_page_read(chip); @@ -1466,18 +1466,18 @@ qcom_nandc_read_cw_raw(struct mtd_info *mtd, struct nand_chip *chip, config_nand_cw_read(chip, false, raw_cw); - read_data_dma(nandc, reg_off, data_buf, data_size1, 0); + qcom_read_data_dma(nandc, reg_off, data_buf, data_size1, 0); reg_off += data_size1; - read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); + qcom_read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); reg_off += oob_size1; - read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0); + qcom_read_data_dma(nandc, reg_off, data_buf + data_size1, data_size2, 0); reg_off += data_size2; - read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0); + qcom_read_data_dma(nandc, reg_off, oob_buf + oob_size1, oob_size2, 0); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to read raw cw %d\n", cw); return ret; @@ -1575,7 +1575,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, u8 *data_buf_start = data_buf, *oob_buf_start = oob_buf; buf = (struct read_stats *)nandc->reg_read_buf; - nandc_dev_to_mem(nandc, true); + qcom_nandc_dev_to_mem(nandc, true); for (i = 0; i < ecc->steps; i++, buf++) { u32 flash, buffer, erased_cw; @@ -1704,8 +1704,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, config_nand_cw_read(chip, true, i); if (data_buf) - read_data_dma(nandc, FLASH_BUF_ACC, data_buf, - data_size, 0); + qcom_read_data_dma(nandc, FLASH_BUF_ACC, data_buf, + data_size, 0); /* * when ecc is enabled, the controller doesn't read the real @@ -1720,8 +1720,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, for (j = 0; j < host->bbm_size; j++) *oob_buf++ = 0xff; - read_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size, 0); + qcom_read_data_dma(nandc, FLASH_BUF_ACC + data_size, + oob_buf, oob_size, 0); } if (data_buf) @@ -1730,7 +1730,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_buf += oob_size; } - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to read page/oob\n"); return ret; @@ -1751,7 +1751,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) int size; int ret; - clear_read_regs(nandc); + qcom_clear_read_regs(nandc); size = host->use_ecc ? host->cw_data : host->cw_size; @@ -1763,9 +1763,9 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) config_nand_single_cw_page_read(chip, host->use_ecc, ecc->steps - 1); - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); + qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) dev_err(nandc->dev, "failed to copy last codeword\n"); @@ -1851,14 +1851,14 @@ static int qcom_nandc_read_page(struct nand_chip *chip, u8 *buf, nandc->buf_count = 0; nandc->buf_start = 0; host->use_ecc = true; - clear_read_regs(nandc); + qcom_clear_read_regs(nandc); set_address(host, 0, page); update_rw_regs(host, ecc->steps, true, 0); data_buf = buf; oob_buf = oob_required ? chip->oob_poi : NULL; - clear_bam_transaction(nandc); + qcom_clear_bam_transaction(nandc); return read_page_ecc(host, data_buf, oob_buf, page); } @@ -1899,8 +1899,8 @@ static int qcom_nandc_read_oob(struct nand_chip *chip, int page) if (host->nr_boot_partitions) qcom_nandc_codeword_fixup(host, page); - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); host->use_ecc = true; set_address(host, 0, page); @@ -1927,8 +1927,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, set_address(host, 0, page); nandc->buf_count = 0; nandc->buf_start = 0; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -1949,8 +1949,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, oob_size = ecc->bytes; } - write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, - i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); + qcom_write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, + i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); /* * when ECC is enabled, we don't really need to write anything @@ -1962,8 +1962,8 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, if (qcom_nandc_is_last_cw(ecc, i)) { oob_buf += host->bbm_size; - write_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size, 0); + qcom_write_data_dma(nandc, FLASH_BUF_ACC + data_size, + oob_buf, oob_size, 0); } config_nand_cw_write(chip); @@ -1972,7 +1972,7 @@ static int qcom_nandc_write_page(struct nand_chip *chip, const u8 *buf, oob_buf += oob_size; } - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to write page\n"); return ret; @@ -1997,8 +1997,8 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, qcom_nandc_codeword_fixup(host, page); nand_prog_page_begin_op(chip, page, 0, NULL, 0); - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -2024,28 +2024,28 @@ static int qcom_nandc_write_page_raw(struct nand_chip *chip, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - write_data_dma(nandc, reg_off, data_buf, data_size1, - NAND_BAM_NO_EOT); + qcom_write_data_dma(nandc, reg_off, data_buf, data_size1, + NAND_BAM_NO_EOT); reg_off += data_size1; data_buf += data_size1; - write_data_dma(nandc, reg_off, oob_buf, oob_size1, - NAND_BAM_NO_EOT); + qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size1, + NAND_BAM_NO_EOT); reg_off += oob_size1; oob_buf += oob_size1; - write_data_dma(nandc, reg_off, data_buf, data_size2, - NAND_BAM_NO_EOT); + qcom_write_data_dma(nandc, reg_off, data_buf, data_size2, + NAND_BAM_NO_EOT); reg_off += data_size2; data_buf += data_size2; - write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); + qcom_write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; config_nand_cw_write(chip); } - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to write raw page\n"); return ret; @@ -2075,7 +2075,7 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) qcom_nandc_codeword_fixup(host, page); host->use_ecc = true; - clear_bam_transaction(nandc); + qcom_clear_bam_transaction(nandc); /* calculate the data and oob size for the last codeword/step */ data_size = ecc->size - ((ecc->steps - 1) << 2); @@ -2090,11 +2090,11 @@ static int qcom_nandc_write_oob(struct nand_chip *chip, int page) update_rw_regs(host, 1, false, 0); config_nand_page_write(chip); - write_data_dma(nandc, FLASH_BUF_ACC, - nandc->data_buffer, data_size + oob_size, 0); + qcom_write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, data_size + oob_size, 0); config_nand_cw_write(chip); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to write oob\n"); return ret; @@ -2121,7 +2121,7 @@ static int qcom_nandc_block_bad(struct nand_chip *chip, loff_t ofs) */ host->use_ecc = false; - clear_bam_transaction(nandc); + qcom_clear_bam_transaction(nandc); ret = copy_last_cw(host, page); if (ret) goto err; @@ -2148,8 +2148,8 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) struct nand_ecc_ctrl *ecc = &chip->ecc; int page, ret; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); /* * to mark the BBM as bad, we flash the entire last codeword with 0s. @@ -2166,11 +2166,11 @@ static int qcom_nandc_block_markbad(struct nand_chip *chip, loff_t ofs) update_rw_regs(host, 1, false, ecc->steps - 1); config_nand_page_write(chip); - write_data_dma(nandc, FLASH_BUF_ACC, - nandc->data_buffer, host->cw_size, 0); + qcom_write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, host->cw_size, 0); config_nand_cw_write(chip); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure to update BBM\n"); return ret; @@ -2410,14 +2410,14 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); /* Free the initially allocated BAM transaction for reading the ONFI params */ if (nandc->props->supports_bam) - free_bam_transaction(nandc); + qcom_free_bam_transaction(nandc); nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, cwperpage); /* Now allocate the BAM transaction based on updated max_cwperpage */ if (nandc->props->supports_bam) { - nandc->bam_txn = alloc_bam_transaction(nandc); + nandc->bam_txn = qcom_alloc_bam_transaction(nandc); if (!nandc->bam_txn) { dev_err(nandc->dev, "failed to allocate bam transaction\n"); @@ -2617,7 +2617,7 @@ static int qcom_wait_rdy_poll(struct nand_chip *chip, unsigned int time_ms) unsigned long start = jiffies + msecs_to_jiffies(time_ms); u32 flash; - nandc_dev_to_mem(nandc, true); + qcom_nandc_dev_to_mem(nandc, true); do { flash = le32_to_cpu(nandc->reg_read_buf[0]); @@ -2657,23 +2657,23 @@ static int qcom_read_status_exec(struct nand_chip *chip, nandc->buf_start = 0; host->use_ecc = false; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); nandc->regs->cmd = q_op.cmd_reg; nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure in submitting status descriptor\n"); goto err_out; } - nandc_dev_to_mem(nandc, true); + qcom_nandc_dev_to_mem(nandc, true); for (i = 0; i < num_cw; i++) { flash_status = le32_to_cpu(nandc->reg_read_buf[i]); @@ -2714,8 +2714,8 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo nandc->buf_start = 0; host->use_ecc = false; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); nandc->regs->cmd = q_op.cmd_reg; nandc->regs->addr0 = q_op.addr1_reg; @@ -2723,12 +2723,12 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo nandc->regs->chip_sel = cpu_to_le32(nandc->props->supports_bam ? 0 : DM_EN); nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure in submitting read id descriptor\n"); goto err_out; @@ -2738,7 +2738,7 @@ static int qcom_read_id_type_exec(struct nand_chip *chip, const struct nand_subo op_id = q_op.data_instr_idx; len = nand_subop_get_data_len(subop, op_id); - nandc_dev_to_mem(nandc, true); + qcom_nandc_dev_to_mem(nandc, true); memcpy(instr->ctx.data.buf.in, nandc->reg_read_buf, len); err_out: @@ -2774,20 +2774,20 @@ static int qcom_misc_cmd_type_exec(struct nand_chip *chip, const struct nand_sub nandc->buf_start = 0; host->use_ecc = false; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); nandc->regs->cmd = q_op.cmd_reg; nandc->regs->exec = cpu_to_le32(1); - write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cmd, NAND_FLASH_CMD, instrs, NAND_BAM_NEXT_SGL); if (q_op.cmd_reg == cpu_to_le32(OP_BLOCK_ERASE)) - write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure in submitting misc descriptor\n"); goto err_out; @@ -2825,8 +2825,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ nandc->buf_count = 0; nandc->buf_start = 0; host->use_ecc = false; - clear_read_regs(nandc); - clear_bam_transaction(nandc); + qcom_clear_read_regs(nandc); + qcom_clear_bam_transaction(nandc); nandc->regs->cmd = q_op.cmd_reg; nandc->regs->addr0 = 0; @@ -2872,8 +2872,8 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ nandc_set_read_loc_first(chip, reg_base, 0, len, 1); if (!nandc->props->qpic_version2) { - write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); - write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->vld, NAND_DEV_CMD_VLD, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->cmd1, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); } nandc->buf_count = 512; @@ -2881,17 +2881,17 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ config_nand_single_cw_page_read(chip, false, 0); - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - nandc->buf_count, 0); + qcom_read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, + nandc->buf_count, 0); /* restore CMD1 and VLD regs */ if (!nandc->props->qpic_version2) { - write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); - write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, - NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(nandc, &nandc->regs->orig_cmd1, NAND_DEV_CMD1_RESTORE, 1, 0); + qcom_write_reg_dma(nandc, &nandc->regs->orig_vld, NAND_DEV_CMD_VLD_RESTORE, 1, + NAND_BAM_NEXT_SGL); } - ret = submit_descs(nandc); + ret = qcom_submit_descs(nandc); if (ret) { dev_err(nandc->dev, "failure in submitting param page descriptor\n"); goto err_out; @@ -3075,7 +3075,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) * maximum codeword size */ nandc->max_cwperpage = 1; - nandc->bam_txn = alloc_bam_transaction(nandc); + nandc->bam_txn = qcom_alloc_bam_transaction(nandc); if (!nandc->bam_txn) { dev_err(nandc->dev, "failed to allocate bam transaction\n"); -- 2.51.0 From 6c04b5738159ccfc2447219245c49e71c7428db0 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 20 Nov 2024 14:45:02 +0530 Subject: [PATCH 012/517] mtd: nand: Add qpic_common API file Add qpic_common.c file which hold all the common qpic APIs which will be used by both qpic raw nand driver and qpic spi nand driver. Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/qpic_common.c | 759 ++++++++++++++++++ drivers/mtd/nand/raw/qcom_nandc.c | 1092 +------------------------- include/linux/mtd/nand-qpic-common.h | 468 +++++++++++ 4 files changed, 1240 insertions(+), 1081 deletions(-) create mode 100644 drivers/mtd/nand/qpic_common.c create mode 100644 include/linux/mtd/nand-qpic-common.h diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 19e1291ac4d5..da1586a36574 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -3,7 +3,7 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o - +obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o obj-y += onenand/ obj-y += raw/ obj-y += spi/ diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c new file mode 100644 index 000000000000..8abbb960a7ce --- /dev/null +++ b/drivers/mtd/nand/qpic_common.c @@ -0,0 +1,759 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * qcom_free_bam_transaction() - Frees the BAM transaction memory + * @nandc: qpic nand controller + * + * This function frees the bam transaction memory + */ +void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + kfree(bam_txn); +} +EXPORT_SYMBOL(qcom_free_bam_transaction); + +/** + * qcom_alloc_bam_transaction() - allocate BAM transaction + * @nandc: qpic nand controller + * + * This function will allocate and initialize the BAM transaction structure + */ +struct bam_transaction * +qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn; + size_t bam_txn_size; + unsigned int num_cw = nandc->max_cwperpage; + void *bam_txn_buf; + + bam_txn_size = + sizeof(*bam_txn) + num_cw * + ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) + + (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + + (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); + + bam_txn_buf = kzalloc(bam_txn_size, GFP_KERNEL); + if (!bam_txn_buf) + return NULL; + + bam_txn = bam_txn_buf; + bam_txn_buf += sizeof(*bam_txn); + + bam_txn->bam_ce = bam_txn_buf; + bam_txn_buf += + sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw; + + bam_txn->cmd_sgl = bam_txn_buf; + bam_txn_buf += + sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; + + bam_txn->data_sgl = bam_txn_buf; + + init_completion(&bam_txn->txn_done); + + return bam_txn; +} +EXPORT_SYMBOL(qcom_alloc_bam_transaction); + +/** + * qcom_clear_bam_transaction() - Clears the BAM transaction + * @nandc: qpic nand controller + * + * This function will clear the BAM transaction indexes. + */ +void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (!nandc->props->supports_bam) + return; + + memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); + bam_txn->last_data_desc = NULL; + + sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * + QPIC_PER_CW_CMD_SGL); + sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * + QPIC_PER_CW_DATA_SGL); + + reinit_completion(&bam_txn->txn_done); +} +EXPORT_SYMBOL(qcom_clear_bam_transaction); + +/** + * qcom_qpic_bam_dma_done() - Callback for DMA descriptor completion + * @data: data pointer + * + * This function is a callback for DMA descriptor completion + */ +void qcom_qpic_bam_dma_done(void *data) +{ + struct bam_transaction *bam_txn = data; + + complete(&bam_txn->txn_done); +} +EXPORT_SYMBOL(qcom_qpic_bam_dma_done); + +/** + * qcom_nandc_dev_to_mem() - Check for dma sync for cpu or device + * @nandc: qpic nand controller + * @is_cpu: cpu or Device + * + * This function will check for dma sync for cpu or device + */ +inline void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) +{ + if (!nandc->props->supports_bam) + return; + + if (is_cpu) + dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + else + dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); +} +EXPORT_SYMBOL(qcom_nandc_dev_to_mem); + +/** + * qcom_prepare_bam_async_desc() - Prepare DMA descriptor + * @nandc: qpic nand controller + * @chan: dma channel + * @flags: flags to control DMA descriptor preparation + * + * This function maps the scatter gather list for DMA transfer and forms the + * DMA descriptor for BAM.This descriptor will be added in the NAND DMA + * descriptor queue which will be submitted to DMA engine. + */ +int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, + struct dma_chan *chan, unsigned long flags) +{ + struct desc_info *desc; + struct scatterlist *sgl; + unsigned int sgl_cnt; + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + enum dma_transfer_direction dir_eng; + struct dma_async_tx_descriptor *dma_desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + if (chan == nandc->cmd_chan) { + sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; + sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; + bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else if (chan == nandc->tx_chan) { + sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; + sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; + bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else { + sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; + sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; + bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; + dir_eng = DMA_DEV_TO_MEM; + desc->dir = DMA_FROM_DEVICE; + } + + sg_mark_end(sgl + sgl_cnt - 1); + ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + if (ret == 0) { + dev_err(nandc->dev, "failure in mapping desc\n"); + kfree(desc); + return -ENOMEM; + } + + desc->sgl_cnt = sgl_cnt; + desc->bam_sgl = sgl; + + dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, + flags); + + if (!dma_desc) { + dev_err(nandc->dev, "failure in prep desc\n"); + dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + kfree(desc); + return -EINVAL; + } + + desc->dma_desc = dma_desc; + + /* update last data/command descriptor */ + if (chan == nandc->cmd_chan) + bam_txn->last_cmd_desc = dma_desc; + else + bam_txn->last_data_desc = dma_desc; + + list_add_tail(&desc->node, &nandc->desc_list); + + return 0; +} +EXPORT_SYMBOL(qcom_prepare_bam_async_desc); + +/** + * qcom_prep_bam_dma_desc_cmd() - Prepares the command descriptor for BAM DMA + * @nandc: qpic nand controller + * @read: read or write type + * @reg_off: offset within the controller's data buffer + * @vaddr: virtual address of the buffer we want to write to + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares the command descriptor for BAM DMA + * which will be used for NAND register reads and writes. + */ +int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, + int size, unsigned int flags) +{ + int bam_ce_size; + int i, ret; + struct bam_cmd_element *bam_ce_buffer; + struct bam_transaction *bam_txn = nandc->bam_txn; + + bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos]; + + /* fill the command desc */ + for (i = 0; i < size; i++) { + if (read) + bam_prep_ce(&bam_ce_buffer[i], + nandc_reg_phys(nandc, reg_off + 4 * i), + BAM_READ_COMMAND, + reg_buf_dma_addr(nandc, + (__le32 *)vaddr + i)); + else + bam_prep_ce_le32(&bam_ce_buffer[i], + nandc_reg_phys(nandc, reg_off + 4 * i), + BAM_WRITE_COMMAND, + *((__le32 *)vaddr + i)); + } + + bam_txn->bam_ce_pos += size; + + /* use the separate sgl after this command */ + if (flags & NAND_BAM_NEXT_SGL) { + bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start]; + bam_ce_size = (bam_txn->bam_ce_pos - + bam_txn->bam_ce_start) * + sizeof(struct bam_cmd_element); + sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos], + bam_ce_buffer, bam_ce_size); + bam_txn->cmd_sgl_pos++; + bam_txn->bam_ce_start = bam_txn->bam_ce_pos; + + if (flags & NAND_BAM_NWD) { + ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, + DMA_PREP_FENCE | DMA_PREP_CMD); + if (ret) + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(qcom_prep_bam_dma_desc_cmd); + +/** + * qcom_prep_bam_dma_desc_data() - Prepares the data descriptor for BAM DMA + * @nandc: qpic nand controller + * @read: read or write type + * @vaddr: virtual address of the buffer we want to write to + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares the data descriptor for BAM DMA which + * will be used for NAND data reads and writes. + */ +int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + const void *vaddr, int size, unsigned int flags) +{ + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (read) { + sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], + vaddr, size); + bam_txn->rx_sgl_pos++; + } else { + sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], + vaddr, size); + bam_txn->tx_sgl_pos++; + + /* + * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag + * is not set, form the DMA descriptor + */ + if (!(flags & NAND_BAM_NO_EOT)) { + ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (ret) + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(qcom_prep_bam_dma_desc_data); + +/** + * qcom_prep_adm_dma_desc() - Prepare descriptor for adma + * @nandc: qpic nand controller + * @read: read or write type + * @reg_off: offset within the controller's data buffer + * @vaddr: virtual address of the buffer we want to write to + * @size: adm dma transaction size in bytes + * @flow_control: flow controller + * + * This function will prepare descriptor for adma + */ +int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, int size, + bool flow_control) +{ + struct qcom_adm_peripheral_config periph_conf = {}; + struct dma_async_tx_descriptor *dma_desc; + struct dma_slave_config slave_conf = {0}; + enum dma_transfer_direction dir_eng; + struct desc_info *desc; + struct scatterlist *sgl; + int ret; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + sgl = &desc->adm_sgl; + + sg_init_one(sgl, vaddr, size); + + if (read) { + dir_eng = DMA_DEV_TO_MEM; + desc->dir = DMA_FROM_DEVICE; + } else { + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } + + ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir); + if (!ret) { + ret = -ENOMEM; + goto err; + } + + slave_conf.device_fc = flow_control; + if (read) { + slave_conf.src_maxburst = 16; + slave_conf.src_addr = nandc->base_dma + reg_off; + if (nandc->data_crci) { + periph_conf.crci = nandc->data_crci; + slave_conf.peripheral_config = &periph_conf; + slave_conf.peripheral_size = sizeof(periph_conf); + } + } else { + slave_conf.dst_maxburst = 16; + slave_conf.dst_addr = nandc->base_dma + reg_off; + if (nandc->cmd_crci) { + periph_conf.crci = nandc->cmd_crci; + slave_conf.peripheral_config = &periph_conf; + slave_conf.peripheral_size = sizeof(periph_conf); + } + } + + ret = dmaengine_slave_config(nandc->chan, &slave_conf); + if (ret) { + dev_err(nandc->dev, "failed to configure dma channel\n"); + goto err; + } + + dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0); + if (!dma_desc) { + dev_err(nandc->dev, "failed to prepare desc\n"); + ret = -EINVAL; + goto err; + } + + desc->dma_desc = dma_desc; + + list_add_tail(&desc->node, &nandc->desc_list); + + return 0; +err: + kfree(desc); + + return ret; +} +EXPORT_SYMBOL(qcom_prep_adm_dma_desc); + +/** + * qcom_read_reg_dma() - read a given number of registers to the reg_read_buf pointer + * @nandc: qpic nand controller + * @first: offset of the first register in the contiguous block + * @num_regs: number of registers to read + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares a descriptor to read a given number of + * contiguous registers to the reg_read_buf pointer. + */ +int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, + int num_regs, unsigned int flags) +{ + bool flow_control = false; + void *vaddr; + + vaddr = nandc->reg_read_buf + nandc->reg_read_pos; + nandc->reg_read_pos += num_regs; + + if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, first); + + if (nandc->props->supports_bam) + return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, + num_regs, flags); + + if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) + flow_control = true; + + return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, + num_regs * sizeof(u32), flow_control); +} +EXPORT_SYMBOL(qcom_read_reg_dma); + +/** + * qcom_write_reg_dma() - write a given number of registers + * @nandc: qpic nand controller + * @vaddr: contiguous memory from where register value will + * be written + * @first: offset of the first register in the contiguous block + * @num_regs: number of registers to write + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares a descriptor to write a given number of + * contiguous registers + */ +int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, + int first, int num_regs, unsigned int flags) +{ + bool flow_control = false; + + if (first == NAND_EXEC_CMD) + flags |= NAND_BAM_NWD; + + if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); + + if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); + + if (nandc->props->supports_bam) + return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, + num_regs, flags); + + if (first == NAND_FLASH_CMD) + flow_control = true; + + return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, + num_regs * sizeof(u32), flow_control); +} +EXPORT_SYMBOL(qcom_write_reg_dma); + +/** + * qcom_read_data_dma() - transfer data + * @nandc: qpic nand controller + * @reg_off: offset within the controller's data buffer + * @vaddr: virtual address of the buffer we want to write to + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares a DMA descriptor to transfer data from the + * controller's internal buffer to the buffer 'vaddr' + */ +int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) +{ + if (nandc->props->supports_bam) + return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + + return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); +} +EXPORT_SYMBOL(qcom_read_data_dma); + +/** + * qcom_write_data_dma() - transfer data + * @nandc: qpic nand controller + * @reg_off: offset within the controller's data buffer + * @vaddr: virtual address of the buffer we want to read from + * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation + * + * This function will prepares a DMA descriptor to transfer data from + * 'vaddr' to the controller's internal buffer + */ +int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, + const u8 *vaddr, int size, unsigned int flags) +{ + if (nandc->props->supports_bam) + return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + + return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); +} +EXPORT_SYMBOL(qcom_write_data_dma); + +/** + * qcom_submit_descs() - submit dma descriptor + * @nandc: qpic nand controller + * + * This function will submit all the prepared dma descriptor + * cmd or data descriptor + */ +int qcom_submit_descs(struct qcom_nand_controller *nandc) +{ + struct desc_info *desc, *n; + dma_cookie_t cookie = 0; + struct bam_transaction *bam_txn = nandc->bam_txn; + int ret = 0; + + if (nandc->props->supports_bam) { + if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { + ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + if (ret) + goto err_unmap_free_desc; + } + + if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { + ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (ret) + goto err_unmap_free_desc; + } + + if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { + ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, + DMA_PREP_CMD); + if (ret) + goto err_unmap_free_desc; + } + } + + list_for_each_entry(desc, &nandc->desc_list, node) + cookie = dmaengine_submit(desc->dma_desc); + + if (nandc->props->supports_bam) { + bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; + bam_txn->last_cmd_desc->callback_param = bam_txn; + + dma_async_issue_pending(nandc->tx_chan); + dma_async_issue_pending(nandc->rx_chan); + dma_async_issue_pending(nandc->cmd_chan); + + if (!wait_for_completion_timeout(&bam_txn->txn_done, + QPIC_NAND_COMPLETION_TIMEOUT)) + ret = -ETIMEDOUT; + } else { + if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) + ret = -ETIMEDOUT; + } + +err_unmap_free_desc: + /* + * Unmap the dma sg_list and free the desc allocated by both + * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. + */ + list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { + list_del(&desc->node); + + if (nandc->props->supports_bam) + dma_unmap_sg(nandc->dev, desc->bam_sgl, + desc->sgl_cnt, desc->dir); + else + dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, + desc->dir); + + kfree(desc); + } + + return ret; +} +EXPORT_SYMBOL(qcom_submit_descs); + +/** + * qcom_clear_read_regs() - reset the read register buffer + * @nandc: qpic nand controller + * + * This function reset the register read buffer for next NAND operation + */ +void qcom_clear_read_regs(struct qcom_nand_controller *nandc) +{ + nandc->reg_read_pos = 0; + qcom_nandc_dev_to_mem(nandc, false); +} +EXPORT_SYMBOL(qcom_clear_read_regs); + +/** + * qcom_nandc_unalloc() - unallocate qpic nand controller + * @nandc: qpic nand controller + * + * This function will unallocate memory alloacted for qpic nand controller + */ +void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) +{ + if (nandc->props->supports_bam) { + if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) + dma_unmap_single(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + + if (nandc->tx_chan) + dma_release_channel(nandc->tx_chan); + + if (nandc->rx_chan) + dma_release_channel(nandc->rx_chan); + + if (nandc->cmd_chan) + dma_release_channel(nandc->cmd_chan); + } else { + if (nandc->chan) + dma_release_channel(nandc->chan); + } +} +EXPORT_SYMBOL(qcom_nandc_unalloc); + +/** + * qcom_nandc_alloc() - Allocate qpic nand controller + * @nandc: qpic nand controller + * + * This function will allocate memory for qpic nand controller + */ +int qcom_nandc_alloc(struct qcom_nand_controller *nandc) +{ + int ret; + + ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(nandc->dev, "failed to set DMA mask\n"); + return ret; + } + + /* + * we use the internal buffer for reading ONFI params, reading small + * data like ID and status, and preforming read-copy-write operations + * when writing to a codeword partially. 532 is the maximum possible + * size of a codeword for our nand controller + */ + nandc->buf_size = 532; + + nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL); + if (!nandc->data_buffer) + return -ENOMEM; + + nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL); + if (!nandc->regs) + return -ENOMEM; + + nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD, + sizeof(*nandc->reg_read_buf), + GFP_KERNEL); + if (!nandc->reg_read_buf) + return -ENOMEM; + + if (nandc->props->supports_bam) { + nandc->reg_read_dma = + dma_map_single(nandc->dev, nandc->reg_read_buf, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { + dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); + return -EIO; + } + + nandc->tx_chan = dma_request_chan(nandc->dev, "tx"); + if (IS_ERR(nandc->tx_chan)) { + ret = PTR_ERR(nandc->tx_chan); + nandc->tx_chan = NULL; + dev_err_probe(nandc->dev, ret, + "tx DMA channel request failed\n"); + goto unalloc; + } + + nandc->rx_chan = dma_request_chan(nandc->dev, "rx"); + if (IS_ERR(nandc->rx_chan)) { + ret = PTR_ERR(nandc->rx_chan); + nandc->rx_chan = NULL; + dev_err_probe(nandc->dev, ret, + "rx DMA channel request failed\n"); + goto unalloc; + } + + nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd"); + if (IS_ERR(nandc->cmd_chan)) { + ret = PTR_ERR(nandc->cmd_chan); + nandc->cmd_chan = NULL; + dev_err_probe(nandc->dev, ret, + "cmd DMA channel request failed\n"); + goto unalloc; + } + + /* + * Initially allocate BAM transaction to read ONFI param page. + * After detecting all the devices, this BAM transaction will + * be freed and the next BAM transaction will be allocated with + * maximum codeword size + */ + nandc->max_cwperpage = 1; + nandc->bam_txn = qcom_alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + ret = -ENOMEM; + goto unalloc; + } + } else { + nandc->chan = dma_request_chan(nandc->dev, "rxtx"); + if (IS_ERR(nandc->chan)) { + ret = PTR_ERR(nandc->chan); + nandc->chan = NULL; + dev_err_probe(nandc->dev, ret, + "rxtx DMA channel request failed\n"); + return ret; + } + } + + INIT_LIST_HEAD(&nandc->desc_list); + INIT_LIST_HEAD(&nandc->host_list); + + return 0; +unalloc: + qcom_nandc_unalloc(nandc); + return ret; +} +EXPORT_SYMBOL(qcom_nandc_alloc); + +MODULE_DESCRIPTION("QPIC controller common api"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index ee73876f7244..f07871532ef0 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -15,417 +15,7 @@ #include #include #include - -/* NANDc reg offsets */ -#define NAND_FLASH_CMD 0x00 -#define NAND_ADDR0 0x04 -#define NAND_ADDR1 0x08 -#define NAND_FLASH_CHIP_SELECT 0x0c -#define NAND_EXEC_CMD 0x10 -#define NAND_FLASH_STATUS 0x14 -#define NAND_BUFFER_STATUS 0x18 -#define NAND_DEV0_CFG0 0x20 -#define NAND_DEV0_CFG1 0x24 -#define NAND_DEV0_ECC_CFG 0x28 -#define NAND_AUTO_STATUS_EN 0x2c -#define NAND_DEV1_CFG0 0x30 -#define NAND_DEV1_CFG1 0x34 -#define NAND_READ_ID 0x40 -#define NAND_READ_STATUS 0x44 -#define NAND_DEV_CMD0 0xa0 -#define NAND_DEV_CMD1 0xa4 -#define NAND_DEV_CMD2 0xa8 -#define NAND_DEV_CMD_VLD 0xac -#define SFLASHC_BURST_CFG 0xe0 -#define NAND_ERASED_CW_DETECT_CFG 0xe8 -#define NAND_ERASED_CW_DETECT_STATUS 0xec -#define NAND_EBI2_ECC_BUF_CFG 0xf0 -#define FLASH_BUF_ACC 0x100 - -#define NAND_CTRL 0xf00 -#define NAND_VERSION 0xf08 -#define NAND_READ_LOCATION_0 0xf20 -#define NAND_READ_LOCATION_1 0xf24 -#define NAND_READ_LOCATION_2 0xf28 -#define NAND_READ_LOCATION_3 0xf2c -#define NAND_READ_LOCATION_LAST_CW_0 0xf40 -#define NAND_READ_LOCATION_LAST_CW_1 0xf44 -#define NAND_READ_LOCATION_LAST_CW_2 0xf48 -#define NAND_READ_LOCATION_LAST_CW_3 0xf4c - -/* dummy register offsets, used by qcom_write_reg_dma */ -#define NAND_DEV_CMD1_RESTORE 0xdead -#define NAND_DEV_CMD_VLD_RESTORE 0xbeef - -/* NAND_FLASH_CMD bits */ -#define PAGE_ACC BIT(4) -#define LAST_PAGE BIT(5) - -/* NAND_FLASH_CHIP_SELECT bits */ -#define NAND_DEV_SEL 0 -#define DM_EN BIT(2) - -/* NAND_FLASH_STATUS bits */ -#define FS_OP_ERR BIT(4) -#define FS_READY_BSY_N BIT(5) -#define FS_MPU_ERR BIT(8) -#define FS_DEVICE_STS_ERR BIT(16) -#define FS_DEVICE_WP BIT(23) - -/* NAND_BUFFER_STATUS bits */ -#define BS_UNCORRECTABLE_BIT BIT(8) -#define BS_CORRECTABLE_ERR_MSK 0x1f - -/* NAND_DEVn_CFG0 bits */ -#define DISABLE_STATUS_AFTER_WRITE 4 -#define CW_PER_PAGE 6 -#define UD_SIZE_BYTES 9 -#define UD_SIZE_BYTES_MASK GENMASK(18, 9) -#define ECC_PARITY_SIZE_BYTES_RS 19 -#define SPARE_SIZE_BYTES 23 -#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) -#define NUM_ADDR_CYCLES 27 -#define STATUS_BFR_READ 30 -#define SET_RD_MODE_AFTER_STATUS 31 - -/* NAND_DEVn_CFG0 bits */ -#define DEV0_CFG1_ECC_DISABLE 0 -#define WIDE_FLASH 1 -#define NAND_RECOVERY_CYCLES 2 -#define CS_ACTIVE_BSY 5 -#define BAD_BLOCK_BYTE_NUM 6 -#define BAD_BLOCK_IN_SPARE_AREA 16 -#define WR_RD_BSY_GAP 17 -#define ENABLE_BCH_ECC 27 - -/* NAND_DEV0_ECC_CFG bits */ -#define ECC_CFG_ECC_DISABLE 0 -#define ECC_SW_RESET 1 -#define ECC_MODE 4 -#define ECC_PARITY_SIZE_BYTES_BCH 8 -#define ECC_NUM_DATA_BYTES 16 -#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) -#define ECC_FORCE_CLK_OPEN 30 - -/* NAND_DEV_CMD1 bits */ -#define READ_ADDR 0 - -/* NAND_DEV_CMD_VLD bits */ -#define READ_START_VLD BIT(0) -#define READ_STOP_VLD BIT(1) -#define WRITE_START_VLD BIT(2) -#define ERASE_START_VLD BIT(3) -#define SEQ_READ_START_VLD BIT(4) - -/* NAND_EBI2_ECC_BUF_CFG bits */ -#define NUM_STEPS 0 - -/* NAND_ERASED_CW_DETECT_CFG bits */ -#define ERASED_CW_ECC_MASK 1 -#define AUTO_DETECT_RES 0 -#define MASK_ECC BIT(ERASED_CW_ECC_MASK) -#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) -#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) -#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) -#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) - -/* NAND_ERASED_CW_DETECT_STATUS bits */ -#define PAGE_ALL_ERASED BIT(7) -#define CODEWORD_ALL_ERASED BIT(6) -#define PAGE_ERASED BIT(5) -#define CODEWORD_ERASED BIT(4) -#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) -#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) - -/* NAND_READ_LOCATION_n bits */ -#define READ_LOCATION_OFFSET 0 -#define READ_LOCATION_SIZE 16 -#define READ_LOCATION_LAST 31 - -/* Version Mask */ -#define NAND_VERSION_MAJOR_MASK 0xf0000000 -#define NAND_VERSION_MAJOR_SHIFT 28 -#define NAND_VERSION_MINOR_MASK 0x0fff0000 -#define NAND_VERSION_MINOR_SHIFT 16 - -/* NAND OP_CMDs */ -#define OP_PAGE_READ 0x2 -#define OP_PAGE_READ_WITH_ECC 0x3 -#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 -#define OP_PAGE_READ_ONFI_READ 0x5 -#define OP_PROGRAM_PAGE 0x6 -#define OP_PAGE_PROGRAM_WITH_ECC 0x7 -#define OP_PROGRAM_PAGE_SPARE 0x9 -#define OP_BLOCK_ERASE 0xa -#define OP_CHECK_STATUS 0xc -#define OP_FETCH_ID 0xb -#define OP_RESET_DEVICE 0xd - -/* Default Value for NAND_DEV_CMD_VLD */ -#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ - ERASE_START_VLD | SEQ_READ_START_VLD) - -/* NAND_CTRL bits */ -#define BAM_MODE_EN BIT(0) - -/* - * the NAND controller performs reads/writes with ECC in 516 byte chunks. - * the driver calls the chunks 'step' or 'codeword' interchangeably - */ -#define NANDC_STEP_SIZE 512 - -/* - * the largest page size we support is 8K, this will have 16 steps/codewords - * of 512 bytes each - */ -#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) - -/* we read at most 3 registers per codeword scan */ -#define MAX_REG_RD (3 * MAX_NUM_STEPS) - -/* ECC modes supported by the controller */ -#define ECC_NONE BIT(0) -#define ECC_RS_4BIT BIT(1) -#define ECC_BCH_4BIT BIT(2) -#define ECC_BCH_8BIT BIT(3) - -/* - * Returns the actual register address for all NAND_DEV_ registers - * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) - */ -#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) - -/* Returns the NAND register physical address */ -#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) - -/* Returns the dma address for reg read buffer */ -#define reg_buf_dma_addr(chip, vaddr) \ - ((chip)->reg_read_dma + \ - ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) - -#define QPIC_PER_CW_CMD_ELEMENTS 32 -#define QPIC_PER_CW_CMD_SGL 32 -#define QPIC_PER_CW_DATA_SGL 8 - -#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000) - -/* - * Flags used in DMA descriptor preparation helper functions - * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) - */ -/* Don't set the EOT in current tx BAM sgl */ -#define NAND_BAM_NO_EOT BIT(0) -/* Set the NWD flag in current BAM sgl */ -#define NAND_BAM_NWD BIT(1) -/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ -#define NAND_BAM_NEXT_SGL BIT(2) -/* - * Erased codeword status is being used two times in single transfer so this - * flag will determine the current value of erased codeword status register - */ -#define NAND_ERASED_CW_SET BIT(4) - -#define MAX_ADDRESS_CYCLE 5 - -/* - * This data type corresponds to the BAM transaction which will be used for all - * NAND transfers. - * @bam_ce - the array of BAM command elements - * @cmd_sgl - sgl for NAND BAM command pipe - * @data_sgl - sgl for NAND BAM consumer/producer pipe - * @last_data_desc - last DMA desc in data channel (tx/rx). - * @last_cmd_desc - last DMA desc in command channel. - * @txn_done - completion for NAND transfer. - * @bam_ce_pos - the index in bam_ce which is available for next sgl - * @bam_ce_start - the index in bam_ce which marks the start position ce - * for current sgl. It will be used for size calculation - * for current sgl - * @cmd_sgl_pos - current index in command sgl. - * @cmd_sgl_start - start index in command sgl. - * @tx_sgl_pos - current index in data sgl for tx. - * @tx_sgl_start - start index in data sgl for tx. - * @rx_sgl_pos - current index in data sgl for rx. - * @rx_sgl_start - start index in data sgl for rx. - */ -struct bam_transaction { - struct bam_cmd_element *bam_ce; - struct scatterlist *cmd_sgl; - struct scatterlist *data_sgl; - struct dma_async_tx_descriptor *last_data_desc; - struct dma_async_tx_descriptor *last_cmd_desc; - struct completion txn_done; - u32 bam_ce_pos; - u32 bam_ce_start; - u32 cmd_sgl_pos; - u32 cmd_sgl_start; - u32 tx_sgl_pos; - u32 tx_sgl_start; - u32 rx_sgl_pos; - u32 rx_sgl_start; -}; - -/* - * This data type corresponds to the nand dma descriptor - * @dma_desc - low level DMA engine descriptor - * @list - list for desc_info - * - * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by - * ADM - * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM - * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM - * @dir - DMA transfer direction - */ -struct desc_info { - struct dma_async_tx_descriptor *dma_desc; - struct list_head node; - - union { - struct scatterlist adm_sgl; - struct { - struct scatterlist *bam_sgl; - int sgl_cnt; - }; - }; - enum dma_data_direction dir; -}; - -/* - * holds the current register values that we want to write. acts as a contiguous - * chunk of memory which we use to write the controller registers through DMA. - */ -struct nandc_regs { - __le32 cmd; - __le32 addr0; - __le32 addr1; - __le32 chip_sel; - __le32 exec; - - __le32 cfg0; - __le32 cfg1; - __le32 ecc_bch_cfg; - - __le32 clrflashstatus; - __le32 clrreadstatus; - - __le32 cmd1; - __le32 vld; - - __le32 orig_cmd1; - __le32 orig_vld; - - __le32 ecc_buf_cfg; - __le32 read_location0; - __le32 read_location1; - __le32 read_location2; - __le32 read_location3; - __le32 read_location_last0; - __le32 read_location_last1; - __le32 read_location_last2; - __le32 read_location_last3; - - __le32 erased_cw_detect_cfg_clr; - __le32 erased_cw_detect_cfg_set; -}; - -/* - * NAND controller data struct - * - * @dev: parent device - * - * @base: MMIO base - * - * @core_clk: controller clock - * @aon_clk: another controller clock - * - * @regs: a contiguous chunk of memory for DMA register - * writes. contains the register values to be - * written to controller - * - * @props: properties of current NAND controller, - * initialized via DT match data - * - * @controller: base controller structure - * @host_list: list containing all the chips attached to the - * controller - * - * @chan: dma channel - * @cmd_crci: ADM DMA CRCI for command flow control - * @data_crci: ADM DMA CRCI for data flow control - * - * @desc_list: DMA descriptor list (list of desc_infos) - * - * @data_buffer: our local DMA buffer for page read/writes, - * used when we can't use the buffer provided - * by upper layers directly - * @reg_read_buf: local buffer for reading back registers via DMA - * - * @base_phys: physical base address of controller registers - * @base_dma: dma base address of controller registers - * @reg_read_dma: contains dma address for register read buffer - * - * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf - * functions - * @max_cwperpage: maximum QPIC codewords required. calculated - * from all connected NAND devices pagesize - * - * @reg_read_pos: marker for data read in reg_read_buf - * - * @cmd1/vld: some fixed controller register values - * - * @exec_opwrite: flag to select correct number of code word - * while reading status - */ -struct qcom_nand_controller { - struct device *dev; - - void __iomem *base; - - struct clk *core_clk; - struct clk *aon_clk; - - struct nandc_regs *regs; - struct bam_transaction *bam_txn; - - const struct qcom_nandc_props *props; - - struct nand_controller controller; - struct list_head host_list; - - union { - /* will be used only by QPIC for BAM DMA */ - struct { - struct dma_chan *tx_chan; - struct dma_chan *rx_chan; - struct dma_chan *cmd_chan; - }; - - /* will be used only by EBI2 for ADM DMA */ - struct { - struct dma_chan *chan; - unsigned int cmd_crci; - unsigned int data_crci; - }; - }; - - struct list_head desc_list; - - u8 *data_buffer; - __le32 *reg_read_buf; - - phys_addr_t base_phys; - dma_addr_t base_dma; - dma_addr_t reg_read_dma; - - int buf_size; - int buf_count; - int buf_start; - unsigned int max_cwperpage; - - int reg_read_pos; - - u32 cmd1, vld; - bool exec_opwrite; -}; +#include /* * NAND special boot partitions @@ -530,97 +120,6 @@ struct qcom_nand_host { bool bch_enabled; }; -/* - * This data type corresponds to the NAND controller properties which varies - * among different NAND controllers. - * @ecc_modes - ecc mode for NAND - * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset - * @supports_bam - whether NAND controller is using Bus Access Manager (BAM) - * @nandc_part_of_qpic - whether NAND controller is part of qpic IP - * @qpic_version2 - flag to indicate QPIC IP version 2 - * @use_codeword_fixup - whether NAND has different layout for boot partitions - */ -struct qcom_nandc_props { - u32 ecc_modes; - u32 dev_cmd_reg_start; - bool supports_bam; - bool nandc_part_of_qpic; - bool qpic_version2; - bool use_codeword_fixup; -}; - -/* Frees the BAM transaction memory */ -static void qcom_free_bam_transaction(struct qcom_nand_controller *nandc) -{ - struct bam_transaction *bam_txn = nandc->bam_txn; - - devm_kfree(nandc->dev, bam_txn); -} - -/* Allocates and Initializes the BAM transaction */ -static struct bam_transaction * -qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc) -{ - struct bam_transaction *bam_txn; - size_t bam_txn_size; - unsigned int num_cw = nandc->max_cwperpage; - void *bam_txn_buf; - - bam_txn_size = - sizeof(*bam_txn) + num_cw * - ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) + - (sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + - (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); - - bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL); - if (!bam_txn_buf) - return NULL; - - bam_txn = bam_txn_buf; - bam_txn_buf += sizeof(*bam_txn); - - bam_txn->bam_ce = bam_txn_buf; - bam_txn_buf += - sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw; - - bam_txn->cmd_sgl = bam_txn_buf; - bam_txn_buf += - sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; - - bam_txn->data_sgl = bam_txn_buf; - - init_completion(&bam_txn->txn_done); - - return bam_txn; -} - -/* Clears the BAM transaction indexes */ -static void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) -{ - struct bam_transaction *bam_txn = nandc->bam_txn; - - if (!nandc->props->supports_bam) - return; - - memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); - bam_txn->last_data_desc = NULL; - - sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * - QPIC_PER_CW_CMD_SGL); - sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * - QPIC_PER_CW_DATA_SGL); - - reinit_completion(&bam_txn->txn_done); -} - -/* Callback for DMA descriptor completion */ -static void qcom_qpic_bam_dma_done(void *data) -{ - struct bam_transaction *bam_txn = data; - - complete(&bam_txn->txn_done); -} - static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -629,8 +128,8 @@ static struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) static struct qcom_nand_controller * get_qcom_nand_controller(struct nand_chip *chip) { - return container_of(chip->controller, struct qcom_nand_controller, - controller); + return (struct qcom_nand_controller *) + ((u8 *)chip->controller - sizeof(struct qcom_nand_controller)); } static u32 nandc_read(struct qcom_nand_controller *nandc, int offset) @@ -644,23 +143,6 @@ static void nandc_write(struct qcom_nand_controller *nandc, int offset, iowrite32(val, nandc->base + offset); } -static void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu) -{ - if (!nandc->props->supports_bam) - return; - - if (is_cpu) - dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, - MAX_REG_RD * - sizeof(*nandc->reg_read_buf), - DMA_FROM_DEVICE); - else - dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, - MAX_REG_RD * - sizeof(*nandc->reg_read_buf), - DMA_FROM_DEVICE); -} - /* Helper to check whether this is the last CW or not */ static bool qcom_nandc_is_last_cw(struct nand_ecc_ctrl *ecc, int cw) { @@ -819,356 +301,6 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i host->cw_data : host->cw_size, 1); } -/* - * Maps the scatter gather list for DMA transfer and forms the DMA descriptor - * for BAM. This descriptor will be added in the NAND DMA descriptor queue - * which will be submitted to DMA engine. - */ -static int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, - struct dma_chan *chan, - unsigned long flags) -{ - struct desc_info *desc; - struct scatterlist *sgl; - unsigned int sgl_cnt; - int ret; - struct bam_transaction *bam_txn = nandc->bam_txn; - enum dma_transfer_direction dir_eng; - struct dma_async_tx_descriptor *dma_desc; - - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return -ENOMEM; - - if (chan == nandc->cmd_chan) { - sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; - sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; - bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; - dir_eng = DMA_MEM_TO_DEV; - desc->dir = DMA_TO_DEVICE; - } else if (chan == nandc->tx_chan) { - sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; - sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; - bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; - dir_eng = DMA_MEM_TO_DEV; - desc->dir = DMA_TO_DEVICE; - } else { - sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; - sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; - bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; - dir_eng = DMA_DEV_TO_MEM; - desc->dir = DMA_FROM_DEVICE; - } - - sg_mark_end(sgl + sgl_cnt - 1); - ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); - if (ret == 0) { - dev_err(nandc->dev, "failure in mapping desc\n"); - kfree(desc); - return -ENOMEM; - } - - desc->sgl_cnt = sgl_cnt; - desc->bam_sgl = sgl; - - dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, - flags); - - if (!dma_desc) { - dev_err(nandc->dev, "failure in prep desc\n"); - dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); - kfree(desc); - return -EINVAL; - } - - desc->dma_desc = dma_desc; - - /* update last data/command descriptor */ - if (chan == nandc->cmd_chan) - bam_txn->last_cmd_desc = dma_desc; - else - bam_txn->last_data_desc = dma_desc; - - list_add_tail(&desc->node, &nandc->desc_list); - - return 0; -} - -/* - * Prepares the command descriptor for BAM DMA which will be used for NAND - * register reads and writes. The command descriptor requires the command - * to be formed in command element type so this function uses the command - * element from bam transaction ce array and fills the same with required - * data. A single SGL can contain multiple command elements so - * NAND_BAM_NEXT_SGL will be used for starting the separate SGL - * after the current command element. - */ -static int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, - int size, unsigned int flags) -{ - int bam_ce_size; - int i, ret; - struct bam_cmd_element *bam_ce_buffer; - struct bam_transaction *bam_txn = nandc->bam_txn; - - bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos]; - - /* fill the command desc */ - for (i = 0; i < size; i++) { - if (read) - bam_prep_ce(&bam_ce_buffer[i], - nandc_reg_phys(nandc, reg_off + 4 * i), - BAM_READ_COMMAND, - reg_buf_dma_addr(nandc, - (__le32 *)vaddr + i)); - else - bam_prep_ce_le32(&bam_ce_buffer[i], - nandc_reg_phys(nandc, reg_off + 4 * i), - BAM_WRITE_COMMAND, - *((__le32 *)vaddr + i)); - } - - bam_txn->bam_ce_pos += size; - - /* use the separate sgl after this command */ - if (flags & NAND_BAM_NEXT_SGL) { - bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start]; - bam_ce_size = (bam_txn->bam_ce_pos - - bam_txn->bam_ce_start) * - sizeof(struct bam_cmd_element); - sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos], - bam_ce_buffer, bam_ce_size); - bam_txn->cmd_sgl_pos++; - bam_txn->bam_ce_start = bam_txn->bam_ce_pos; - - if (flags & NAND_BAM_NWD) { - ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, - DMA_PREP_FENCE | - DMA_PREP_CMD); - if (ret) - return ret; - } - } - - return 0; -} - -/* - * Prepares the data descriptor for BAM DMA which will be used for NAND - * data reads and writes. - */ -static int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, - const void *vaddr, int size, unsigned int flags) -{ - int ret; - struct bam_transaction *bam_txn = nandc->bam_txn; - - if (read) { - sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], - vaddr, size); - bam_txn->rx_sgl_pos++; - } else { - sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], - vaddr, size); - bam_txn->tx_sgl_pos++; - - /* - * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag - * is not set, form the DMA descriptor - */ - if (!(flags & NAND_BAM_NO_EOT)) { - ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, - DMA_PREP_INTERRUPT); - if (ret) - return ret; - } - } - - return 0; -} - -static int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, int size, - bool flow_control) -{ - struct desc_info *desc; - struct dma_async_tx_descriptor *dma_desc; - struct scatterlist *sgl; - struct dma_slave_config slave_conf; - struct qcom_adm_peripheral_config periph_conf = {}; - enum dma_transfer_direction dir_eng; - int ret; - - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return -ENOMEM; - - sgl = &desc->adm_sgl; - - sg_init_one(sgl, vaddr, size); - - if (read) { - dir_eng = DMA_DEV_TO_MEM; - desc->dir = DMA_FROM_DEVICE; - } else { - dir_eng = DMA_MEM_TO_DEV; - desc->dir = DMA_TO_DEVICE; - } - - ret = dma_map_sg(nandc->dev, sgl, 1, desc->dir); - if (ret == 0) { - ret = -ENOMEM; - goto err; - } - - memset(&slave_conf, 0x00, sizeof(slave_conf)); - - slave_conf.device_fc = flow_control; - if (read) { - slave_conf.src_maxburst = 16; - slave_conf.src_addr = nandc->base_dma + reg_off; - if (nandc->data_crci) { - periph_conf.crci = nandc->data_crci; - slave_conf.peripheral_config = &periph_conf; - slave_conf.peripheral_size = sizeof(periph_conf); - } - } else { - slave_conf.dst_maxburst = 16; - slave_conf.dst_addr = nandc->base_dma + reg_off; - if (nandc->cmd_crci) { - periph_conf.crci = nandc->cmd_crci; - slave_conf.peripheral_config = &periph_conf; - slave_conf.peripheral_size = sizeof(periph_conf); - } - } - - ret = dmaengine_slave_config(nandc->chan, &slave_conf); - if (ret) { - dev_err(nandc->dev, "failed to configure dma channel\n"); - goto err; - } - - dma_desc = dmaengine_prep_slave_sg(nandc->chan, sgl, 1, dir_eng, 0); - if (!dma_desc) { - dev_err(nandc->dev, "failed to prepare desc\n"); - ret = -EINVAL; - goto err; - } - - desc->dma_desc = dma_desc; - - list_add_tail(&desc->node, &nandc->desc_list); - - return 0; -err: - kfree(desc); - - return ret; -} - -/* - * qcom_read_reg_dma: prepares a descriptor to read a given number of - * contiguous registers to the reg_read_buf pointer - * - * @first: offset of the first register in the contiguous block - * @num_regs: number of registers to read - * @flags: flags to control DMA descriptor preparation - */ -static int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs, unsigned int flags) -{ - bool flow_control = false; - void *vaddr; - - vaddr = nandc->reg_read_buf + nandc->reg_read_pos; - nandc->reg_read_pos += num_regs; - - if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) - first = dev_cmd_reg_addr(nandc, first); - - if (nandc->props->supports_bam) - return qcom_prep_bam_dma_desc_cmd(nandc, true, first, vaddr, - num_regs, flags); - - if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) - flow_control = true; - - return qcom_prep_adm_dma_desc(nandc, true, first, vaddr, - num_regs * sizeof(u32), flow_control); -} - -/* - * qcom_write_reg_dma: prepares a descriptor to write a given number of - * contiguous registers - * - * @vaddr: contiguous memory from where register value will - * be written - * @first: offset of the first register in the contiguous block - * @num_regs: number of registers to write - * @flags: flags to control DMA descriptor preparation - */ -static int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, - int first, int num_regs, unsigned int flags) -{ - bool flow_control = false; - - if (first == NAND_EXEC_CMD) - flags |= NAND_BAM_NWD; - - if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) - first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); - - if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) - first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); - - if (nandc->props->supports_bam) - return qcom_prep_bam_dma_desc_cmd(nandc, false, first, vaddr, - num_regs, flags); - - if (first == NAND_FLASH_CMD) - flow_control = true; - - return qcom_prep_adm_dma_desc(nandc, false, first, vaddr, - num_regs * sizeof(u32), flow_control); -} - -/* - * qcom_read_data_dma: prepares a DMA descriptor to transfer data from the - * controller's internal buffer to the buffer 'vaddr' - * - * @reg_off: offset within the controller's data buffer - * @vaddr: virtual address of the buffer we want to write to - * @size: DMA transaction size in bytes - * @flags: flags to control DMA descriptor preparation - */ -static int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size, unsigned int flags) -{ - if (nandc->props->supports_bam) - return qcom_prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); - - return qcom_prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); -} - -/* - * qcom_write_data_dma: prepares a DMA descriptor to transfer data from - * 'vaddr' to the controller's internal buffer - * - * @reg_off: offset within the controller's data buffer - * @vaddr: virtual address of the buffer we want to read from - * @size: DMA transaction size in bytes - * @flags: flags to control DMA descriptor preparation - */ -static int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size, unsigned int flags) -{ - if (nandc->props->supports_bam) - return qcom_prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); - - return qcom_prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); -} - /* * Helper to prepare DMA descriptors for configuring registers * before reading a NAND page. @@ -1262,83 +394,6 @@ static void config_nand_cw_write(struct nand_chip *chip) NAND_BAM_NEXT_SGL); } -/* helpers to submit/free our list of dma descriptors */ -static int qcom_submit_descs(struct qcom_nand_controller *nandc) -{ - struct desc_info *desc, *n; - dma_cookie_t cookie = 0; - struct bam_transaction *bam_txn = nandc->bam_txn; - int ret = 0; - - if (nandc->props->supports_bam) { - if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { - ret = qcom_prepare_bam_async_desc(nandc, nandc->rx_chan, 0); - if (ret) - goto err_unmap_free_desc; - } - - if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { - ret = qcom_prepare_bam_async_desc(nandc, nandc->tx_chan, - DMA_PREP_INTERRUPT); - if (ret) - goto err_unmap_free_desc; - } - - if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { - ret = qcom_prepare_bam_async_desc(nandc, nandc->cmd_chan, - DMA_PREP_CMD); - if (ret) - goto err_unmap_free_desc; - } - } - - list_for_each_entry(desc, &nandc->desc_list, node) - cookie = dmaengine_submit(desc->dma_desc); - - if (nandc->props->supports_bam) { - bam_txn->last_cmd_desc->callback = qcom_qpic_bam_dma_done; - bam_txn->last_cmd_desc->callback_param = bam_txn; - - dma_async_issue_pending(nandc->tx_chan); - dma_async_issue_pending(nandc->rx_chan); - dma_async_issue_pending(nandc->cmd_chan); - - if (!wait_for_completion_timeout(&bam_txn->txn_done, - QPIC_NAND_COMPLETION_TIMEOUT)) - ret = -ETIMEDOUT; - } else { - if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) - ret = -ETIMEDOUT; - } - -err_unmap_free_desc: - /* - * Unmap the dma sg_list and free the desc allocated by both - * qcom_prepare_bam_async_desc() and qcom_prep_adm_dma_desc() functions. - */ - list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { - list_del(&desc->node); - - if (nandc->props->supports_bam) - dma_unmap_sg(nandc->dev, desc->bam_sgl, - desc->sgl_cnt, desc->dir); - else - dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, - desc->dir); - - kfree(desc); - } - - return ret; -} - -/* reset the register read buffer for next NAND operation */ -static void qcom_clear_read_regs(struct qcom_nand_controller *nandc) -{ - nandc->reg_read_pos = 0; - qcom_nandc_dev_to_mem(nandc, false); -} - /* * when using BCH ECC, the HW flags an error in NAND_FLASH_STATUS if it read * an erased CW, and reports an erased CW in NAND_ERASED_CW_DETECT_STATUS. @@ -2975,141 +2030,14 @@ static const struct nand_controller_ops qcom_nandc_ops = { .exec_op = qcom_nand_exec_op, }; -static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) -{ - if (nandc->props->supports_bam) { - if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) - dma_unmap_single(nandc->dev, nandc->reg_read_dma, - MAX_REG_RD * - sizeof(*nandc->reg_read_buf), - DMA_FROM_DEVICE); - - if (nandc->tx_chan) - dma_release_channel(nandc->tx_chan); - - if (nandc->rx_chan) - dma_release_channel(nandc->rx_chan); - - if (nandc->cmd_chan) - dma_release_channel(nandc->cmd_chan); - } else { - if (nandc->chan) - dma_release_channel(nandc->chan); - } -} - -static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) -{ - int ret; - - ret = dma_set_coherent_mask(nandc->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(nandc->dev, "failed to set DMA mask\n"); - return ret; - } - - /* - * we use the internal buffer for reading ONFI params, reading small - * data like ID and status, and preforming read-copy-write operations - * when writing to a codeword partially. 532 is the maximum possible - * size of a codeword for our nand controller - */ - nandc->buf_size = 532; - - nandc->data_buffer = devm_kzalloc(nandc->dev, nandc->buf_size, GFP_KERNEL); - if (!nandc->data_buffer) - return -ENOMEM; - - nandc->regs = devm_kzalloc(nandc->dev, sizeof(*nandc->regs), GFP_KERNEL); - if (!nandc->regs) - return -ENOMEM; - - nandc->reg_read_buf = devm_kcalloc(nandc->dev, MAX_REG_RD, - sizeof(*nandc->reg_read_buf), - GFP_KERNEL); - if (!nandc->reg_read_buf) - return -ENOMEM; - - if (nandc->props->supports_bam) { - nandc->reg_read_dma = - dma_map_single(nandc->dev, nandc->reg_read_buf, - MAX_REG_RD * - sizeof(*nandc->reg_read_buf), - DMA_FROM_DEVICE); - if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { - dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); - return -EIO; - } - - nandc->tx_chan = dma_request_chan(nandc->dev, "tx"); - if (IS_ERR(nandc->tx_chan)) { - ret = PTR_ERR(nandc->tx_chan); - nandc->tx_chan = NULL; - dev_err_probe(nandc->dev, ret, - "tx DMA channel request failed\n"); - goto unalloc; - } - - nandc->rx_chan = dma_request_chan(nandc->dev, "rx"); - if (IS_ERR(nandc->rx_chan)) { - ret = PTR_ERR(nandc->rx_chan); - nandc->rx_chan = NULL; - dev_err_probe(nandc->dev, ret, - "rx DMA channel request failed\n"); - goto unalloc; - } - - nandc->cmd_chan = dma_request_chan(nandc->dev, "cmd"); - if (IS_ERR(nandc->cmd_chan)) { - ret = PTR_ERR(nandc->cmd_chan); - nandc->cmd_chan = NULL; - dev_err_probe(nandc->dev, ret, - "cmd DMA channel request failed\n"); - goto unalloc; - } - - /* - * Initially allocate BAM transaction to read ONFI param page. - * After detecting all the devices, this BAM transaction will - * be freed and the next BAM transaction will be allocated with - * maximum codeword size - */ - nandc->max_cwperpage = 1; - nandc->bam_txn = qcom_alloc_bam_transaction(nandc); - if (!nandc->bam_txn) { - dev_err(nandc->dev, - "failed to allocate bam transaction\n"); - ret = -ENOMEM; - goto unalloc; - } - } else { - nandc->chan = dma_request_chan(nandc->dev, "rxtx"); - if (IS_ERR(nandc->chan)) { - ret = PTR_ERR(nandc->chan); - nandc->chan = NULL; - dev_err_probe(nandc->dev, ret, - "rxtx DMA channel request failed\n"); - return ret; - } - } - - INIT_LIST_HEAD(&nandc->desc_list); - INIT_LIST_HEAD(&nandc->host_list); - - nand_controller_init(&nandc->controller); - nandc->controller.ops = &qcom_nandc_ops; - - return 0; -unalloc: - qcom_nandc_unalloc(nandc); - return ret; -} - /* one time setup of a few nand controller registers */ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) { u32 nand_ctrl; + nand_controller_init(nandc->controller); + nandc->controller->ops = &qcom_nandc_ops; + /* kill onenand */ if (!nandc->props->nandc_part_of_qpic) nandc_write(nandc, SFLASHC_BURST_CFG, 0); @@ -3248,7 +2176,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, chip->legacy.block_bad = qcom_nandc_block_bad; chip->legacy.block_markbad = qcom_nandc_block_markbad; - chip->controller = &nandc->controller; + chip->controller = nandc->controller; chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA | NAND_SKIP_BBTSCAN; @@ -3331,17 +2259,21 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) static int qcom_nandc_probe(struct platform_device *pdev) { struct qcom_nand_controller *nandc; + struct nand_controller *controller; const void *dev_data; struct device *dev = &pdev->dev; struct resource *res; int ret; - nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL); + nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc) + sizeof(*controller), + GFP_KERNEL); if (!nandc) return -ENOMEM; + controller = (struct nand_controller *)&nandc[1]; platform_set_drvdata(pdev, nandc); nandc->dev = dev; + nandc->controller = controller; dev_data = of_device_get_match_data(dev); if (!dev_data) { diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h new file mode 100644 index 000000000000..425994429387 --- /dev/null +++ b/include/linux/mtd/nand-qpic-common.h @@ -0,0 +1,468 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * QCOM QPIC common APIs header file + * + * Copyright (c) 2023 Qualcomm Inc. + * Authors: Md sadre Alam + * + */ +#ifndef __MTD_NAND_QPIC_COMMON_H__ +#define __MTD_NAND_QPIC_COMMON_H__ + +/* NANDc reg offsets */ +#define NAND_FLASH_CMD 0x00 +#define NAND_ADDR0 0x04 +#define NAND_ADDR1 0x08 +#define NAND_FLASH_CHIP_SELECT 0x0c +#define NAND_EXEC_CMD 0x10 +#define NAND_FLASH_STATUS 0x14 +#define NAND_BUFFER_STATUS 0x18 +#define NAND_DEV0_CFG0 0x20 +#define NAND_DEV0_CFG1 0x24 +#define NAND_DEV0_ECC_CFG 0x28 +#define NAND_AUTO_STATUS_EN 0x2c +#define NAND_DEV1_CFG0 0x30 +#define NAND_DEV1_CFG1 0x34 +#define NAND_READ_ID 0x40 +#define NAND_READ_STATUS 0x44 +#define NAND_DEV_CMD0 0xa0 +#define NAND_DEV_CMD1 0xa4 +#define NAND_DEV_CMD2 0xa8 +#define NAND_DEV_CMD_VLD 0xac +#define SFLASHC_BURST_CFG 0xe0 +#define NAND_ERASED_CW_DETECT_CFG 0xe8 +#define NAND_ERASED_CW_DETECT_STATUS 0xec +#define NAND_EBI2_ECC_BUF_CFG 0xf0 +#define FLASH_BUF_ACC 0x100 + +#define NAND_CTRL 0xf00 +#define NAND_VERSION 0xf08 +#define NAND_READ_LOCATION_0 0xf20 +#define NAND_READ_LOCATION_1 0xf24 +#define NAND_READ_LOCATION_2 0xf28 +#define NAND_READ_LOCATION_3 0xf2c +#define NAND_READ_LOCATION_LAST_CW_0 0xf40 +#define NAND_READ_LOCATION_LAST_CW_1 0xf44 +#define NAND_READ_LOCATION_LAST_CW_2 0xf48 +#define NAND_READ_LOCATION_LAST_CW_3 0xf4c + +/* dummy register offsets, used by qcom_write_reg_dma */ +#define NAND_DEV_CMD1_RESTORE 0xdead +#define NAND_DEV_CMD_VLD_RESTORE 0xbeef + +/* NAND_FLASH_CMD bits */ +#define PAGE_ACC BIT(4) +#define LAST_PAGE BIT(5) + +/* NAND_FLASH_CHIP_SELECT bits */ +#define NAND_DEV_SEL 0 +#define DM_EN BIT(2) + +/* NAND_FLASH_STATUS bits */ +#define FS_OP_ERR BIT(4) +#define FS_READY_BSY_N BIT(5) +#define FS_MPU_ERR BIT(8) +#define FS_DEVICE_STS_ERR BIT(16) +#define FS_DEVICE_WP BIT(23) + +/* NAND_BUFFER_STATUS bits */ +#define BS_UNCORRECTABLE_BIT BIT(8) +#define BS_CORRECTABLE_ERR_MSK 0x1f + +/* NAND_DEVn_CFG0 bits */ +#define DISABLE_STATUS_AFTER_WRITE 4 +#define CW_PER_PAGE 6 +#define UD_SIZE_BYTES 9 +#define UD_SIZE_BYTES_MASK GENMASK(18, 9) +#define ECC_PARITY_SIZE_BYTES_RS 19 +#define SPARE_SIZE_BYTES 23 +#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) +#define NUM_ADDR_CYCLES 27 +#define STATUS_BFR_READ 30 +#define SET_RD_MODE_AFTER_STATUS 31 + +/* NAND_DEVn_CFG0 bits */ +#define DEV0_CFG1_ECC_DISABLE 0 +#define WIDE_FLASH 1 +#define NAND_RECOVERY_CYCLES 2 +#define CS_ACTIVE_BSY 5 +#define BAD_BLOCK_BYTE_NUM 6 +#define BAD_BLOCK_IN_SPARE_AREA 16 +#define WR_RD_BSY_GAP 17 +#define ENABLE_BCH_ECC 27 + +/* NAND_DEV0_ECC_CFG bits */ +#define ECC_CFG_ECC_DISABLE 0 +#define ECC_SW_RESET 1 +#define ECC_MODE 4 +#define ECC_PARITY_SIZE_BYTES_BCH 8 +#define ECC_NUM_DATA_BYTES 16 +#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) +#define ECC_FORCE_CLK_OPEN 30 + +/* NAND_DEV_CMD1 bits */ +#define READ_ADDR 0 + +/* NAND_DEV_CMD_VLD bits */ +#define READ_START_VLD BIT(0) +#define READ_STOP_VLD BIT(1) +#define WRITE_START_VLD BIT(2) +#define ERASE_START_VLD BIT(3) +#define SEQ_READ_START_VLD BIT(4) + +/* NAND_EBI2_ECC_BUF_CFG bits */ +#define NUM_STEPS 0 + +/* NAND_ERASED_CW_DETECT_CFG bits */ +#define ERASED_CW_ECC_MASK 1 +#define AUTO_DETECT_RES 0 +#define MASK_ECC BIT(ERASED_CW_ECC_MASK) +#define RESET_ERASED_DET BIT(AUTO_DETECT_RES) +#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) +#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) +#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) + +/* NAND_ERASED_CW_DETECT_STATUS bits */ +#define PAGE_ALL_ERASED BIT(7) +#define CODEWORD_ALL_ERASED BIT(6) +#define PAGE_ERASED BIT(5) +#define CODEWORD_ERASED BIT(4) +#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) +#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) + +/* NAND_READ_LOCATION_n bits */ +#define READ_LOCATION_OFFSET 0 +#define READ_LOCATION_SIZE 16 +#define READ_LOCATION_LAST 31 + +/* Version Mask */ +#define NAND_VERSION_MAJOR_MASK 0xf0000000 +#define NAND_VERSION_MAJOR_SHIFT 28 +#define NAND_VERSION_MINOR_MASK 0x0fff0000 +#define NAND_VERSION_MINOR_SHIFT 16 + +/* NAND OP_CMDs */ +#define OP_PAGE_READ 0x2 +#define OP_PAGE_READ_WITH_ECC 0x3 +#define OP_PAGE_READ_WITH_ECC_SPARE 0x4 +#define OP_PAGE_READ_ONFI_READ 0x5 +#define OP_PROGRAM_PAGE 0x6 +#define OP_PAGE_PROGRAM_WITH_ECC 0x7 +#define OP_PROGRAM_PAGE_SPARE 0x9 +#define OP_BLOCK_ERASE 0xa +#define OP_CHECK_STATUS 0xc +#define OP_FETCH_ID 0xb +#define OP_RESET_DEVICE 0xd + +/* Default Value for NAND_DEV_CMD_VLD */ +#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ + ERASE_START_VLD | SEQ_READ_START_VLD) + +/* NAND_CTRL bits */ +#define BAM_MODE_EN BIT(0) + +/* + * the NAND controller performs reads/writes with ECC in 516 byte chunks. + * the driver calls the chunks 'step' or 'codeword' interchangeably + */ +#define NANDC_STEP_SIZE 512 + +/* + * the largest page size we support is 8K, this will have 16 steps/codewords + * of 512 bytes each + */ +#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE) + +/* we read at most 3 registers per codeword scan */ +#define MAX_REG_RD (3 * MAX_NUM_STEPS) + +/* ECC modes supported by the controller */ +#define ECC_NONE BIT(0) +#define ECC_RS_4BIT BIT(1) +#define ECC_BCH_4BIT BIT(2) +#define ECC_BCH_8BIT BIT(3) + +/* + * Returns the actual register address for all NAND_DEV_ registers + * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) + */ +#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) + +/* Returns the NAND register physical address */ +#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset)) + +/* Returns the dma address for reg read buffer */ +#define reg_buf_dma_addr(chip, vaddr) \ + ((chip)->reg_read_dma + \ + ((u8 *)(vaddr) - (u8 *)(chip)->reg_read_buf)) + +#define QPIC_PER_CW_CMD_ELEMENTS 32 +#define QPIC_PER_CW_CMD_SGL 32 +#define QPIC_PER_CW_DATA_SGL 8 + +#define QPIC_NAND_COMPLETION_TIMEOUT msecs_to_jiffies(2000) + +/* + * Flags used in DMA descriptor preparation helper functions + * (i.e. qcom_read_reg_dma/qcom_write_reg_dma/qcom_read_data_dma/qcom_write_data_dma) + */ +/* Don't set the EOT in current tx BAM sgl */ +#define NAND_BAM_NO_EOT BIT(0) +/* Set the NWD flag in current BAM sgl */ +#define NAND_BAM_NWD BIT(1) +/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ +#define NAND_BAM_NEXT_SGL BIT(2) +/* + * Erased codeword status is being used two times in single transfer so this + * flag will determine the current value of erased codeword status register + */ +#define NAND_ERASED_CW_SET BIT(4) + +#define MAX_ADDRESS_CYCLE 5 + +/* + * This data type corresponds to the BAM transaction which will be used for all + * NAND transfers. + * @bam_ce - the array of BAM command elements + * @cmd_sgl - sgl for NAND BAM command pipe + * @data_sgl - sgl for NAND BAM consumer/producer pipe + * @last_data_desc - last DMA desc in data channel (tx/rx). + * @last_cmd_desc - last DMA desc in command channel. + * @txn_done - completion for NAND transfer. + * @bam_ce_pos - the index in bam_ce which is available for next sgl + * @bam_ce_start - the index in bam_ce which marks the start position ce + * for current sgl. It will be used for size calculation + * for current sgl + * @cmd_sgl_pos - current index in command sgl. + * @cmd_sgl_start - start index in command sgl. + * @tx_sgl_pos - current index in data sgl for tx. + * @tx_sgl_start - start index in data sgl for tx. + * @rx_sgl_pos - current index in data sgl for rx. + * @rx_sgl_start - start index in data sgl for rx. + */ +struct bam_transaction { + struct bam_cmd_element *bam_ce; + struct scatterlist *cmd_sgl; + struct scatterlist *data_sgl; + struct dma_async_tx_descriptor *last_data_desc; + struct dma_async_tx_descriptor *last_cmd_desc; + struct completion txn_done; + u32 bam_ce_pos; + u32 bam_ce_start; + u32 cmd_sgl_pos; + u32 cmd_sgl_start; + u32 tx_sgl_pos; + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; +}; + +/* + * This data type corresponds to the nand dma descriptor + * @dma_desc - low level DMA engine descriptor + * @list - list for desc_info + * + * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by + * ADM + * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM + * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM + * @dir - DMA transfer direction + */ +struct desc_info { + struct dma_async_tx_descriptor *dma_desc; + struct list_head node; + + union { + struct scatterlist adm_sgl; + struct { + struct scatterlist *bam_sgl; + int sgl_cnt; + }; + }; + enum dma_data_direction dir; +}; + +/* + * holds the current register values that we want to write. acts as a contiguous + * chunk of memory which we use to write the controller registers through DMA. + */ +struct nandc_regs { + __le32 cmd; + __le32 addr0; + __le32 addr1; + __le32 chip_sel; + __le32 exec; + + __le32 cfg0; + __le32 cfg1; + __le32 ecc_bch_cfg; + + __le32 clrflashstatus; + __le32 clrreadstatus; + + __le32 cmd1; + __le32 vld; + + __le32 orig_cmd1; + __le32 orig_vld; + + __le32 ecc_buf_cfg; + __le32 read_location0; + __le32 read_location1; + __le32 read_location2; + __le32 read_location3; + __le32 read_location_last0; + __le32 read_location_last1; + __le32 read_location_last2; + __le32 read_location_last3; + + __le32 erased_cw_detect_cfg_clr; + __le32 erased_cw_detect_cfg_set; +}; + +/* + * NAND controller data struct + * + * @dev: parent device + * + * @base: MMIO base + * + * @core_clk: controller clock + * @aon_clk: another controller clock + * + * @regs: a contiguous chunk of memory for DMA register + * writes. contains the register values to be + * written to controller + * + * @props: properties of current NAND controller, + * initialized via DT match data + * + * @controller: base controller structure + * @host_list: list containing all the chips attached to the + * controller + * + * @chan: dma channel + * @cmd_crci: ADM DMA CRCI for command flow control + * @data_crci: ADM DMA CRCI for data flow control + * + * @desc_list: DMA descriptor list (list of desc_infos) + * + * @data_buffer: our local DMA buffer for page read/writes, + * used when we can't use the buffer provided + * by upper layers directly + * @reg_read_buf: local buffer for reading back registers via DMA + * + * @base_phys: physical base address of controller registers + * @base_dma: dma base address of controller registers + * @reg_read_dma: contains dma address for register read buffer + * + * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf + * functions + * @max_cwperpage: maximum QPIC codewords required. calculated + * from all connected NAND devices pagesize + * + * @reg_read_pos: marker for data read in reg_read_buf + * + * @cmd1/vld: some fixed controller register values + * + * @exec_opwrite: flag to select correct number of code word + * while reading status + */ +struct qcom_nand_controller { + struct device *dev; + + void __iomem *base; + + struct clk *core_clk; + struct clk *aon_clk; + + struct nandc_regs *regs; + struct bam_transaction *bam_txn; + + const struct qcom_nandc_props *props; + + struct nand_controller *controller; + struct list_head host_list; + + union { + /* will be used only by QPIC for BAM DMA */ + struct { + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + struct dma_chan *cmd_chan; + }; + + /* will be used only by EBI2 for ADM DMA */ + struct { + struct dma_chan *chan; + unsigned int cmd_crci; + unsigned int data_crci; + }; + }; + + struct list_head desc_list; + + u8 *data_buffer; + __le32 *reg_read_buf; + + phys_addr_t base_phys; + dma_addr_t base_dma; + dma_addr_t reg_read_dma; + + int buf_size; + int buf_count; + int buf_start; + unsigned int max_cwperpage; + + int reg_read_pos; + + u32 cmd1, vld; + bool exec_opwrite; +}; + +/* + * This data type corresponds to the NAND controller properties which varies + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + * @supports_bam - whether NAND controller is using BAM + * @nandc_part_of_qpic - whether NAND controller is part of qpic IP + * @qpic_version2 - flag to indicate QPIC IP version 2 + * @use_codeword_fixup - whether NAND has different layout for boot partitions + */ +struct qcom_nandc_props { + u32 ecc_modes; + u32 dev_cmd_reg_start; + bool supports_bam; + bool nandc_part_of_qpic; + bool qpic_version2; + bool use_codeword_fixup; +}; + +void qcom_free_bam_transaction(struct qcom_nand_controller *nandc); +struct bam_transaction *qcom_alloc_bam_transaction(struct qcom_nand_controller *nandc); +void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc); +void qcom_qpic_bam_dma_done(void *data); +void qcom_nandc_dev_to_mem(struct qcom_nand_controller *nandc, bool is_cpu); +int qcom_prepare_bam_async_desc(struct qcom_nand_controller *nandc, + struct dma_chan *chan, unsigned long flags); +int qcom_prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, int size, unsigned int flags); +int qcom_prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + const void *vaddr, int size, unsigned int flags); +int qcom_prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off, + const void *vaddr, int size, bool flow_control); +int qcom_read_reg_dma(struct qcom_nand_controller *nandc, int first, int num_regs, + unsigned int flags); +int qcom_write_reg_dma(struct qcom_nand_controller *nandc, __le32 *vaddr, int first, + int num_regs, unsigned int flags); +int qcom_read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, + int size, unsigned int flags); +int qcom_write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, + int size, unsigned int flags); +int qcom_submit_descs(struct qcom_nand_controller *nandc); +void qcom_clear_read_regs(struct qcom_nand_controller *nandc); +void qcom_nandc_unalloc(struct qcom_nand_controller *nandc); +int qcom_nandc_alloc(struct qcom_nand_controller *nandc); +#endif + -- 2.51.0 From 70800832162a019d19111fdac370e50ae4afad08 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 20 Nov 2024 14:45:03 +0530 Subject: [PATCH 013/517] mtd: rawnand: qcom: use FIELD_PREP and GENMASK Use the bitfield macro FIELD_PREP, and GENMASK to do the shift and mask in one go. This makes the code more readable. Reviewed-by: Konrad Dybcio Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/qcom_nandc.c | 97 ++++++++++++++-------------- include/linux/mtd/nand-qpic-common.h | 31 +++++---- 2 files changed, 67 insertions(+), 61 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index f07871532ef0..086cb139adf1 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -281,7 +281,7 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read, i (num_cw - 1) << CW_PER_PAGE); cfg1 = cpu_to_le32(host->cfg1_raw); - ecc_bch_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); + ecc_bch_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); } nandc->regs->cmd = cmd; @@ -1494,42 +1494,41 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) host->cw_size = host->cw_data + ecc->bytes; bad_block_byte = mtd->writesize - host->cw_size * (cwperpage - 1) + 1; - host->cfg0 = (cwperpage - 1) << CW_PER_PAGE - | host->cw_data << UD_SIZE_BYTES - | 0 << DISABLE_STATUS_AFTER_WRITE - | 5 << NUM_ADDR_CYCLES - | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_RS - | 0 << STATUS_BFR_READ - | 1 << SET_RD_MODE_AFTER_STATUS - | host->spare_bytes << SPARE_SIZE_BYTES; - - host->cfg1 = 7 << NAND_RECOVERY_CYCLES - | 0 << CS_ACTIVE_BSY - | bad_block_byte << BAD_BLOCK_BYTE_NUM - | 0 << BAD_BLOCK_IN_SPARE_AREA - | 2 << WR_RD_BSY_GAP - | wide_bus << WIDE_FLASH - | host->bch_enabled << ENABLE_BCH_ECC; - - host->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE - | host->cw_size << UD_SIZE_BYTES - | 5 << NUM_ADDR_CYCLES - | 0 << SPARE_SIZE_BYTES; - - host->cfg1_raw = 7 << NAND_RECOVERY_CYCLES - | 0 << CS_ACTIVE_BSY - | 17 << BAD_BLOCK_BYTE_NUM - | 1 << BAD_BLOCK_IN_SPARE_AREA - | 2 << WR_RD_BSY_GAP - | wide_bus << WIDE_FLASH - | 1 << DEV0_CFG1_ECC_DISABLE; - - host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE - | 0 << ECC_SW_RESET - | host->cw_data << ECC_NUM_DATA_BYTES - | 1 << ECC_FORCE_CLK_OPEN - | ecc_mode << ECC_MODE - | host->ecc_bytes_hw << ECC_PARITY_SIZE_BYTES_BCH; + host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | + FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_data) | + FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 0) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, host->ecc_bytes_hw) | + FIELD_PREP(STATUS_BFR_READ, 0) | + FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, host->spare_bytes); + + host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | + FIELD_PREP(WIDE_FLASH, wide_bus) | + FIELD_PREP(ENABLE_BCH_ECC, host->bch_enabled); + + host->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | + FIELD_PREP(UD_SIZE_BYTES_MASK, host->cw_size) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); + + host->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | + FIELD_PREP(CS_ACTIVE_BSY, 0) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | + FIELD_PREP(WIDE_FLASH, wide_bus) | + FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); + + host->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !host->bch_enabled) | + FIELD_PREP(ECC_SW_RESET, 0) | + FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, host->cw_data) | + FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | + FIELD_PREP(ECC_MODE_MASK, ecc_mode) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, host->ecc_bytes_hw); if (!nandc->props->qpic_version2) host->ecc_buf_cfg = 0x203 << NUM_STEPS; @@ -1887,21 +1886,21 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ nandc->regs->addr0 = 0; nandc->regs->addr1 = 0; - nandc->regs->cfg0 = cpu_to_le32(0 << CW_PER_PAGE | - 512 << UD_SIZE_BYTES | - 5 << NUM_ADDR_CYCLES | - 0 << SPARE_SIZE_BYTES); + host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | + FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); - nandc->regs->cfg1 = cpu_to_le32(7 << NAND_RECOVERY_CYCLES | - 0 << CS_ACTIVE_BSY | - 17 << BAD_BLOCK_BYTE_NUM | - 1 << BAD_BLOCK_IN_SPARE_AREA | - 2 << WR_RD_BSY_GAP | - 0 << WIDE_FLASH | - 1 << DEV0_CFG1_ECC_DISABLE); + host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | + FIELD_PREP(CS_ACTIVE_BSY, 0) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | + FIELD_PREP(WIDE_FLASH, 0) | + FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); if (!nandc->props->qpic_version2) - nandc->regs->ecc_buf_cfg = cpu_to_le32(1 << ECC_CFG_ECC_DISABLE); + nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); /* configure CMD1 and VLD for ONFI param probing in QPIC v1 */ if (!nandc->props->qpic_version2) { diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h index 425994429387..e79c79775eb8 100644 --- a/include/linux/mtd/nand-qpic-common.h +++ b/include/linux/mtd/nand-qpic-common.h @@ -70,35 +70,42 @@ #define BS_CORRECTABLE_ERR_MSK 0x1f /* NAND_DEVn_CFG0 bits */ -#define DISABLE_STATUS_AFTER_WRITE 4 +#define DISABLE_STATUS_AFTER_WRITE BIT(4) #define CW_PER_PAGE 6 +#define CW_PER_PAGE_MASK GENMASK(8, 6) #define UD_SIZE_BYTES 9 #define UD_SIZE_BYTES_MASK GENMASK(18, 9) -#define ECC_PARITY_SIZE_BYTES_RS 19 +#define ECC_PARITY_SIZE_BYTES_RS GENMASK(22, 19) #define SPARE_SIZE_BYTES 23 #define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) #define NUM_ADDR_CYCLES 27 -#define STATUS_BFR_READ 30 -#define SET_RD_MODE_AFTER_STATUS 31 +#define NUM_ADDR_CYCLES_MASK GENMASK(29, 27) +#define STATUS_BFR_READ BIT(30) +#define SET_RD_MODE_AFTER_STATUS BIT(31) /* NAND_DEVn_CFG0 bits */ -#define DEV0_CFG1_ECC_DISABLE 0 -#define WIDE_FLASH 1 +#define DEV0_CFG1_ECC_DISABLE BIT(0) +#define WIDE_FLASH BIT(1) #define NAND_RECOVERY_CYCLES 2 -#define CS_ACTIVE_BSY 5 +#define NAND_RECOVERY_CYCLES_MASK GENMASK(4, 2) +#define CS_ACTIVE_BSY BIT(5) #define BAD_BLOCK_BYTE_NUM 6 -#define BAD_BLOCK_IN_SPARE_AREA 16 +#define BAD_BLOCK_BYTE_NUM_MASK GENMASK(15, 6) +#define BAD_BLOCK_IN_SPARE_AREA BIT(16) #define WR_RD_BSY_GAP 17 -#define ENABLE_BCH_ECC 27 +#define WR_RD_BSY_GAP_MASK GENMASK(22, 17) +#define ENABLE_BCH_ECC BIT(27) /* NAND_DEV0_ECC_CFG bits */ -#define ECC_CFG_ECC_DISABLE 0 -#define ECC_SW_RESET 1 +#define ECC_CFG_ECC_DISABLE BIT(0) +#define ECC_SW_RESET BIT(1) #define ECC_MODE 4 +#define ECC_MODE_MASK GENMASK(5, 4) #define ECC_PARITY_SIZE_BYTES_BCH 8 +#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8) #define ECC_NUM_DATA_BYTES 16 #define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) -#define ECC_FORCE_CLK_OPEN 30 +#define ECC_FORCE_CLK_OPEN BIT(30) /* NAND_DEV_CMD1 bits */ #define READ_ADDR 0 -- 2.51.0 From 7f26e2256fd3b07d0d72101cd313fbe8adc0b6c5 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 7 Feb 2025 20:42:38 +0100 Subject: [PATCH 014/517] mtd: rawnand: qcom: fix broken config in qcom_param_page_type_exec Fix broken config in qcom_param_page_type_exec caused by copy-paste error from commit 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") In qcom_param_page_type_exec the value needs to be set to nandc->regs->cfg0 instead of host->cfg0. This wrong configuration caused the Qcom NANDC driver to malfunction on any device that makes use of it (IPQ806x, IPQ40xx, IPQ807x, IPQ60xx) with the following error: [ 0.885369] nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xaa [ 0.885909] nand: Micron NAND 256MiB 1,8V 8-bit [ 0.892499] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 [ 0.896823] nand: ECC (step, strength) = (512, 8) does not fit in OOB [ 0.896836] qcom-nandc 79b0000.nand-controller: No valid ECC settings possible [ 0.910996] bam-dma-engine 7984000.dma-controller: Cannot free busy channel [ 0.918070] qcom-nandc: probe of 79b0000.nand-controller failed with error -28 Restore original configuration fix the problem and makes the driver work again. Cc: stable@vger.kernel.org Fixes: 0c08080fd71c ("mtd: rawnand: qcom: use FIELD_PREP and GENMASK") Signed-off-by: Christian Marangi --- drivers/mtd/nand/raw/qcom_nandc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 086cb139adf1..c3b26fee55a8 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1886,18 +1886,18 @@ static int qcom_param_page_type_exec(struct nand_chip *chip, const struct nand_ nandc->regs->addr0 = 0; nandc->regs->addr1 = 0; - host->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | - FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | - FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | - FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); - - host->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | - FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | - FIELD_PREP(CS_ACTIVE_BSY, 0) | - FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | - FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | - FIELD_PREP(WIDE_FLASH, 0) | - FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); + nandc->regs->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, 0) | + FIELD_PREP(UD_SIZE_BYTES_MASK, 512) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 5) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); + + nandc->regs->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 7) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | + FIELD_PREP(CS_ACTIVE_BSY, 0) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 2) | + FIELD_PREP(WIDE_FLASH, 0) | + FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); if (!nandc->props->qpic_version2) nandc->regs->ecc_buf_cfg = cpu_to_le32(ECC_CFG_ECC_DISABLE); -- 2.51.0 From 49f737acfea2251c082d8669fe62fabb1f13f626 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 6 Jan 2025 18:45:58 +0530 Subject: [PATCH 015/517] mtd: rawnand: qcom: Fix build issue on x86 architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a buffer overflow issue in qcom_clear_bam_transaction by using struct_group to group related fields and avoid FORTIFY_SOURCE warnings. On x86 architecture, the following error occurs due to warnings being treated as errors: In function ‘fortify_memset_chk’, inlined from ‘qcom_clear_bam_transaction’ at drivers/mtd/nand/qpic_common.c:88:2: ./include/linux/fortify-string.h:480:25: error: call to ‘__write_overflow_field’ declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] 480 | __write_overflow_field(p_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LD [M] drivers/mtd/nand/nandcore.o CC [M] drivers/w1/masters/mxc_w1.o cc1: all warnings being treated as errors This patch addresses the issue by grouping the related fields in struct bam_transaction using struct_group and updating the memset call accordingly. Fixes: 8c52932da5e6 ("mtd: rawnand: qcom: cleanup qcom_nandc driver") Signed-off-by: Md Sadre Alam Signed-off-by: Miquel Raynal --- drivers/mtd/nand/qpic_common.c | 2 +- include/linux/mtd/nand-qpic-common.h | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/qpic_common.c b/drivers/mtd/nand/qpic_common.c index 8abbb960a7ce..e0ed25b5afea 100644 --- a/drivers/mtd/nand/qpic_common.c +++ b/drivers/mtd/nand/qpic_common.c @@ -85,7 +85,7 @@ void qcom_clear_bam_transaction(struct qcom_nand_controller *nandc) if (!nandc->props->supports_bam) return; - memset(&bam_txn->bam_ce_pos, 0, sizeof(u32) * 8); + memset(&bam_txn->bam_positions, 0, sizeof(bam_txn->bam_positions)); bam_txn->last_data_desc = NULL; sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h index e79c79775eb8..4d9b736ff8b7 100644 --- a/include/linux/mtd/nand-qpic-common.h +++ b/include/linux/mtd/nand-qpic-common.h @@ -254,14 +254,17 @@ struct bam_transaction { struct dma_async_tx_descriptor *last_data_desc; struct dma_async_tx_descriptor *last_cmd_desc; struct completion txn_done; - u32 bam_ce_pos; - u32 bam_ce_start; - u32 cmd_sgl_pos; - u32 cmd_sgl_start; - u32 tx_sgl_pos; - u32 tx_sgl_start; - u32 rx_sgl_pos; - u32 rx_sgl_start; + struct_group(bam_positions, + u32 bam_ce_pos; + u32 bam_ce_start; + u32 cmd_sgl_pos; + u32 cmd_sgl_start; + u32 tx_sgl_pos; + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; + + ); }; /* -- 2.51.0 From ab61cede0b93c3d9c961220f76bf9918611d2884 Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Mon, 24 Feb 2025 16:44:14 +0530 Subject: [PATCH 016/517] spi: spi-qpic: add driver for QCOM SPI NAND flash Interface This driver implements support for the SPI-NAND mode of QCOM NAND Flash Interface as a SPI-MEM controller with pipelined ECC capability. Co-developed-by: Sricharan Ramabadhran Signed-off-by: Sricharan Ramabadhran Co-developed-by: Varadarajan Narayanan Signed-off-by: Varadarajan Narayanan Signed-off-by: Md Sadre Alam Link: https://patch.msgid.link/20250224111414.2809669-3-quic_mdalam@quicinc.com Signed-off-by: Mark Brown --- drivers/mtd/nand/Makefile | 4 + drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/spi-qpic-snand.c | 1631 ++++++++++++++++++++++++++ include/linux/mtd/nand-qpic-common.h | 7 + 5 files changed, 1652 insertions(+) create mode 100644 drivers/spi/spi-qpic-snand.c diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index da1586a36574..db516a45f0c5 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -3,7 +3,11 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +ifeq ($(CONFIG_SPI_QPIC_SNAND),y) +obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o +else obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o +endif obj-y += onenand/ obj-y += raw/ obj-y += spi/ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 823797217404..98c5fa460fb1 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -898,6 +898,15 @@ config SPI_QCOM_QSPI help QSPI(Quad SPI) driver for Qualcomm QSPI controller. +config SPI_QPIC_SNAND + bool "QPIC SNAND controller" + depends on ARCH_QCOM || COMPILE_TEST + select MTD + help + QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller. + QPIC controller supports both parallel nand and serial nand. + This config will enable serial nand driver for QPIC controller. + config SPI_QUP tristate "Qualcomm SPI controller with QUP interface" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a9b1bc259b68..d9d674eb84a6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -114,6 +114,7 @@ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o +obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c new file mode 100644 index 000000000000..1a4746d0fd62 --- /dev/null +++ b/drivers/spi/spi-qpic-snand.c @@ -0,0 +1,1631 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Authors: + * Md Sadre Alam + * Sricharan R + * Varadarajan Narayanan + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAND_FLASH_SPI_CFG 0xc0 +#define NAND_NUM_ADDR_CYCLES 0xc4 +#define NAND_BUSY_CHECK_WAIT_CNT 0xc8 +#define NAND_FLASH_FEATURES 0xf64 + +/* QSPI NAND config reg bits */ +#define LOAD_CLK_CNTR_INIT_EN BIT(28) +#define CLK_CNTR_INIT_VAL_VEC 0x924 +#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16) +#define FEA_STATUS_DEV_ADDR 0xc0 +#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8) +#define SPI_CFG BIT(0) +#define SPI_NUM_ADDR 0xDA4DB +#define SPI_WAIT_CNT 0x10 +#define QPIC_QSPI_NUM_CS 1 +#define SPI_TRANSFER_MODE_x1 BIT(29) +#define SPI_TRANSFER_MODE_x4 (3 << 29) +#define SPI_WP BIT(28) +#define SPI_HOLD BIT(27) +#define QPIC_SET_FEATURE BIT(31) + +#define SPINAND_RESET 0xff +#define SPINAND_READID 0x9f +#define SPINAND_GET_FEATURE 0x0f +#define SPINAND_SET_FEATURE 0x1f +#define SPINAND_READ 0x13 +#define SPINAND_ERASE 0xd8 +#define SPINAND_WRITE_EN 0x06 +#define SPINAND_PROGRAM_EXECUTE 0x10 +#define SPINAND_PROGRAM_LOAD 0x84 + +#define ACC_FEATURE 0xe +#define BAD_BLOCK_MARKER_SIZE 0x2 +#define OOB_BUF_SIZE 128 +#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng) + +struct qpic_snand_op { + u32 cmd_reg; + u32 addr1_reg; + u32 addr2_reg; +}; + +struct snandc_read_status { + __le32 snandc_flash; + __le32 snandc_buffer; + __le32 snandc_erased_cw; +}; + +/* + * ECC state struct + * @corrected: ECC corrected + * @bitflips: Max bit flip + * @failed: ECC failed + */ +struct qcom_ecc_stats { + u32 corrected; + u32 bitflips; + u32 failed; +}; + +struct qpic_ecc { + struct device *dev; + int ecc_bytes_hw; + int spare_bytes; + int bbm_size; + int ecc_mode; + int bytes; + int steps; + int step_size; + int strength; + int cw_size; + int cw_data; + u32 cfg0; + u32 cfg1; + u32 cfg0_raw; + u32 cfg1_raw; + u32 ecc_buf_cfg; + u32 ecc_bch_cfg; + u32 clrflashstatus; + u32 clrreadstatus; + bool bch_enabled; +}; + +struct qpic_spi_nand { + struct qcom_nand_controller *snandc; + struct spi_controller *ctlr; + struct mtd_info *mtd; + struct clk *iomacro_clk; + struct qpic_ecc *ecc; + struct qcom_ecc_stats ecc_stats; + struct nand_ecc_engine ecc_eng; + u8 *data_buf; + u8 *oob_buf; + u32 wlen; + __le32 addr1; + __le32 addr2; + __le32 cmd; + u32 num_cw; + bool oob_rw; + bool page_rw; + bool raw_rw; +}; + +static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, + int reg, int cw_offset, int read_size, + int is_last_read_loc) +{ + __le32 locreg_val; + u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | + ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) + << READ_LOCATION_LAST)); + + locreg_val = cpu_to_le32(val); + + if (reg == NAND_READ_LOCATION_0) + snandc->regs->read_location0 = locreg_val; + else if (reg == NAND_READ_LOCATION_1) + snandc->regs->read_location1 = locreg_val; + else if (reg == NAND_READ_LOCATION_2) + snandc->regs->read_location1 = locreg_val; + else if (reg == NAND_READ_LOCATION_3) + snandc->regs->read_location3 = locreg_val; +} + +static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc, + int reg, int cw_offset, int read_size, + int is_last_read_loc) +{ + __le32 locreg_val; + u32 val = (((cw_offset) << READ_LOCATION_OFFSET) | + ((read_size) << READ_LOCATION_SIZE) | ((is_last_read_loc) + << READ_LOCATION_LAST)); + + locreg_val = cpu_to_le32(val); + + if (reg == NAND_READ_LOCATION_LAST_CW_0) + snandc->regs->read_location_last0 = locreg_val; + else if (reg == NAND_READ_LOCATION_LAST_CW_1) + snandc->regs->read_location_last1 = locreg_val; + else if (reg == NAND_READ_LOCATION_LAST_CW_2) + snandc->regs->read_location_last2 = locreg_val; + else if (reg == NAND_READ_LOCATION_LAST_CW_3) + snandc->regs->read_location_last3 = locreg_val; +} + +static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand) +{ + struct nand_ecc_engine *eng = nand->ecc.engine; + struct qpic_spi_nand *qspi = ecceng_to_qspi(eng); + + return qspi->snandc; +} + +static int qcom_spi_init(struct qcom_nand_controller *snandc) +{ + u32 snand_cfg_val = 0x0; + int ret; + + snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) | + FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) | + FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) | + FIELD_PREP(SPI_CFG, 0); + + snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); + snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR); + snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT); + + qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); + + snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN; + snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val); + + qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0); + + qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1, + NAND_BAM_NEXT_SGL); + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure in submitting spi init descriptor\n"); + return ret; + } + + return ret; +} + +static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct qpic_ecc *qecc = snandc->qspi->ecc; + + if (section > 1) + return -ERANGE; + + oobregion->length = qecc->ecc_bytes_hw + qecc->spare_bytes; + oobregion->offset = mtd->oobsize - oobregion->length; + + return 0; +} + +static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct qpic_ecc *qecc = snandc->qspi->ecc; + + if (section) + return -ERANGE; + + oobregion->length = qecc->steps * 4; + oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size; + + return 0; +} + +static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { + .ecc = qcom_spi_ooblayout_ecc, + .free = qcom_spi_ooblayout_free, +}; + +static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) +{ + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct nand_ecc_props *conf = &nand->ecc.ctx.conf; + struct mtd_info *mtd = nanddev_to_mtd(nand); + int cwperpage, bad_block_byte; + struct qpic_ecc *ecc_cfg; + + cwperpage = mtd->writesize / NANDC_STEP_SIZE; + snandc->qspi->num_cw = cwperpage; + + ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); + if (!ecc_cfg) + return -ENOMEM; + snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!snandc->qspi->oob_buf) + return -ENOMEM; + + memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); + + nand->ecc.ctx.priv = ecc_cfg; + snandc->qspi->mtd = mtd; + + ecc_cfg->ecc_bytes_hw = 7; + ecc_cfg->spare_bytes = 4; + ecc_cfg->bbm_size = 1; + ecc_cfg->bch_enabled = true; + ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; + + ecc_cfg->steps = 4; + ecc_cfg->strength = 4; + ecc_cfg->step_size = 512; + ecc_cfg->cw_data = 516; + ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; + bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; + + mtd_set_ooblayout(mtd, &qcom_spi_ooblayout); + + ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | + FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) | + FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) | + FIELD_PREP(STATUS_BFR_READ, 0) | + FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes); + + ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | + FIELD_PREP(CS_ACTIVE_BSY, 0) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | + FIELD_PREP(WIDE_FLASH, 0) | + FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled); + + ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) | + FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) | + FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) | + FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0); + + ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) | + FIELD_PREP(CS_ACTIVE_BSY, 0) | + FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) | + FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) | + FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) | + FIELD_PREP(WIDE_FLASH, 0) | + FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1); + + ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) | + FIELD_PREP(ECC_SW_RESET, 0) | + FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | + FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | + FIELD_PREP(ECC_MODE_MASK, 0) | + FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); + + ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; + ecc_cfg->clrflashstatus = FS_READY_BSY_N; + ecc_cfg->clrreadstatus = 0xc0; + + conf->step_size = ecc_cfg->step_size; + conf->strength = ecc_cfg->strength; + + snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET); + snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET); + + dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n", + ecc_cfg->strength, ecc_cfg->step_size); + + return 0; +} + +static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) +{ + struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); + + kfree(ecc_cfg); +} + +static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand, + struct nand_page_io_req *req) +{ + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand); + + snandc->qspi->ecc = ecc_cfg; + snandc->qspi->raw_rw = false; + snandc->qspi->oob_rw = false; + snandc->qspi->page_rw = false; + + if (req->datalen) + snandc->qspi->page_rw = true; + + if (req->ooblen) + snandc->qspi->oob_rw = true; + + if (req->mode == MTD_OPS_RAW) + snandc->qspi->raw_rw = true; + + return 0; +} + +static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand, + struct nand_page_io_req *req) +{ + struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct mtd_info *mtd = nanddev_to_mtd(nand); + + if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ) + return 0; + + if (snandc->qspi->ecc_stats.failed) + mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed; + else + mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected; + + if (snandc->qspi->ecc_stats.failed) + return -EBADMSG; + else + return snandc->qspi->ecc_stats.bitflips; +} + +static struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = { + .init_ctx = qcom_spi_ecc_init_ctx_pipelined, + .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined, + .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined, + .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined, +}; + +/* helper to configure location register values */ +static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg, + int cw_offset, int read_size, int is_last_read_loc) +{ + int reg_base = NAND_READ_LOCATION_0; + int num_cw = snandc->qspi->num_cw; + + if (cw == (num_cw - 1)) + reg_base = NAND_READ_LOCATION_LAST_CW_0; + + reg_base += reg * 4; + + if (cw == (num_cw - 1)) + return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset, + read_size, is_last_read_loc); + else + return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset, + read_size, is_last_read_loc); +} + +static void +qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw) +{ + __le32 *reg = &snandc->regs->read_location0; + int num_cw = snandc->qspi->num_cw; + + qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL); + if (cw == (num_cw - 1)) { + reg = &snandc->regs->read_location_last0; + qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, + NAND_BAM_NEXT_SGL); + } + + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0); + qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1, + NAND_BAM_NEXT_SGL); +} + +static int qcom_spi_block_erase(struct qcom_nand_controller *snandc) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + int ret; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->addr0 = snandc->qspi->addr1; + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cfg0 = cpu_to_le32(ecc_cfg->cfg0_raw & ~(7 << CW_PER_PAGE)); + snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw); + snandc->regs->exec = cpu_to_le32(1); + + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to erase block\n"); + return ret; + } + + return 0; +} + +static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc, + bool use_ecc, int cw) +{ + __le32 *reg = &snandc->regs->read_location0; + int num_cw = snandc->qspi->num_cw; + + qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + + if (cw == (num_cw - 1)) { + reg = &snandc->regs->read_location_last0; + qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL); + } + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0); +} + +static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + struct mtd_info *mtd = snandc->qspi->mtd; + int size, ret = 0; + int col, bbpos; + u32 cfg0, cfg1, ecc_bch_cfg; + u32 num_cw = snandc->qspi->num_cw; + + qcom_clear_bam_transaction(snandc); + qcom_clear_read_regs(snandc); + + size = ecc_cfg->cw_size; + col = ecc_cfg->cw_size * (num_cw - 1); + + memset(snandc->data_buffer, 0xff, size); + snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); + snandc->regs->addr1 = snandc->qspi->addr2; + + cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | + 0 << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1_raw; + ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; + + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); + snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1); + + qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1); + + qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0); + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failed to read last cw\n"); + return ret; + } + + qcom_nandc_dev_to_mem(snandc, true); + u32 flash = le32_to_cpu(snandc->reg_read_buf[0]); + + if (flash & (FS_OP_ERR | FS_MPU_ERR)) + return -EIO; + + bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); + + if (snandc->data_buffer[bbpos] == 0xff) + snandc->data_buffer[bbpos + 1] = 0xff; + if (snandc->data_buffer[bbpos] != 0xff) + snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos]; + + memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes); + + return ret; +} + +static int qcom_spi_check_error(struct qcom_nand_controller *snandc, u8 *data_buf, u8 *oob_buf) +{ + struct snandc_read_status *buf; + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + int i, num_cw = snandc->qspi->num_cw; + bool flash_op_err = false, erased; + unsigned int max_bitflips = 0; + unsigned int uncorrectable_cws = 0; + + snandc->qspi->ecc_stats.failed = 0; + snandc->qspi->ecc_stats.corrected = 0; + + qcom_nandc_dev_to_mem(snandc, true); + buf = (struct snandc_read_status *)snandc->reg_read_buf; + + for (i = 0; i < num_cw; i++, buf++) { + u32 flash, buffer, erased_cw; + int data_len, oob_len; + + if (i == (num_cw - 1)) { + data_len = NANDC_STEP_SIZE - ((num_cw - 1) << 2); + oob_len = num_cw << 2; + } else { + data_len = ecc_cfg->cw_data; + oob_len = 0; + } + + flash = le32_to_cpu(buf->snandc_flash); + buffer = le32_to_cpu(buf->snandc_buffer); + erased_cw = le32_to_cpu(buf->snandc_erased_cw); + + if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) { + if (ecc_cfg->bch_enabled) + erased = (erased_cw & ERASED_CW) == ERASED_CW; + else + erased = false; + + if (!erased) + uncorrectable_cws |= BIT(i); + + } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) { + flash_op_err = true; + } else { + unsigned int stat; + + stat = buffer & BS_CORRECTABLE_ERR_MSK; + snandc->qspi->ecc_stats.corrected += stat; + max_bitflips = max(max_bitflips, stat); + } + + if (data_buf) + data_buf += data_len; + if (oob_buf) + oob_buf += oob_len + ecc_cfg->bytes; + } + + if (flash_op_err) + return -EIO; + + if (!uncorrectable_cws) + snandc->qspi->ecc_stats.bitflips = max_bitflips; + else + snandc->qspi->ecc_stats.failed++; + + return 0; +} + +static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt) +{ + int i; + + qcom_nandc_dev_to_mem(snandc, true); + + for (i = 0; i < cw_cnt; i++) { + u32 flash = le32_to_cpu(snandc->reg_read_buf[i]); + + if (flash & (FS_OP_ERR | FS_MPU_ERR)) + return -EIO; + } + + return 0; +} + +static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf, + u8 *oob_buf, int cw) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + struct mtd_info *mtd = snandc->qspi->mtd; + int data_size1, data_size2, oob_size1, oob_size2; + int ret, reg_off = FLASH_BUF_ACC, read_loc = 0; + int raw_cw = cw; + u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; + int col; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + raw_cw = num_cw - 1; + + cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | + 0 << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1_raw; + ecc_bch_cfg = ECC_CFG_ECC_DISABLE; + + col = ecc_cfg->cw_size * cw; + + snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); + snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1); + + qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); + + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + + data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); + oob_size1 = ecc_cfg->bbm_size; + + if (cw == (num_cw - 1)) { + data_size2 = NANDC_STEP_SIZE - data_size1 - + ((num_cw - 1) * 4); + oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw + + ecc_cfg->spare_bytes; + } else { + data_size2 = ecc_cfg->cw_data - data_size1; + oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; + } + + qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0); + read_loc += data_size1; + + qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0); + read_loc += oob_size1; + + qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0); + read_loc += data_size2; + + qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1); + + qcom_spi_config_cw_read(snandc, false, raw_cw); + + qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0); + reg_off += data_size1; + + qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0); + reg_off += oob_size1; + + qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0); + reg_off += data_size2; + + qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0); + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to read raw cw %d\n", cw); + return ret; + } + + return qcom_spi_check_raw_flash_errors(snandc, 1); +} + +static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + u8 *data_buf = NULL, *oob_buf = NULL; + int ret, cw; + u32 num_cw = snandc->qspi->num_cw; + + if (snandc->qspi->page_rw) + data_buf = op->data.buf.in; + + oob_buf = snandc->qspi->oob_buf; + memset(oob_buf, 0xff, OOB_BUF_SIZE); + + for (cw = 0; cw < num_cw; cw++) { + ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw); + if (ret) + return ret; + + if (data_buf) + data_buf += ecc_cfg->cw_data; + if (oob_buf) + oob_buf += ecc_cfg->bytes; + } + + return 0; +} + +static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; + int ret, i; + u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; + + data_buf = op->data.buf.in; + data_buf_start = data_buf; + + oob_buf = snandc->qspi->oob_buf; + oob_buf_start = oob_buf; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + + cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1; + ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; + + snandc->regs->addr0 = snandc->qspi->addr1; + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); + snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); + + qcom_clear_bam_transaction(snandc); + + qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + + for (i = 0; i < num_cw; i++) { + int data_size, oob_size; + + if (i == (num_cw - 1)) { + data_size = 512 - ((num_cw - 1) << 2); + oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + + ecc_cfg->spare_bytes; + } else { + data_size = ecc_cfg->cw_data; + oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; + } + + if (data_buf && oob_buf) { + qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0); + qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1); + } else if (data_buf) { + qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1); + } else { + qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); + } + + qcom_spi_config_cw_read(snandc, true, i); + + if (data_buf) + qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf, + data_size, 0); + if (oob_buf) { + int j; + + for (j = 0; j < ecc_cfg->bbm_size; j++) + *oob_buf++ = 0xff; + + qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, + oob_buf, oob_size, 0); + } + + if (data_buf) + data_buf += data_size; + if (oob_buf) + oob_buf += oob_size; + } + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to read page\n"); + return ret; + } + + return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); +} + +static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + u8 *data_buf = NULL, *data_buf_start, *oob_buf = NULL, *oob_buf_start; + int ret, i; + u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw; + + oob_buf = op->data.buf.in; + oob_buf_start = oob_buf; + + data_buf_start = data_buf; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + + cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1; + ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; + + snandc->regs->addr0 = snandc->qspi->addr1; + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); + snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1); + + qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, + NAND_ERASED_CW_DETECT_CFG, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, + NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); + + for (i = 0; i < num_cw; i++) { + int data_size, oob_size; + + if (i == (num_cw - 1)) { + data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); + oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + + ecc_cfg->spare_bytes; + } else { + data_size = ecc_cfg->cw_data; + oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; + } + + qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1); + + qcom_spi_config_cw_read(snandc, true, i); + + if (oob_buf) { + int j; + + for (j = 0; j < ecc_cfg->bbm_size; j++) + *oob_buf++ = 0xff; + + qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size, + oob_buf, oob_size, 0); + } + + if (oob_buf) + oob_buf += oob_size; + } + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to read oob\n"); + return ret; + } + + return qcom_spi_check_error(snandc, data_buf_start, oob_buf_start); +} + +static int qcom_spi_read_page(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + if (snandc->qspi->page_rw && snandc->qspi->raw_rw) + return qcom_spi_read_page_raw(snandc, op); + + if (snandc->qspi->page_rw) + return qcom_spi_read_page_ecc(snandc, op); + + if (snandc->qspi->oob_rw && snandc->qspi->raw_rw) + return qcom_spi_read_last_cw(snandc, op); + + if (snandc->qspi->oob_rw) + return qcom_spi_read_page_oob(snandc, op); + + return 0; +} + +static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc) +{ + qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); + qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); + qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, + 1, NAND_BAM_NEXT_SGL); +} + +static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc) +{ + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); + + qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0); + qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1, + NAND_BAM_NEXT_SGL); +} + +static int qcom_spi_program_raw(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + struct mtd_info *mtd = snandc->qspi->mtd; + u8 *data_buf = NULL, *oob_buf = NULL; + int i, ret; + int num_cw = snandc->qspi->num_cw; + u32 cfg0, cfg1, ecc_bch_cfg; + + cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1_raw; + ecc_bch_cfg = ECC_CFG_ECC_DISABLE; + + data_buf = snandc->qspi->data_buf; + + oob_buf = snandc->qspi->oob_buf; + memset(oob_buf, 0xff, OOB_BUF_SIZE); + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + + snandc->regs->addr0 = snandc->qspi->addr1; + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->clrflashstatus = cpu_to_le32(ecc_cfg->clrflashstatus); + snandc->regs->clrreadstatus = cpu_to_le32(ecc_cfg->clrreadstatus); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_config_page_write(snandc); + + for (i = 0; i < num_cw; i++) { + int data_size1, data_size2, oob_size1, oob_size2; + int reg_off = FLASH_BUF_ACC; + + data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1); + oob_size1 = ecc_cfg->bbm_size; + + if (i == (num_cw - 1)) { + data_size2 = NANDC_STEP_SIZE - data_size1 - + ((num_cw - 1) << 2); + oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + + ecc_cfg->spare_bytes; + } else { + data_size2 = ecc_cfg->cw_data - data_size1; + oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes; + } + + qcom_write_data_dma(snandc, reg_off, data_buf, data_size1, + NAND_BAM_NO_EOT); + reg_off += data_size1; + data_buf += data_size1; + + qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1, + NAND_BAM_NO_EOT); + oob_buf += oob_size1; + reg_off += oob_size1; + + qcom_write_data_dma(snandc, reg_off, data_buf, data_size2, + NAND_BAM_NO_EOT); + reg_off += data_size2; + data_buf += data_size2; + + qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0); + oob_buf += oob_size2; + + qcom_spi_config_cw_write(snandc); + } + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to write raw page\n"); + return ret; + } + + return 0; +} + +static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + u8 *data_buf = NULL, *oob_buf = NULL; + int i, ret; + int num_cw = snandc->qspi->num_cw; + u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; + + cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1; + ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; + ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; + + if (snandc->qspi->data_buf) + data_buf = snandc->qspi->data_buf; + + oob_buf = snandc->qspi->oob_buf; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + + snandc->regs->addr0 = snandc->qspi->addr1; + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); + snandc->regs->exec = cpu_to_le32(1); + + qcom_spi_config_page_write(snandc); + + for (i = 0; i < num_cw; i++) { + int data_size, oob_size; + + if (i == (num_cw - 1)) { + data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); + oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw + + ecc_cfg->spare_bytes; + } else { + data_size = ecc_cfg->cw_data; + oob_size = ecc_cfg->bytes; + } + + if (data_buf) + qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size, + i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0); + + if (i == (num_cw - 1)) { + if (oob_buf) { + oob_buf += ecc_cfg->bbm_size; + qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size, + oob_buf, oob_size, 0); + } + } + + qcom_spi_config_cw_write(snandc); + + if (data_buf) + data_buf += data_size; + if (oob_buf) + oob_buf += oob_size; + } + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to write page\n"); + return ret; + } + + return 0; +} + +static int qcom_spi_program_oob(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_ecc *ecc_cfg = snandc->qspi->ecc; + u8 *oob_buf = NULL; + int ret, col, data_size, oob_size; + int num_cw = snandc->qspi->num_cw; + u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg; + + cfg0 = (ecc_cfg->cfg0 & ~(7U << CW_PER_PAGE)) | + (num_cw - 1) << CW_PER_PAGE; + cfg1 = ecc_cfg->cfg1; + ecc_bch_cfg = ecc_cfg->ecc_bch_cfg; + ecc_buf_cfg = ecc_cfg->ecc_buf_cfg; + + col = ecc_cfg->cw_size * (num_cw - 1); + + oob_buf = snandc->qspi->data_buf; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col)); + snandc->regs->addr1 = snandc->qspi->addr2; + snandc->regs->cmd = snandc->qspi->cmd; + snandc->regs->cfg0 = cpu_to_le32(cfg0); + snandc->regs->cfg1 = cpu_to_le32(cfg1); + snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg); + snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg); + snandc->regs->exec = cpu_to_le32(1); + + /* calculate the data and oob size for the last codeword/step */ + data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2); + oob_size = snandc->qspi->mtd->oobavail; + + memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data); + /* override new oob content to last codeword */ + mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size, + oob_buf, 0, snandc->qspi->mtd->oobavail); + qcom_spi_config_page_write(snandc); + qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0); + qcom_spi_config_cw_write(snandc); + + ret = qcom_submit_descs(snandc); + if (ret) { + dev_err(snandc->dev, "failure to write oob\n"); + return ret; + } + + return 0; +} + +static int qcom_spi_program_execute(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + if (snandc->qspi->page_rw && snandc->qspi->raw_rw) + return qcom_spi_program_raw(snandc, op); + + if (snandc->qspi->page_rw) + return qcom_spi_program_ecc(snandc, op); + + if (snandc->qspi->oob_rw) + return qcom_spi_program_oob(snandc, op); + + return 0; +} + +static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd) +{ + switch (opcode) { + case SPINAND_RESET: + *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE); + break; + case SPINAND_READID: + *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID); + break; + case SPINAND_GET_FEATURE: + *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE); + break; + case SPINAND_SET_FEATURE: + *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE | + QPIC_SET_FEATURE); + break; + case SPINAND_READ: + if (snandc->qspi->raw_rw) { + *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | + SPI_WP | SPI_HOLD | OP_PAGE_READ); + } else { + *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | + SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC); + } + + break; + case SPINAND_ERASE: + *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP | + SPI_HOLD | SPI_TRANSFER_MODE_x1; + break; + case SPINAND_WRITE_EN: + *cmd = SPINAND_WRITE_EN; + break; + case SPINAND_PROGRAM_EXECUTE: + *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 | + SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE); + break; + case SPINAND_PROGRAM_LOAD: + *cmd = SPINAND_PROGRAM_LOAD; + break; + default: + dev_err(snandc->dev, "Opcode not supported: %u\n", opcode); + return -EOPNOTSUPP; + } + + return 0; +} + +static int qcom_spi_write_page(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + int ret; + u32 cmd; + + ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); + if (ret < 0) + return ret; + + if (op->cmd.opcode == SPINAND_PROGRAM_LOAD) + snandc->qspi->data_buf = (u8 *)op->data.buf.out; + + return 0; +} + +static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, + const struct spi_mem_op *op) +{ + struct qpic_snand_op s_op = {}; + u32 cmd; + int ret, opcode; + + ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd); + if (ret < 0) + return ret; + + s_op.cmd_reg = cmd; + s_op.addr1_reg = op->addr.val; + s_op.addr2_reg = 0; + + opcode = op->cmd.opcode; + + switch (opcode) { + case SPINAND_WRITE_EN: + return 0; + case SPINAND_PROGRAM_EXECUTE: + s_op.addr1_reg = op->addr.val << 16; + s_op.addr2_reg = op->addr.val >> 16 & 0xff; + snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); + snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); + snandc->qspi->cmd = cpu_to_le32(cmd); + return qcom_spi_program_execute(snandc, op); + case SPINAND_READ: + s_op.addr1_reg = (op->addr.val << 16); + s_op.addr2_reg = op->addr.val >> 16 & 0xff; + snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg); + snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); + snandc->qspi->cmd = cpu_to_le32(cmd); + return 0; + case SPINAND_ERASE: + s_op.addr2_reg = (op->addr.val >> 16) & 0xffff; + s_op.addr1_reg = op->addr.val; + snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16); + snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); + snandc->qspi->cmd = cpu_to_le32(cmd); + qcom_spi_block_erase(snandc); + return 0; + default: + break; + } + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + + snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg); + snandc->regs->exec = cpu_to_le32(1); + snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg); + snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg); + + qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); + qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); + + ret = qcom_submit_descs(snandc); + if (ret) + dev_err(snandc->dev, "failure in submitting cmd descriptor\n"); + + return ret; +} + +static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op) +{ + int ret, val, opcode; + bool copy = false, copy_ftr = false; + + ret = qcom_spi_send_cmdaddr(snandc, op); + if (ret) + return ret; + + snandc->buf_count = 0; + snandc->buf_start = 0; + qcom_clear_read_regs(snandc); + qcom_clear_bam_transaction(snandc); + opcode = op->cmd.opcode; + + switch (opcode) { + case SPINAND_READID: + snandc->buf_count = 4; + qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); + copy = true; + break; + case SPINAND_GET_FEATURE: + snandc->buf_count = 4; + qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); + copy_ftr = true; + break; + case SPINAND_SET_FEATURE: + snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out); + qcom_write_reg_dma(snandc, &snandc->regs->flash_feature, + NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL); + break; + case SPINAND_PROGRAM_EXECUTE: + case SPINAND_WRITE_EN: + case SPINAND_RESET: + case SPINAND_ERASE: + case SPINAND_READ: + return 0; + default: + return -EOPNOTSUPP; + } + + ret = qcom_submit_descs(snandc); + if (ret) + dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode); + + if (copy) { + qcom_nandc_dev_to_mem(snandc, true); + memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count); + } + + if (copy_ftr) { + qcom_nandc_dev_to_mem(snandc, true); + val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf); + val >>= 8; + memcpy(op->data.buf.in, &val, snandc->buf_count); + } + + return ret; +} + +static bool qcom_spi_is_page_op(const struct spi_mem_op *op) +{ + if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4) + return false; + + if (op->data.dir == SPI_MEM_DATA_IN) { + if (op->addr.buswidth == 4 && op->data.buswidth == 4) + return true; + + if (op->addr.nbytes == 2 && op->addr.buswidth == 1) + return true; + + } else if (op->data.dir == SPI_MEM_DATA_OUT) { + if (op->data.buswidth == 4) + return true; + if (op->addr.nbytes == 2 && op->addr.buswidth == 1) + return true; + } + + return false; +} + +static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + + if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) + return false; + + if (qcom_spi_is_page_op(op)) + return true; + + return ((!op->addr.nbytes || op->addr.buswidth == 1) && + (!op->dummy.nbytes || op->dummy.buswidth == 1) && + (!op->data.nbytes || op->data.buswidth == 1)); +} + +static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller); + + dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode, + op->addr.val, op->addr.buswidth, op->addr.nbytes, + op->data.buswidth, op->data.nbytes); + + if (qcom_spi_is_page_op(op)) { + if (op->data.dir == SPI_MEM_DATA_IN) + return qcom_spi_read_page(snandc, op); + if (op->data.dir == SPI_MEM_DATA_OUT) + return qcom_spi_write_page(snandc, op); + } else { + return qcom_spi_io_op(snandc, op); + } + + return 0; +} + +static const struct spi_controller_mem_ops qcom_spi_mem_ops = { + .supports_op = qcom_spi_supports_op, + .exec_op = qcom_spi_exec_op, +}; + +static const struct spi_controller_mem_caps qcom_spi_mem_caps = { + .ecc = true, +}; + +static int qcom_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_controller *ctlr; + struct qcom_nand_controller *snandc; + struct qpic_spi_nand *qspi; + struct qpic_ecc *ecc; + struct resource *res; + const void *dev_data; + int ret; + + ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); + if (!ecc) + return -ENOMEM; + + qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL); + if (!qspi) + return -ENOMEM; + + ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false); + if (!ctlr) + return -ENOMEM; + + platform_set_drvdata(pdev, ctlr); + + snandc = spi_controller_get_devdata(ctlr); + qspi->snandc = snandc; + + snandc->dev = dev; + snandc->qspi = qspi; + snandc->qspi->ctlr = ctlr; + snandc->qspi->ecc = ecc; + + dev_data = of_device_get_match_data(dev); + if (!dev_data) { + dev_err(&pdev->dev, "failed to get device data\n"); + return -ENODEV; + } + + snandc->props = dev_data; + snandc->dev = &pdev->dev; + + snandc->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(snandc->core_clk)) + return PTR_ERR(snandc->core_clk); + + snandc->aon_clk = devm_clk_get(dev, "aon"); + if (IS_ERR(snandc->aon_clk)) + return PTR_ERR(snandc->aon_clk); + + snandc->qspi->iomacro_clk = devm_clk_get(dev, "iom"); + if (IS_ERR(snandc->qspi->iomacro_clk)) + return PTR_ERR(snandc->qspi->iomacro_clk); + + snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(snandc->base)) + return PTR_ERR(snandc->base); + + snandc->base_phys = res->start; + snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res), + DMA_BIDIRECTIONAL, 0); + if (dma_mapping_error(dev, snandc->base_dma)) + return -ENXIO; + + ret = clk_prepare_enable(snandc->core_clk); + if (ret) + goto err_dis_core_clk; + + ret = clk_prepare_enable(snandc->aon_clk); + if (ret) + goto err_dis_aon_clk; + + ret = clk_prepare_enable(snandc->qspi->iomacro_clk); + if (ret) + goto err_dis_iom_clk; + + ret = qcom_nandc_alloc(snandc); + if (ret) + goto err_snand_alloc; + + ret = qcom_spi_init(snandc); + if (ret) + goto err_spi_init; + + /* setup ECC engine */ + snandc->qspi->ecc_eng.dev = &pdev->dev; + snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED; + snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined; + snandc->qspi->ecc_eng.priv = snandc; + + ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng); + if (ret) { + dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret); + goto err_spi_init; + } + + ctlr->num_chipselect = QPIC_QSPI_NUM_CS; + ctlr->mem_ops = &qcom_spi_mem_ops; + ctlr->mem_caps = &qcom_spi_mem_caps; + ctlr->dev.of_node = pdev->dev.of_node; + ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL | + SPI_TX_QUAD | SPI_RX_QUAD; + + ret = spi_register_controller(ctlr); + if (ret) { + dev_err(&pdev->dev, "spi_register_controller failed.\n"); + goto err_spi_init; + } + + return 0; + +err_spi_init: + qcom_nandc_unalloc(snandc); +err_snand_alloc: + clk_disable_unprepare(snandc->qspi->iomacro_clk); +err_dis_iom_clk: + clk_disable_unprepare(snandc->aon_clk); +err_dis_aon_clk: + clk_disable_unprepare(snandc->core_clk); +err_dis_core_clk: + dma_unmap_resource(dev, res->start, resource_size(res), + DMA_BIDIRECTIONAL, 0); + return ret; +} + +static void qcom_spi_remove(struct platform_device *pdev) +{ + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + spi_unregister_controller(ctlr); + + qcom_nandc_unalloc(snandc); + + clk_disable_unprepare(snandc->aon_clk); + clk_disable_unprepare(snandc->core_clk); + clk_disable_unprepare(snandc->qspi->iomacro_clk); + + dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res), + DMA_BIDIRECTIONAL, 0); +} + +static const struct qcom_nandc_props ipq9574_snandc_props = { + .dev_cmd_reg_start = 0x7000, + .supports_bam = true, +}; + +static const struct of_device_id qcom_snandc_of_match[] = { + { + .compatible = "qcom,ipq9574-snand", + .data = &ipq9574_snandc_props, + }, + {} +} +MODULE_DEVICE_TABLE(of, qcom_snandc_of_match); + +static struct platform_driver qcom_spi_driver = { + .driver = { + .name = "qcom_snand", + .of_match_table = qcom_snandc_of_match, + }, + .probe = qcom_spi_probe, + .remove_new = qcom_spi_remove, +}; +module_platform_driver(qcom_spi_driver); + +MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores"); +MODULE_AUTHOR("Md Sadre Alam "); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h index 4d9b736ff8b7..7760154de581 100644 --- a/include/linux/mtd/nand-qpic-common.h +++ b/include/linux/mtd/nand-qpic-common.h @@ -325,6 +325,10 @@ struct nandc_regs { __le32 read_location_last1; __le32 read_location_last2; __le32 read_location_last3; + __le32 spi_cfg; + __le32 num_addr_cycle; + __le32 busy_wait_cnt; + __le32 flash_feature; __le32 erased_cw_detect_cfg_clr; __le32 erased_cw_detect_cfg_set; @@ -339,6 +343,7 @@ struct nandc_regs { * * @core_clk: controller clock * @aon_clk: another controller clock + * @iomacro_clk: io macro clock * * @regs: a contiguous chunk of memory for DMA register * writes. contains the register values to be @@ -348,6 +353,7 @@ struct nandc_regs { * initialized via DT match data * * @controller: base controller structure + * @qspi: qpic spi structure * @host_list: list containing all the chips attached to the * controller * @@ -392,6 +398,7 @@ struct qcom_nand_controller { const struct qcom_nandc_props *props; struct nand_controller *controller; + struct qpic_spi_nand *qspi; struct list_head host_list; union { -- 2.51.0 From 5f4a73da9c92fc7c87503e7865997fb54a39783c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 6 Mar 2025 12:40:01 +0300 Subject: [PATCH 017/517] spi: spi-qpic-snand: Fix ECC_CFG_ECC_DISABLE shift in qcom_spi_read_last_cw() The ECC_CFG_ECC_DISABLE define is BIT(0). It's supposed to be used directly instead of used as a shifter. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/2f4b0a0b-2c03-41c0-8a4a-3d789a83832d@stanley.mountain Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 1a4746d0fd62..d7a43ed5e304 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -514,7 +514,7 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc, cfg0 = (ecc_cfg->cfg0_raw & ~(7U << CW_PER_PAGE)) | 0 << CW_PER_PAGE; cfg1 = ecc_cfg->cfg1_raw; - ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE; + ecc_bch_cfg = ECC_CFG_ECC_DISABLE; snandc->regs->cmd = snandc->qspi->cmd; snandc->regs->cfg0 = cpu_to_le32(cfg0); -- 2.51.0 From 619c0af9a03bdca0c0346277ba75b1d42c4d6f04 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 13 Mar 2025 19:31:21 +0100 Subject: [PATCH 018/517] spi: spi-qpic-snand: avoid memleak in qcom_spi_ecc_init_ctx_pipelined() When the allocation of the OOB buffer fails, the qcom_spi_ecc_init_ctx_pipelined() function returns without freeing the memory allocated for 'ecc_cfg' thus it can cause a memory leak. Call kfree() to free 'ecc_cfg' before returning from the function to avoid that. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20250313-qpic-snand-memleak-fix-v1-1-e54e78d1da3a@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index d7a43ed5e304..3b8020f37f97 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -263,8 +263,10 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) return -ENOMEM; snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); - if (!snandc->qspi->oob_buf) + if (!snandc->qspi->oob_buf) { + kfree(ecc_cfg); return -ENOMEM; + } memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); -- 2.51.0 From 420047e7ae6f00cf8aa3e6d37b679f63390f586b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 26 Mar 2025 15:22:19 +0100 Subject: [PATCH 019/517] spi: SPI_QPIC_SNAND should be tristate and depend on MTD SPI_QPIC_SNAND is the only driver that selects MTD instead of depending on it, which could lead to circular dependencies. Moreover, as SPI_QPIC_SNAND is bool, this forces MTD (and various related symbols) to be built-in, as can be seen in an allmodconfig kernel. Except for a missing semicolon, there is no reason why SPI_QPIC_SNAND cannot be tristate; all MODULE_*() boilerplate is already present. Hence make SPI_QPIC_SNAND tristate, let it depend on MTD, and add the missing semicolon. Fixes: 7304d1909080ef0c ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/b63db431cbf35223a4400e44c296293d32c4543c.1742998909.git.geert+renesas@glider.be Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 4 ++-- drivers/spi/spi-qpic-snand.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 98c5fa460fb1..712cf74a73d9 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -899,9 +899,9 @@ config SPI_QCOM_QSPI QSPI(Quad SPI) driver for Qualcomm QSPI controller. config SPI_QPIC_SNAND - bool "QPIC SNAND controller" + tristate "QPIC SNAND controller" depends on ARCH_QCOM || COMPILE_TEST - select MTD + depends on MTD help QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller. QPIC controller supports both parallel nand and serial nand. diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 3b8020f37f97..10ce98bcacef 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1614,7 +1614,7 @@ static const struct of_device_id qcom_snandc_of_match[] = { .data = &ipq9574_snandc_props, }, {} -} +}; MODULE_DEVICE_TABLE(of, qcom_snandc_of_match); static struct platform_driver qcom_spi_driver = { -- 2.51.0 From 4c2cc0b314a1f1635b9e563add9ef8b5f99fd4f3 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 23 Apr 2025 21:31:57 +0200 Subject: [PATCH 020/517] spi: spi-qpic-snand: propagate errors from qcom_spi_block_erase() The qcom_spi_block_erase() function returns with error in case of failure. Change the qcom_spi_send_cmdaddr() function to propagate these errors to the callers instead of returning with success. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Reviewed-by: Abel Vesa Reviewed-by: Md Sadre Alam --- drivers/spi/spi-qpic-snand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 10ce98bcacef..4f08cd0e41cc 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -1307,8 +1307,7 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc, snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16); snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg); snandc->qspi->cmd = cpu_to_le32(cmd); - qcom_spi_block_erase(snandc); - return 0; + return qcom_spi_block_erase(snandc); default: break; } -- 2.51.0 From 3a06d824412d2e8082d82f9f527b7b805e849a33 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 28 Apr 2025 09:30:55 +0200 Subject: [PATCH 021/517] spi: spi-qpic-snand: fix NAND_READ_LOCATION_2 register handling The precomputed value for the NAND_READ_LOCATION_2 register should be stored in 'snandc->regs->read_location2'. Fix the qcom_spi_set_read_loc_first() function accordingly. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos Reviewed-by: Md Sadre Alam --- drivers/spi/spi-qpic-snand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 4f08cd0e41cc..f01f9517c15d 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -142,7 +142,7 @@ static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc, else if (reg == NAND_READ_LOCATION_1) snandc->regs->read_location1 = locreg_val; else if (reg == NAND_READ_LOCATION_2) - snandc->regs->read_location1 = locreg_val; + snandc->regs->read_location2 = locreg_val; else if (reg == NAND_READ_LOCATION_3) snandc->regs->read_location3 = locreg_val; } -- 2.51.0 From 4de9243c76e9bb34f53b9804e1fe7479084a896d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 20 Mar 2025 19:11:59 +0100 Subject: [PATCH 022/517] spi: spi-qpic-snand: use kmalloc() for OOB buffer allocation The qcom_spi_ecc_init_ctx_pipelined() function allocates zeroed memory for the OOB buffer, then it fills the buffer with '0xff' bytes right after the allocation. In this case zeroing the memory during allocation is superfluous, so use kmalloc() instead of kzalloc() to avoid that. Signed-off-by: Gabor Juhos Link: https://patch.msgid.link/20250320-qpic-snand-kmalloc-v1-1-94e267550675@gmail.com Signed-off-by: Mark Brown --- drivers/spi/spi-qpic-snand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index f01f9517c15d..b03ab39727da 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -261,7 +261,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); if (!ecc_cfg) return -ENOMEM; - snandc->qspi->oob_buf = kzalloc(mtd->writesize + mtd->oobsize, + snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!snandc->qspi->oob_buf) { kfree(ecc_cfg); -- 2.51.0 From c07685fe8817b098d96bf963114d077fb44574da Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 24 Apr 2025 20:10:59 +0200 Subject: [PATCH 023/517] spi: spi-qpic-snand: remove unused 'wlen' member of 'struct qpic_spi_nand' The 'wlen' member of the qpic_spi_nand structure is never used in the code so remove that. Signed-off-by: Gabor Juhos --- drivers/spi/spi-qpic-snand.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index b03ab39727da..98d32d269d55 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -116,7 +116,6 @@ struct qpic_spi_nand { struct nand_ecc_engine ecc_eng; u8 *data_buf; u8 *oob_buf; - u32 wlen; __le32 addr1; __le32 addr2; __le32 cmd; -- 2.51.0 From 992315f651da18bc66f4c200cdfcb5f54ed9acd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 14 May 2025 08:14:54 +0200 Subject: [PATCH 024/517] mtd: rawnand: brcmnand: remove unused parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit last_cmd and last_byte are now unused brcmnand_host members. last_addr is only written and never read so we can remove it too. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Florian Fainelli Reviewed-by: William Zhang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 2eb44c1428fb..3bea54fe5a73 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -310,9 +310,6 @@ struct brcmnand_host { struct platform_device *pdev; int cs; - unsigned int last_cmd; - unsigned int last_byte; - u64 last_addr; struct brcmnand_cfg hwcfg; struct brcmnand_controller *ctrl; }; @@ -2233,14 +2230,11 @@ static int brcmnand_read_page(struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); - struct brcmnand_host *host = nand_get_controller_data(chip); u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL; u64 addr = (u64)page << chip->page_shift; - host->last_addr = addr; - - return brcmnand_read(mtd, chip, host->last_addr, - mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); + return brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, + (u32 *)buf, oob); } static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, @@ -2252,11 +2246,9 @@ static int brcmnand_read_page_raw(struct nand_chip *chip, uint8_t *buf, int ret; u64 addr = (u64)page << chip->page_shift; - host->last_addr = addr; - brcmnand_set_ecc_enabled(host, 0); - ret = brcmnand_read(mtd, chip, host->last_addr, - mtd->writesize >> FC_SHIFT, (u32 *)buf, oob); + ret = brcmnand_read(mtd, chip, addr, mtd->writesize >> FC_SHIFT, + (u32 *)buf, oob); brcmnand_set_ecc_enabled(host, 1); return ret; } @@ -2363,13 +2355,10 @@ static int brcmnand_write_page(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) { struct mtd_info *mtd = nand_to_mtd(chip); - struct brcmnand_host *host = nand_get_controller_data(chip); void *oob = oob_required ? chip->oob_poi : NULL; u64 addr = (u64)page << chip->page_shift; - host->last_addr = addr; - - return brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); + return brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); } static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, @@ -2381,9 +2370,8 @@ static int brcmnand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, u64 addr = (u64)page << chip->page_shift; int ret = 0; - host->last_addr = addr; brcmnand_set_ecc_enabled(host, 0); - ret = brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob); + ret = brcmnand_write(mtd, chip, addr, (const u32 *)buf, oob); brcmnand_set_ecc_enabled(host, 1); return ret; -- 2.51.0 From c59673659b207ba134af6ede988607ee22aa3f57 Mon Sep 17 00:00:00 2001 From: David Regan Date: Thu, 22 May 2025 10:25:17 -0700 Subject: [PATCH 025/517] mtd: nand: brcmnand: fix NAND timeout when accessing eMMC When booting a board to NAND and accessing NAND while eMMC transactions are occurring the NAND will sometimes timeout. This is due to both NAND and eMMC controller sharing the same data bus on BCMBCA chips. Fix is to extend NAND timeout to allow eMMC transactions time to complete. Signed-off-by: David Regan Reviewed-by: William Zhang Reviewed-by: Florian Fainelli Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 3bea54fe5a73..7593b88f7c99 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -101,7 +101,7 @@ struct brcm_nand_dma_desc { #define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024) #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) -#define NAND_POLL_STATUS_TIMEOUT_MS 100 +#define NAND_POLL_STATUS_TIMEOUT_MS 500 #define EDU_CMD_WRITE 0x00 #define EDU_CMD_READ 0x01 -- 2.51.0 From bdbbf888ee66c9275304629c89a7f57d977d1074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Wed, 21 May 2025 10:03:25 +0200 Subject: [PATCH 026/517] mtd: rawnand: brcmnand: legacy exec_op implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") removed legacy interface functions, breaking < v5.0 controllers support. In order to fix older controllers we need to add an alternative exec_op implementation which doesn't rely on low level registers. Fixes: 3c8260ce7663 ("mtd: rawnand: brcmnand: exec_op implementation") Signed-off-by: Álvaro Fernández Rojas Reviewed-by: David Regan Reviewed-by: Florian Fainelli Reviewed-by: William Zhang Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 222 ++++++++++++++++++++++- 1 file changed, 215 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 7593b88f7c99..59568c430315 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -65,6 +65,7 @@ module_param(wp_on, int, 0444); #define CMD_PARAMETER_READ 0x0e #define CMD_PARAMETER_CHANGE_COL 0x0f #define CMD_LOW_LEVEL_OP 0x10 +#define CMD_NOT_SUPPORTED 0xff struct brcm_nand_dma_desc { u32 next_desc; @@ -199,6 +200,30 @@ static const u16 flash_dma_regs_v4[] = { [FLASH_DMA_CURRENT_DESC_EXT] = 0x34, }; +/* Native command conversion for legacy controllers (< v5.0) */ +static const u8 native_cmd_conv[] = { + [NAND_CMD_READ0] = CMD_NOT_SUPPORTED, + [NAND_CMD_READ1] = CMD_NOT_SUPPORTED, + [NAND_CMD_RNDOUT] = CMD_PARAMETER_CHANGE_COL, + [NAND_CMD_PAGEPROG] = CMD_NOT_SUPPORTED, + [NAND_CMD_READOOB] = CMD_NOT_SUPPORTED, + [NAND_CMD_ERASE1] = CMD_BLOCK_ERASE, + [NAND_CMD_STATUS] = CMD_NOT_SUPPORTED, + [NAND_CMD_SEQIN] = CMD_NOT_SUPPORTED, + [NAND_CMD_RNDIN] = CMD_NOT_SUPPORTED, + [NAND_CMD_READID] = CMD_DEVICE_ID_READ, + [NAND_CMD_ERASE2] = CMD_NULL, + [NAND_CMD_PARAM] = CMD_PARAMETER_READ, + [NAND_CMD_GET_FEATURES] = CMD_NOT_SUPPORTED, + [NAND_CMD_SET_FEATURES] = CMD_NOT_SUPPORTED, + [NAND_CMD_RESET] = CMD_NOT_SUPPORTED, + [NAND_CMD_READSTART] = CMD_NOT_SUPPORTED, + [NAND_CMD_READCACHESEQ] = CMD_NOT_SUPPORTED, + [NAND_CMD_READCACHEEND] = CMD_NOT_SUPPORTED, + [NAND_CMD_RNDOUTSTART] = CMD_NULL, + [NAND_CMD_CACHEDPROG] = CMD_NOT_SUPPORTED, +}; + /* Controller feature flags */ enum { BRCMNAND_HAS_1K_SECTORS = BIT(0), @@ -237,6 +262,12 @@ struct brcmnand_controller { /* List of NAND hosts (one for each chip-select) */ struct list_head host_list; + /* Functions to be called from exec_op */ + int (*check_instr)(struct nand_chip *chip, + const struct nand_operation *op); + int (*exec_instr)(struct nand_chip *chip, + const struct nand_operation *op); + /* EDU info, per-transaction */ const u16 *edu_offsets; void __iomem *edu_base; @@ -2478,18 +2509,190 @@ static int brcmnand_op_is_reset(const struct nand_operation *op) return 0; } +static int brcmnand_check_instructions(struct nand_chip *chip, + const struct nand_operation *op) +{ + return 0; +} + +static int brcmnand_exec_instructions(struct nand_chip *chip, + const struct nand_operation *op) +{ + struct brcmnand_host *host = nand_get_controller_data(chip); + unsigned int i; + int ret = 0; + + for (i = 0; i < op->ninstrs; i++) { + ret = brcmnand_exec_instr(host, i, op); + if (ret) + break; + } + + return ret; +} + +static int brcmnand_check_instructions_legacy(struct nand_chip *chip, + const struct nand_operation *op) +{ + const struct nand_op_instr *instr; + unsigned int i; + u8 cmd; + + for (i = 0; i < op->ninstrs; i++) { + instr = &op->instrs[i]; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + cmd = native_cmd_conv[instr->ctx.cmd.opcode]; + if (cmd == CMD_NOT_SUPPORTED) + return -EOPNOTSUPP; + break; + case NAND_OP_ADDR_INSTR: + case NAND_OP_DATA_IN_INSTR: + case NAND_OP_WAITRDY_INSTR: + break; + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int brcmnand_exec_instructions_legacy(struct nand_chip *chip, + const struct nand_operation *op) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; + const struct nand_op_instr *instr; + unsigned int i, j; + u8 cmd = CMD_NULL, last_cmd = CMD_NULL; + int ret = 0; + u64 last_addr; + + for (i = 0; i < op->ninstrs; i++) { + instr = &op->instrs[i]; + + if (instr->type == NAND_OP_CMD_INSTR) { + cmd = native_cmd_conv[instr->ctx.cmd.opcode]; + if (cmd == CMD_NOT_SUPPORTED) { + dev_err(ctrl->dev, "unsupported cmd=%d\n", + instr->ctx.cmd.opcode); + ret = -EOPNOTSUPP; + break; + } + } else if (instr->type == NAND_OP_ADDR_INSTR) { + u64 addr = 0; + + if (cmd == CMD_NULL) + continue; + + if (instr->ctx.addr.naddrs > 8) { + dev_err(ctrl->dev, "unsupported naddrs=%u\n", + instr->ctx.addr.naddrs); + ret = -EOPNOTSUPP; + break; + } + + for (j = 0; j < instr->ctx.addr.naddrs; j++) + addr |= (instr->ctx.addr.addrs[j]) << (j << 3); + + if (cmd == CMD_BLOCK_ERASE) + addr <<= chip->page_shift; + else if (cmd == CMD_PARAMETER_CHANGE_COL) + addr &= ~((u64)(FC_BYTES - 1)); + + brcmnand_set_cmd_addr(mtd, addr); + brcmnand_send_cmd(host, cmd); + last_addr = addr; + last_cmd = cmd; + cmd = CMD_NULL; + brcmnand_waitfunc(chip); + + if (last_cmd == CMD_PARAMETER_READ || + last_cmd == CMD_PARAMETER_CHANGE_COL) { + /* Copy flash cache word-wise */ + u32 *flash_cache = (u32 *)ctrl->flash_cache; + + brcmnand_soc_data_bus_prepare(ctrl->soc, true); + + /* + * Must cache the FLASH_CACHE now, since changes in + * SECTOR_SIZE_1K may invalidate it + */ + for (j = 0; j < FC_WORDS; j++) + /* + * Flash cache is big endian for parameter pages, at + * least on STB SoCs + */ + flash_cache[j] = be32_to_cpu(brcmnand_read_fc(ctrl, j)); + + brcmnand_soc_data_bus_unprepare(ctrl->soc, true); + } + } else if (instr->type == NAND_OP_DATA_IN_INSTR) { + u8 *in = instr->ctx.data.buf.in; + + if (last_cmd == CMD_DEVICE_ID_READ) { + u32 val; + + if (instr->ctx.data.len > 8) { + dev_err(ctrl->dev, "unsupported len=%u\n", + instr->ctx.data.len); + ret = -EOPNOTSUPP; + break; + } + + for (j = 0; j < instr->ctx.data.len; j++) { + if (j == 0) + val = brcmnand_read_reg(ctrl, BRCMNAND_ID); + else if (j == 4) + val = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT); + + in[j] = (val >> (24 - ((j % 4) << 3))) & 0xff; + } + } else if (last_cmd == CMD_PARAMETER_READ || + last_cmd == CMD_PARAMETER_CHANGE_COL) { + u64 addr; + u32 offs; + + for (j = 0; j < instr->ctx.data.len; j++) { + addr = last_addr + j; + offs = addr & (FC_BYTES - 1); + + if (j > 0 && offs == 0) + nand_change_read_column_op(chip, addr, NULL, 0, + false); + + in[j] = ctrl->flash_cache[offs]; + } + } + } else if (instr->type == NAND_OP_WAITRDY_INSTR) { + ret = bcmnand_ctrl_poll_status(host, NAND_CTRL_RDY, NAND_CTRL_RDY, 0); + if (ret) + break; + } else { + dev_err(ctrl->dev, "unsupported instruction type: %d\n", instr->type); + ret = -EOPNOTSUPP; + break; + } + } + + return ret; +} + static int brcmnand_exec_op(struct nand_chip *chip, const struct nand_operation *op, bool check_only) { struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; struct mtd_info *mtd = nand_to_mtd(chip); u8 *status; - unsigned int i; int ret = 0; if (check_only) - return 0; + return ctrl->check_instr(chip, op); if (brcmnand_op_is_status(op)) { status = op->instrs[1].ctx.data.buf.in; @@ -2513,11 +2716,7 @@ static int brcmnand_exec_op(struct nand_chip *chip, if (op->deassert_wp) brcmnand_wp(mtd, 0); - for (i = 0; i < op->ninstrs; i++) { - ret = brcmnand_exec_instr(host, i, op); - if (ret) - break; - } + ret = ctrl->exec_instr(chip, op); if (op->deassert_wp) brcmnand_wp(mtd, 1); @@ -3130,6 +3329,15 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc) if (ret) goto err; + /* Only v5.0+ controllers have low level ops support */ + if (ctrl->nand_version >= 0x0500) { + ctrl->check_instr = brcmnand_check_instructions; + ctrl->exec_instr = brcmnand_exec_instructions; + } else { + ctrl->check_instr = brcmnand_check_instructions_legacy; + ctrl->exec_instr = brcmnand_exec_instructions_legacy; + } + /* * Most chips have this cache at a fixed offset within 'nand' block. * Some must specify this region separately. -- 2.51.0 From 498ecabf18426e22786a167b9f59652ff36cdb26 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 3 Oct 2024 00:11:41 +0200 Subject: [PATCH 027/517] block: add support for defining read-only partitions Add support for defining read-only partitions and complete support for it in the cmdline partition parser as the additional "ro" after a partition is scanned but never actually applied. Signed-off-by: Christian Marangi Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20241002221306.4403-2-ansuelsmth@gmail.com Signed-off-by: Jens Axboe --- block/blk.h | 1 + block/partitions/cmdline.c | 3 +++ block/partitions/core.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/block/blk.h b/block/blk.h index e91012247ff2..a8ac9c6dbb85 100644 --- a/block/blk.h +++ b/block/blk.h @@ -556,6 +556,7 @@ void blk_free_ext_minor(unsigned int minor); #define ADDPART_FLAG_NONE 0 #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 +#define ADDPART_FLAG_READONLY 4 int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, sector_t length); int bdev_del_partition(struct gendisk *disk, int partno); diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c index 152c85df92b2..da3e719d8e51 100644 --- a/block/partitions/cmdline.c +++ b/block/partitions/cmdline.c @@ -237,6 +237,9 @@ static int add_part(int slot, struct cmdline_subpart *subpart, put_partition(state, slot, subpart->from >> 9, subpart->size >> 9); + if (subpart->flags & PF_RDONLY) + state->parts[slot].flags |= ADDPART_FLAG_READONLY; + info = &state->parts[slot].info; strscpy(info->volname, subpart->name, sizeof(info->volname)); diff --git a/block/partitions/core.c b/block/partitions/core.c index 5bd7a603092e..629ed08b9ab9 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -373,6 +373,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, goto out_del; } + if (flags & ADDPART_FLAG_READONLY) + bdev_set_flag(bdev, BD_READ_ONLY); + /* everything is up and running, commence */ err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL); if (err) -- 2.51.0 From b9b466eecefdedee1240f5f182b4083a0cd8627b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 3 Oct 2024 00:11:43 +0200 Subject: [PATCH 028/517] block: introduce add_disk_fwnode() Introduce add_disk_fwnode() as a replacement of device_add_disk() that permits to pass and attach a fwnode to disk dev. This variant can be useful for eMMC that might have the partition table for the disk defined in DT. A parser can later make use of the attached fwnode to parse the related table and init the hardcoded partition for the disk. device_add_disk() is converted to a simple wrapper of add_disk_fwnode() with the fwnode entry set as NULL. Signed-off-by: Christian Marangi Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20241002221306.4403-4-ansuelsmth@gmail.com Signed-off-by: Jens Axboe --- block/genhd.c | 28 ++++++++++++++++++++++++---- include/linux/blkdev.h | 3 +++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 99344f53c789..342a92f1391e 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode) } /** - * device_add_disk - add disk information to kernel list + * add_disk_fwnode - add disk information to kernel list with fwnode * @parent: parent device for the disk * @disk: per-device partitioning information * @groups: Additional per-device sysfs groups + * @fwnode: attached disk fwnode * * This function registers the partitioning information in @disk - * with the kernel. + * with the kernel. Also attach a fwnode to the disk device. */ -int __must_check device_add_disk(struct device *parent, struct gendisk *disk, - const struct attribute_group **groups) +int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups, + struct fwnode_handle *fwnode) { struct device *ddev = disk_to_dev(disk); @@ -452,6 +454,8 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, ddev->parent = parent; ddev->groups = groups; dev_set_name(ddev, "%s", disk->disk_name); + if (fwnode) + device_set_node(ddev, fwnode); if (!(disk->flags & GENHD_FL_HIDDEN)) ddev->devt = MKDEV(disk->major, disk->first_minor); ret = device_add(ddev); @@ -553,6 +557,22 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, elevator_exit(disk->queue); return ret; } +EXPORT_SYMBOL_GPL(add_disk_fwnode); + +/** + * device_add_disk - add disk information to kernel list + * @parent: parent device for the disk + * @disk: per-device partitioning information + * @groups: Additional per-device sysfs groups + * + * This function registers the partitioning information in @disk + * with the kernel. + */ +int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups) +{ + return add_disk_fwnode(parent, disk, groups, NULL); +} EXPORT_SYMBOL(device_add_disk); static void blk_report_disk_dead(struct gendisk *disk, bool surprise) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cd9c97f6f948..fa9d324b7069 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -789,6 +789,9 @@ static inline unsigned int blk_queue_depth(struct request_queue *q) #define for_each_bio(_bio) \ for (; _bio; _bio = _bio->bi_next) +int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups, + struct fwnode_handle *fwnode); int __must_check device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups); static inline int __must_check add_disk(struct gendisk *disk) -- 2.51.0 From 3272770722c2740510bba41e7d07d4ccda7b7439 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 3 Oct 2024 00:11:44 +0200 Subject: [PATCH 029/517] mmc: block: attach partitions fwnode if found in mmc-card Attach partitions fwnode if found in mmc-card and register disk with it. This permits block partition to reference the node and register a partition table defined in DT for the special case for embedded device that doesn't have a partition table flashed but have an hardcoded partition table passed from the system. JEDEC BOOT partition boot0/boot1 are supported but in DT we refer with the JEDEC name of boot1 and boot2 to better adhere to documentation. Also JEDEC GP partition gp0/1/2/3 are supported but in DT we refer with the JEDEC name of gp1/2/3/4 to better adhere to documentration. Signed-off-by: Christian Marangi Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20241002221306.4403-5-ansuelsmth@gmail.com Signed-off-by: Jens Axboe --- drivers/mmc/core/block.c | 55 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 08b8276e1da9..28882b75ba26 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2517,6 +2517,56 @@ static inline int mmc_blk_readonly(struct mmc_card *card) !(card->csd.cmdclass & CCC_BLOCK_WRITE); } +/* + * Search for a declared partitions node for the disk in mmc-card related node. + * + * This is to permit support for partition table defined in DT in special case + * where a partition table is not written in the disk and is expected to be + * passed from the running system. + * + * For the user disk, "partitions" node is searched. + * For the special HW disk, "partitions-" node with the appended name is used + * following this conversion table (to adhere to JEDEC naming) + * - boot0 -> partitions-boot1 + * - boot1 -> partitions-boot2 + * - gp0 -> partitions-gp1 + * - gp1 -> partitions-gp2 + * - gp2 -> partitions-gp3 + * - gp3 -> partitions-gp4 + */ +static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev, + const char *subname) +{ + const char *node_name = "partitions"; + + if (subname) { + mmc_dev = mmc_dev->parent; + + /* + * Check if we are allocating a BOOT disk boot0/1 disk. + * In DT we use the JEDEC naming boot1/2. + */ + if (!strcmp(subname, "boot0")) + node_name = "partitions-boot1"; + if (!strcmp(subname, "boot1")) + node_name = "partitions-boot2"; + /* + * Check if we are allocating a GP disk gp0/1/2/3 disk. + * In DT we use the JEDEC naming gp1/2/3/4. + */ + if (!strcmp(subname, "gp0")) + node_name = "partitions-gp1"; + if (!strcmp(subname, "gp1")) + node_name = "partitions-gp2"; + if (!strcmp(subname, "gp2")) + node_name = "partitions-gp3"; + if (!strcmp(subname, "gp3")) + node_name = "partitions-gp4"; + } + + return device_get_named_child_node(mmc_dev, node_name); +} + static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, @@ -2525,6 +2575,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, int area_type, unsigned int part_type) { + struct fwnode_handle *disk_fwnode; struct mmc_blk_data *md; int devidx, ret; char cap_str[10]; @@ -2626,7 +2677,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, /* used in ->open, must be set before add_disk: */ if (area_type == MMC_BLK_DATA_AREA_MAIN) dev_set_drvdata(&card->dev, md); - ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); + disk_fwnode = mmc_blk_get_partitions_node(parent, subname); + ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups, + disk_fwnode); if (ret) goto err_put_disk; return md; -- 2.51.0 From 230f71eab625c48464071341ff4c0170831bce2c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 3 Oct 2024 00:11:45 +0200 Subject: [PATCH 030/517] block: add support for partition table defined in OF Add support for partition table defined in Device Tree. Similar to how it's done with MTD, add support for defining a fixed partition table in device tree. A common scenario for this is fixed block (eMMC) embedded devices that have no MBR or GPT partition table to save storage space. Bootloader access the block device with absolute address of data. This is to complete the functionality with an equivalent implementation with providing partition table with bootargs, for case where the booargs can't be modified and tweaking the Device Tree is the only solution to have an usabe partition table. The implementation follow the fixed-partitions parser used on MTD devices where a "partitions" node is expected to be declared with "fixed-partitions" compatible in the OF node of the disk device (mmc-card for eMMC for example) and each child node declare a label and a reg with offset and size. If label is not declared, the node name is used as fallback. Eventually is also possible to declare the read-only property to flag the partition as read-only. Signed-off-by: Christian Marangi Reviewed-by: Christoph Hellwig Link: https://lore.kernel.org/r/20241002221306.4403-6-ansuelsmth@gmail.com Signed-off-by: Jens Axboe --- block/partitions/Kconfig | 9 ++++ block/partitions/Makefile | 1 + block/partitions/check.h | 1 + block/partitions/core.c | 3 ++ block/partitions/of.c | 110 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 block/partitions/of.c diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig index 7aff4eb81c60..ce17e41451af 100644 --- a/block/partitions/Kconfig +++ b/block/partitions/Kconfig @@ -270,4 +270,13 @@ config CMDLINE_PARTITION Say Y here if you want to read the partition table from bootargs. The format for the command line is just like mtdparts. +config OF_PARTITION + bool "Device Tree partition support" if PARTITION_ADVANCED + depends on OF + help + Say Y here if you want to enable support for partition table + defined in Device Tree. (mainly for eMMC) + The format for the device tree node is just like MTD fixed-partition + schema. + endmenu diff --git a/block/partitions/Makefile b/block/partitions/Makefile index a7f05cdb02a8..25d424922c6e 100644 --- a/block/partitions/Makefile +++ b/block/partitions/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o obj-$(CONFIG_MAC_PARTITION) += mac.o obj-$(CONFIG_LDM_PARTITION) += ldm.o obj-$(CONFIG_MSDOS_PARTITION) += msdos.o +obj-$(CONFIG_OF_PARTITION) += of.o obj-$(CONFIG_OSF_PARTITION) += osf.o obj-$(CONFIG_SGI_PARTITION) += sgi.o obj-$(CONFIG_SUN_PARTITION) += sun.o diff --git a/block/partitions/check.h b/block/partitions/check.h index 8d70a880c372..e5c1c61eb353 100644 --- a/block/partitions/check.h +++ b/block/partitions/check.h @@ -62,6 +62,7 @@ int karma_partition(struct parsed_partitions *state); int ldm_partition(struct parsed_partitions *state); int mac_partition(struct parsed_partitions *state); int msdos_partition(struct parsed_partitions *state); +int of_partition(struct parsed_partitions *state); int osf_partition(struct parsed_partitions *state); int sgi_partition(struct parsed_partitions *state); int sun_partition(struct parsed_partitions *state); diff --git a/block/partitions/core.c b/block/partitions/core.c index 629ed08b9ab9..cdad05f97647 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -43,6 +43,9 @@ static int (*const check_part[])(struct parsed_partitions *) = { #ifdef CONFIG_CMDLINE_PARTITION cmdline_partition, #endif +#ifdef CONFIG_OF_PARTITION + of_partition, /* cmdline have priority to OF */ +#endif #ifdef CONFIG_EFI_PARTITION efi_partition, /* this must come before msdos */ #endif diff --git a/block/partitions/of.c b/block/partitions/of.c new file mode 100644 index 000000000000..4e760fdffb3f --- /dev/null +++ b/block/partitions/of.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include "check.h" + +static int validate_of_partition(struct device_node *np, int slot) +{ + u64 offset, size; + int len; + + const __be32 *reg = of_get_property(np, "reg", &len); + int a_cells = of_n_addr_cells(np); + int s_cells = of_n_size_cells(np); + + /* Make sure reg len match the expected addr and size cells */ + if (len / sizeof(*reg) != a_cells + s_cells) + return -EINVAL; + + /* Validate offset conversion from bytes to sectors */ + offset = of_read_number(reg, a_cells); + if (offset % SECTOR_SIZE) + return -EINVAL; + + /* Validate size conversion from bytes to sectors */ + size = of_read_number(reg + a_cells, s_cells); + if (!size || size % SECTOR_SIZE) + return -EINVAL; + + return 0; +} + +static void add_of_partition(struct parsed_partitions *state, int slot, + struct device_node *np) +{ + struct partition_meta_info *info; + char tmp[sizeof(info->volname) + 4]; + const char *partname; + int len; + + const __be32 *reg = of_get_property(np, "reg", &len); + int a_cells = of_n_addr_cells(np); + int s_cells = of_n_size_cells(np); + + /* Convert bytes to sector size */ + u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE; + u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE; + + put_partition(state, slot, offset, size); + + if (of_property_read_bool(np, "read-only")) + state->parts[slot].flags |= ADDPART_FLAG_READONLY; + + /* + * Follow MTD label logic, search for label property, + * fallback to node name if not found. + */ + info = &state->parts[slot].info; + partname = of_get_property(np, "label", &len); + if (!partname) + partname = of_get_property(np, "name", &len); + strscpy(info->volname, partname, sizeof(info->volname)); + + snprintf(tmp, sizeof(tmp), "(%s)", info->volname); + strlcat(state->pp_buf, tmp, PAGE_SIZE); +} + +int of_partition(struct parsed_partitions *state) +{ + struct device *ddev = disk_to_dev(state->disk); + struct device_node *np; + int slot; + + struct device_node *partitions_np = of_node_get(ddev->of_node); + + if (!partitions_np || + !of_device_is_compatible(partitions_np, "fixed-partitions")) + return 0; + + slot = 1; + /* Validate parition offset and size */ + for_each_child_of_node(partitions_np, np) { + if (validate_of_partition(np, slot)) { + of_node_put(np); + of_node_put(partitions_np); + + return -1; + } + + slot++; + } + + slot = 1; + for_each_child_of_node(partitions_np, np) { + if (slot >= state->limit) { + of_node_put(np); + break; + } + + add_of_partition(state, slot, np); + + slot++; + } + + strlcat(state->pp_buf, "\n", PAGE_SIZE); + + return 1; +} -- 2.51.0 From 564834bbaef7bec34bc5c34c25ad2f5a509c23f9 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 8 Nov 2024 16:01:44 +0000 Subject: [PATCH 031/517] net: phylink: move manual flow control setting Move the handling of manual flow control configuration to a common location during resolve. We currently evaluate this for all but fixed links. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1t9RQe-002Feh-T1@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index b78dfcbec936..8fc59aba1ded 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1484,7 +1484,6 @@ static void phylink_resolve(struct work_struct *w) switch (pl->cur_link_an_mode) { case MLO_AN_PHY: link_state = pl->phy_state; - phylink_apply_manual_flow(pl, &link_state); mac_config = link_state.link; break; @@ -1545,11 +1544,13 @@ static void phylink_resolve(struct work_struct *w) link_state.pause = pl->phy_state.pause; mac_config = true; } - phylink_apply_manual_flow(pl, &link_state); break; } } + if (pl->cur_link_an_mode != MLO_AN_FIXED) + phylink_apply_manual_flow(pl, &link_state); + if (mac_config) { if (link_state.interface != pl->link_config.interface) { /* The interface has changed, force the link down and -- 2.51.0 From b2650f725996177178c95ba69b7d2fe5edd85eca Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 8 Nov 2024 16:01:50 +0000 Subject: [PATCH 032/517] net: phylink: move MLO_AN_FIXED resolve handling to if() statement The switch() statement doesn't sit very well with the preceeding if() statements, and results in excessive indentation that spoils code readability. Begin cleaning this up by converting the MLO_AN_FIXED case to an if() statement. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1t9RQk-002Fen-1A@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 8fc59aba1ded..f1d97db70f58 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1480,6 +1480,9 @@ static void phylink_resolve(struct work_struct *w) } else if (pl->link_failed) { link_state.link = false; retrigger = true; + } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { + phylink_get_fixed_state(pl, &link_state); + mac_config = link_state.link; } else { switch (pl->cur_link_an_mode) { case MLO_AN_PHY: @@ -1487,11 +1490,6 @@ static void phylink_resolve(struct work_struct *w) mac_config = link_state.link; break; - case MLO_AN_FIXED: - phylink_get_fixed_state(pl, &link_state); - mac_config = link_state.link; - break; - case MLO_AN_INBAND: phylink_mac_pcs_get_state(pl, &link_state); -- 2.51.0 From 3740814469f6222bdbaa014e71911970fb45223f Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 8 Nov 2024 16:01:55 +0000 Subject: [PATCH 033/517] net: phylink: move MLO_AN_PHY resolve handling to if() statement The switch() statement doesn't sit very well with the preceeding if() statements, and results in excessive indentation that spoils code readability. Continue cleaning this up by converting the MLO_AN_PHY case to use an if() statmeent. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1t9RQp-002Fet-5W@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f1d97db70f58..1169ffb30a31 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1483,13 +1483,11 @@ static void phylink_resolve(struct work_struct *w) } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { phylink_get_fixed_state(pl, &link_state); mac_config = link_state.link; + } else if (pl->cur_link_an_mode == MLO_AN_PHY) { + link_state = pl->phy_state; + mac_config = link_state.link; } else { switch (pl->cur_link_an_mode) { - case MLO_AN_PHY: - link_state = pl->phy_state; - mac_config = link_state.link; - break; - case MLO_AN_INBAND: phylink_mac_pcs_get_state(pl, &link_state); -- 2.51.0 From 001a54bc68e2061d58af85a76f1cb9d2908c0031 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 8 Nov 2024 16:02:00 +0000 Subject: [PATCH 034/517] net: phylink: remove switch() statement in resolve handling The switch() statement doesn't sit very well with the preceeding if() statements, so let's just convert everything to if()s. As a result of the two preceding commits, there is now only one case in the switch() statement. Remove the switch statement and reduce the code indentation. Code reformatting will be in the following commit. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1t9RQu-002Fez-AA@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 94 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1169ffb30a31..cee1f1aa11a1 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1487,60 +1487,56 @@ static void phylink_resolve(struct work_struct *w) link_state = pl->phy_state; mac_config = link_state.link; } else { - switch (pl->cur_link_an_mode) { - case MLO_AN_INBAND: - phylink_mac_pcs_get_state(pl, &link_state); - - /* The PCS may have a latching link-fail indicator. - * If the link was up, bring the link down and - * re-trigger the resolve. Otherwise, re-read the - * PCS state to get the current status of the link. + phylink_mac_pcs_get_state(pl, &link_state); + + /* The PCS may have a latching link-fail indicator. + * If the link was up, bring the link down and + * re-trigger the resolve. Otherwise, re-read the + * PCS state to get the current status of the link. + */ + if (!link_state.link) { + if (cur_link_state) + retrigger = true; + else + phylink_mac_pcs_get_state(pl, + &link_state); + } + + /* If we have a phy, the "up" state is the union of + * both the PHY and the MAC + */ + if (pl->phydev) + link_state.link &= pl->phy_state.link; + + /* Only update if the PHY link is up */ + if (pl->phydev && pl->phy_state.link) { + /* If the interface has changed, force a + * link down event if the link isn't already + * down, and re-resolve. */ - if (!link_state.link) { - if (cur_link_state) - retrigger = true; - else - phylink_mac_pcs_get_state(pl, - &link_state); + if (link_state.interface != + pl->phy_state.interface) { + retrigger = true; + link_state.link = false; } + link_state.interface = pl->phy_state.interface; - /* If we have a phy, the "up" state is the union of - * both the PHY and the MAC + /* If we are doing rate matching, then the + * link speed/duplex comes from the PHY */ - if (pl->phydev) - link_state.link &= pl->phy_state.link; - - /* Only update if the PHY link is up */ - if (pl->phydev && pl->phy_state.link) { - /* If the interface has changed, force a - * link down event if the link isn't already - * down, and re-resolve. - */ - if (link_state.interface != - pl->phy_state.interface) { - retrigger = true; - link_state.link = false; - } - link_state.interface = pl->phy_state.interface; - - /* If we are doing rate matching, then the - * link speed/duplex comes from the PHY - */ - if (pl->phy_state.rate_matching) { - link_state.rate_matching = - pl->phy_state.rate_matching; - link_state.speed = pl->phy_state.speed; - link_state.duplex = - pl->phy_state.duplex; - } - - /* If we have a PHY, we need to update with - * the PHY flow control bits. - */ - link_state.pause = pl->phy_state.pause; - mac_config = true; + if (pl->phy_state.rate_matching) { + link_state.rate_matching = + pl->phy_state.rate_matching; + link_state.speed = pl->phy_state.speed; + link_state.duplex = + pl->phy_state.duplex; } - break; + + /* If we have a PHY, we need to update with + * the PHY flow control bits. + */ + link_state.pause = pl->phy_state.pause; + mac_config = true; } } -- 2.51.0 From 921cbed2099d406e77b90ae879b77b716398851f Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 8 Nov 2024 16:02:05 +0000 Subject: [PATCH 035/517] net: phylink: clean up phylink_resolve() Now that we have reduced the indentation level, clean up the code formatting. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1t9RQz-002Ff5-EA@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index cee1f1aa11a1..e4fc28820bd5 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1489,51 +1489,48 @@ static void phylink_resolve(struct work_struct *w) } else { phylink_mac_pcs_get_state(pl, &link_state); - /* The PCS may have a latching link-fail indicator. - * If the link was up, bring the link down and - * re-trigger the resolve. Otherwise, re-read the - * PCS state to get the current status of the link. + /* The PCS may have a latching link-fail indicator. If the link + * was up, bring the link down and re-trigger the resolve. + * Otherwise, re-read the PCS state to get the current status + * of the link. */ if (!link_state.link) { if (cur_link_state) retrigger = true; else - phylink_mac_pcs_get_state(pl, - &link_state); + phylink_mac_pcs_get_state(pl, &link_state); } - /* If we have a phy, the "up" state is the union of - * both the PHY and the MAC + /* If we have a phy, the "up" state is the union of both the + * PHY and the MAC */ if (pl->phydev) link_state.link &= pl->phy_state.link; /* Only update if the PHY link is up */ if (pl->phydev && pl->phy_state.link) { - /* If the interface has changed, force a - * link down event if the link isn't already - * down, and re-resolve. + /* If the interface has changed, force a link down + * event if the link isn't already down, and re-resolve. */ - if (link_state.interface != - pl->phy_state.interface) { + if (link_state.interface != pl->phy_state.interface) { retrigger = true; link_state.link = false; } + link_state.interface = pl->phy_state.interface; - /* If we are doing rate matching, then the - * link speed/duplex comes from the PHY + /* If we are doing rate matching, then the link + * speed/duplex comes from the PHY */ if (pl->phy_state.rate_matching) { link_state.rate_matching = pl->phy_state.rate_matching; link_state.speed = pl->phy_state.speed; - link_state.duplex = - pl->phy_state.duplex; + link_state.duplex = pl->phy_state.duplex; } - /* If we have a PHY, we need to update with - * the PHY flow control bits. + /* If we have a PHY, we need to update with the PHY + * flow control bits. */ link_state.pause = pl->phy_state.pause; mac_config = true; -- 2.51.0 From 7d2cfc89b6392219e11a8f9d30313f5177a84611 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:30:47 +0000 Subject: [PATCH 036/517] net: phylink: pass phylink and pcs into phylink_pcs_neg_mode() Move the call to phylink_pcs_neg_mode() in phylink_major_config() after we have selected the appropriate PCS to allow the PCS to be passed in. Add struct phylink and struct phylink_pcs pointers to phylink_pcs_neg_mode() and pass in the appropriate structures. Set pl->pcs_neg_mode before returning, and remove the return value. This will allow the capabilities of the PCS and any PHY to be used when deciding which pcs_neg_mode should be used. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUrP-006ITh-6u@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index e4fc28820bd5..ae7e529c70e2 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1102,7 +1102,8 @@ static void phylink_pcs_an_restart(struct phylink *pl) /** * phylink_pcs_neg_mode() - helper to determine PCS inband mode - * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND. + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @pcs: a pointer to &struct phylink_pcs * @interface: interface mode to be used * @advertising: adertisement ethtool link mode mask * @@ -1119,11 +1120,13 @@ static void phylink_pcs_an_restart(struct phylink *pl) * Note: this is for cases where the PCS itself is involved in negotiation * (e.g. Clause 37, SGMII and similar) not Clause 73. */ -static unsigned int phylink_pcs_neg_mode(unsigned int mode, - phy_interface_t interface, - const unsigned long *advertising) +static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, + phy_interface_t interface, + const unsigned long *advertising) { - unsigned int neg_mode; + unsigned int neg_mode, mode; + + mode = pl->cur_link_an_mode; switch (interface) { case PHY_INTERFACE_MODE_SGMII: @@ -1164,7 +1167,7 @@ static unsigned int phylink_pcs_neg_mode(unsigned int mode, break; } - return neg_mode; + pl->pcs_neg_mode = neg_mode; } static void phylink_major_config(struct phylink *pl, bool restart, @@ -1178,10 +1181,6 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); - pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, - state->interface, - state->advertising); - if (pl->using_mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) { @@ -1194,6 +1193,8 @@ static void phylink_major_config(struct phylink *pl, bool restart, pcs_changed = pcs && pl->pcs != pcs; } + phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising); + phylink_pcs_poll_stop(pl); if (pl->mac_ops->mac_prepare) { @@ -1284,9 +1285,8 @@ static int phylink_change_inband_advert(struct phylink *pl) pl->link_config.pause); /* Recompute the PCS neg mode */ - pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, - pl->link_config.interface, - pl->link_config.advertising); + phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface, + pl->link_config.advertising); neg_mode = pl->cur_link_an_mode; if (pl->pcs->neg_mode) -- 2.51.0 From fa2a79a5315cad8983a76f23e445621b9d34cd2c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:30:52 +0000 Subject: [PATCH 037/517] net: phylink: split cur_link_an_mode into requested and active There is an interdependence between the current link_an_mode and pcs_neg_mode that some drivers rely upon to know whether inband or PHY mode will be used. In order to support detection of PCS and PHY inband capabilities resulting in automatic selection of inband or PHY mode, we need to cater for this, and support changing the MAC link_an_mode. However, we end up with an inter-dependency between the current link_an_mode and pcs_neg_mode. To solve this, split the current link_an_mode into the requested link_an_mode and active link_an_mode. The requested link_an_mode will always be passed to phylink_pcs_neg_mode(), and the active link_an_mode will be used for everything else, and only updated during phylink_major_config(). This will ensure that phylink_pcs_neg_mode()'s link_an_mode will not depend on the active link_an_mode that will, in a future patch, depend on pcs_neg_mode. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUrU-006ITn-Ai@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 60 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ae7e529c70e2..5290afd0f54e 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -56,7 +56,8 @@ struct phylink { struct phy_device *phydev; phy_interface_t link_interface; /* PHY_INTERFACE_xxx */ u8 cfg_link_an_mode; /* MLO_AN_xxx */ - u8 cur_link_an_mode; + u8 req_link_an_mode; /* Requested MLO_AN_xxx mode */ + u8 act_link_an_mode; /* Active MLO_AN_xxx mode */ u8 link_port; /* The current non-phy ethtool port */ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); @@ -1082,13 +1083,13 @@ static void phylink_mac_config(struct phylink *pl, phylink_dbg(pl, "%s: mode=%s/%s/%s adv=%*pb pause=%02x\n", - __func__, phylink_an_mode_str(pl->cur_link_an_mode), + __func__, phylink_an_mode_str(pl->act_link_an_mode), phy_modes(st.interface), phy_rate_matching_to_str(st.rate_matching), __ETHTOOL_LINK_MODE_MASK_NBITS, st.advertising, st.pause); - pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, &st); + pl->mac_ops->mac_config(pl->config, pl->act_link_an_mode, &st); } static void phylink_pcs_an_restart(struct phylink *pl) @@ -1096,7 +1097,7 @@ static void phylink_pcs_an_restart(struct phylink *pl) if (pl->pcs && linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, pl->link_config.advertising) && phy_interface_mode_is_8023z(pl->link_config.interface) && - phylink_autoneg_inband(pl->cur_link_an_mode)) + phylink_autoneg_inband(pl->act_link_an_mode)) pl->pcs->ops->pcs_an_restart(pl->pcs); } @@ -1126,7 +1127,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, { unsigned int neg_mode, mode; - mode = pl->cur_link_an_mode; + mode = pl->req_link_an_mode; switch (interface) { case PHY_INTERFACE_MODE_SGMII: @@ -1168,6 +1169,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, } pl->pcs_neg_mode = neg_mode; + pl->act_link_an_mode = mode; } static void phylink_major_config(struct phylink *pl, bool restart, @@ -1198,7 +1200,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_pcs_poll_stop(pl); if (pl->mac_ops->mac_prepare) { - err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, + err = pl->mac_ops->mac_prepare(pl->config, pl->act_link_an_mode, state->interface); if (err < 0) { phylink_err(pl, "mac_prepare failed: %pe\n", @@ -1232,7 +1234,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed) phylink_pcs_enable(pl->pcs); - neg_mode = pl->cur_link_an_mode; + neg_mode = pl->act_link_an_mode; if (pl->pcs && pl->pcs->neg_mode) neg_mode = pl->pcs_neg_mode; @@ -1248,7 +1250,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_pcs_an_restart(pl); if (pl->mac_ops->mac_finish) { - err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode, + err = pl->mac_ops->mac_finish(pl->config, pl->act_link_an_mode, state->interface); if (err < 0) phylink_err(pl, "mac_finish failed: %pe\n", @@ -1279,7 +1281,7 @@ static int phylink_change_inband_advert(struct phylink *pl) return 0; phylink_dbg(pl, "%s: mode=%s/%s adv=%*pb pause=%02x\n", __func__, - phylink_an_mode_str(pl->cur_link_an_mode), + phylink_an_mode_str(pl->req_link_an_mode), phy_modes(pl->link_config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising, pl->link_config.pause); @@ -1288,7 +1290,7 @@ static int phylink_change_inband_advert(struct phylink *pl) phylink_pcs_neg_mode(pl, pl->pcs, pl->link_config.interface, pl->link_config.advertising); - neg_mode = pl->cur_link_an_mode; + neg_mode = pl->act_link_an_mode; if (pl->pcs->neg_mode) neg_mode = pl->pcs_neg_mode; @@ -1353,7 +1355,7 @@ static void phylink_mac_initial_config(struct phylink *pl, bool force_restart) { struct phylink_link_state link_state; - switch (pl->cur_link_an_mode) { + switch (pl->req_link_an_mode) { case MLO_AN_PHY: link_state = pl->phy_state; break; @@ -1427,14 +1429,14 @@ static void phylink_link_up(struct phylink *pl, pl->cur_interface = link_state.interface; - neg_mode = pl->cur_link_an_mode; + neg_mode = pl->act_link_an_mode; if (pl->pcs && pl->pcs->neg_mode) neg_mode = pl->pcs_neg_mode; phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed, duplex); - pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, + pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->act_link_an_mode, pl->cur_interface, speed, duplex, !!(link_state.pause & MLO_PAUSE_TX), rx_pause); @@ -1454,7 +1456,7 @@ static void phylink_link_down(struct phylink *pl) if (ndev) netif_carrier_off(ndev); - pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode, + pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode, pl->cur_interface); phylink_info(pl, "Link is Down\n"); } @@ -1480,10 +1482,10 @@ static void phylink_resolve(struct work_struct *w) } else if (pl->link_failed) { link_state.link = false; retrigger = true; - } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { + } else if (pl->act_link_an_mode == MLO_AN_FIXED) { phylink_get_fixed_state(pl, &link_state); mac_config = link_state.link; - } else if (pl->cur_link_an_mode == MLO_AN_PHY) { + } else if (pl->act_link_an_mode == MLO_AN_PHY) { link_state = pl->phy_state; mac_config = link_state.link; } else { @@ -1537,7 +1539,7 @@ static void phylink_resolve(struct work_struct *w) } } - if (pl->cur_link_an_mode != MLO_AN_FIXED) + if (pl->act_link_an_mode != MLO_AN_FIXED) phylink_apply_manual_flow(pl, &link_state); if (mac_config) { @@ -1661,7 +1663,7 @@ int phylink_set_fixed_link(struct phylink *pl, pl->link_config.an_complete = 1; pl->cfg_link_an_mode = MLO_AN_FIXED; - pl->cur_link_an_mode = pl->cfg_link_an_mode; + pl->req_link_an_mode = pl->cfg_link_an_mode; return 0; } @@ -1756,7 +1758,7 @@ struct phylink *phylink_create(struct phylink_config *config, } } - pl->cur_link_an_mode = pl->cfg_link_an_mode; + pl->req_link_an_mode = pl->cfg_link_an_mode; ret = phylink_register_sfp(pl, fwnode); if (ret < 0) { @@ -2213,7 +2215,7 @@ void phylink_start(struct phylink *pl) ASSERT_RTNL(); phylink_info(pl, "configuring for %s/%s link mode\n", - phylink_an_mode_str(pl->cur_link_an_mode), + phylink_an_mode_str(pl->req_link_an_mode), phy_modes(pl->link_config.interface)); /* Always set the carrier off */ @@ -2472,7 +2474,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, linkmode_copy(kset->link_modes.supported, pl->supported); - switch (pl->cur_link_an_mode) { + switch (pl->act_link_an_mode) { case MLO_AN_FIXED: /* We are using fixed settings. Report these as the * current link settings - and note that these also @@ -2564,7 +2566,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, /* If we have a fixed link, refuse to change link parameters. * If the link parameters match, accept them but do nothing. */ - if (pl->cur_link_an_mode == MLO_AN_FIXED) { + if (pl->req_link_an_mode == MLO_AN_FIXED) { if (s->speed != pl->link_config.speed || s->duplex != pl->link_config.duplex) return -EINVAL; @@ -2580,7 +2582,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, * is our default case) but do not allow the advertisement to * be changed. If the advertisement matches, simply return. */ - if (pl->cur_link_an_mode == MLO_AN_FIXED) { + if (pl->req_link_an_mode == MLO_AN_FIXED) { if (!linkmode_equal(config.advertising, pl->link_config.advertising)) return -EINVAL; @@ -2620,7 +2622,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, linkmode_copy(support, pl->supported); if (phylink_validate(pl, support, &config)) { phylink_err(pl, "validation of %s/%s with support %*pb failed\n", - phylink_an_mode_str(pl->cur_link_an_mode), + phylink_an_mode_str(pl->req_link_an_mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support); return -EINVAL; @@ -2720,7 +2722,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, ASSERT_RTNL(); - if (pl->cur_link_an_mode == MLO_AN_FIXED) + if (pl->req_link_an_mode == MLO_AN_FIXED) return -EOPNOTSUPP; if (!phylink_test(pl->supported, Pause) && @@ -2984,7 +2986,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, struct phylink_link_state state; int val = 0xffff; - switch (pl->cur_link_an_mode) { + switch (pl->act_link_an_mode) { case MLO_AN_FIXED: if (phy_id == 0) { phylink_get_fixed_state(pl, &state); @@ -3009,7 +3011,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, static int phylink_mii_write(struct phylink *pl, unsigned int phy_id, unsigned int reg, unsigned int val) { - switch (pl->cur_link_an_mode) { + switch (pl->act_link_an_mode) { case MLO_AN_FIXED: break; @@ -3199,9 +3201,9 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, changed = true; } - if (pl->cur_link_an_mode != mode || + if (pl->req_link_an_mode != mode || pl->link_config.interface != state->interface) { - pl->cur_link_an_mode = mode; + pl->req_link_an_mode = mode; pl->link_config.interface = state->interface; changed = true; -- 2.51.0 From 015e4e7cba0f05b10e53d1ce833f5dc67d2db231 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:30:57 +0000 Subject: [PATCH 038/517] net: phylink: add debug for phylink_major_config() Now that we have a more complexity in phylink_major_config(), augment the debugging so we can see what's going on there. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUrZ-006ITt-Fa@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 5290afd0f54e..aa89c1f4706e 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -176,6 +176,24 @@ static const char *phylink_an_mode_str(unsigned int mode) return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; } +static const char *phylink_pcs_mode_str(unsigned int mode) +{ + if (!mode) + return "none"; + + if (mode & PHYLINK_PCS_NEG_OUTBAND) + return "outband"; + + if (mode & PHYLINK_PCS_NEG_INBAND) { + if (mode & PHYLINK_PCS_NEG_ENABLED) + return "inband,an-enabled"; + else + return "inband,an-disabled"; + } + + return "unknown"; +} + static unsigned int phylink_interface_signal_rate(phy_interface_t interface) { switch (interface) { @@ -1181,7 +1199,9 @@ static void phylink_major_config(struct phylink *pl, bool restart, unsigned int neg_mode; int err; - phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); + phylink_dbg(pl, "major config, requested %s/%s\n", + phylink_an_mode_str(pl->req_link_an_mode), + phy_modes(state->interface)); if (pl->using_mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); @@ -1197,6 +1217,11 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_pcs_neg_mode(pl, pcs, state->interface, state->advertising); + phylink_dbg(pl, "major config, active %s/%s/%s\n", + phylink_an_mode_str(pl->act_link_an_mode), + phylink_pcs_mode_str(pl->pcs_neg_mode), + phy_modes(state->interface)); + phylink_pcs_poll_stop(pl); if (pl->mac_ops->mac_prepare) { -- 2.51.0 From 6d67fd0b655cd00cc2da9f15e01e6a26d8ec9f8e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:02 +0000 Subject: [PATCH 039/517] net: phy: add phy_inband_caps() Add a method to query the PHY's in-band capabilities for a PHY interface mode. Where the interface mode does not have in-band capability, or the PHY driver has not been updated to return this information, then phy_inband_caps() should return zero. Otherwise, PHY drivers will return a value consisting of the following flags: LINK_INBAND_DISABLE indicates that the hardware does not support in-band signalling, or can have in-band signalling configured via software to be disabled. LINK_INBAND_ENABLE indicates that the hardware will use in-band signalling, or can have in-band signalling configured via software to be enabled. LINK_INBAND_BYPASS indicates that the hardware has the ability to bypass in-band signalling when enabled after a timeout if the link partner does not respond to its in-band signalling. This reports the PHY capabilities for the particular interface mode, not the current configuration. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUre-006ITz-KF@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy.c | 21 +++++++++++++++++++++ include/linux/phy.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c9cfdc33fc5f..8d91922d3bb9 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1048,6 +1048,27 @@ static int phy_check_link_status(struct phy_device *phydev) return 0; } +/** + * phy_inband_caps - query which in-band signalling modes are supported + * @phydev: a pointer to a &struct phy_device + * @interface: the interface mode for the PHY + * + * Returns zero if it is unknown what in-band signalling is supported by the + * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, + * returns a bit mask of the LINK_INBAND_* values from + * &enum link_inband_signalling to describe which inband modes are supported + * by the PHY for this interface mode. + */ +unsigned int phy_inband_caps(struct phy_device *phydev, + phy_interface_t interface) +{ + if (phydev->drv && phydev->drv->inband_caps) + return phydev->drv->inband_caps(phydev, interface); + + return 0; +} +EXPORT_SYMBOL_GPL(phy_inband_caps); + /** * _phy_start_aneg - start auto-negotiation for this PHY device * @phydev: the phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index dfc7b97f9648..fee0fad7538d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -815,6 +815,24 @@ struct phy_tdr_config { }; #define PHY_PAIR_ALL -1 +/** + * enum link_inband_signalling - in-band signalling modes that are supported + * + * @LINK_INBAND_DISABLE: in-band signalling can be disabled + * @LINK_INBAND_ENABLE: in-band signalling can be enabled without bypass + * @LINK_INBAND_BYPASS: in-band signalling can be enabled with bypass + * + * The possible and required bits can only be used if the valid bit is set. + * If possible is clear, that means inband signalling can not be used. + * Required is only valid when possible is set, and means that inband + * signalling must be used. + */ +enum link_inband_signalling { + LINK_INBAND_DISABLE = BIT(0), + LINK_INBAND_ENABLE = BIT(1), + LINK_INBAND_BYPASS = BIT(2), +}; + /** * struct phy_plca_cfg - Configuration of the PLCA (Physical Layer Collision * Avoidance) Reconciliation Sublayer. @@ -953,6 +971,14 @@ struct phy_driver { */ int (*get_features)(struct phy_device *phydev); + /** + * @inband_caps: query whether in-band is supported for the given PHY + * interface mode. Returns a bitmask of bits defined by enum + * link_inband_signalling. + */ + unsigned int (*inband_caps)(struct phy_device *phydev, + phy_interface_t interface); + /** * @get_rate_matching: Get the supported type of rate matching for a * particular phy interface. This is used by phy consumers to determine @@ -1832,6 +1858,8 @@ int phy_config_aneg(struct phy_device *phydev); int _phy_start_aneg(struct phy_device *phydev); int phy_start_aneg(struct phy_device *phydev); int phy_aneg_done(struct phy_device *phydev); +unsigned int phy_inband_caps(struct phy_device *phydev, + phy_interface_t interface); int phy_speed_down(struct phy_device *phydev, bool sync); int phy_speed_up(struct phy_device *phydev); bool phy_check_valid(int speed, int duplex, unsigned long *features); -- 2.51.0 From 8c321641d38995ad5b4412960e323283add4ecac Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:07 +0000 Subject: [PATCH 040/517] net: phy: bcm84881: implement phy_inband_caps() method BCM84881 has no support for inband signalling, so this is a trivial implementation that returns no support for inband. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Acked-by: Florian Fainelli Link: https://patch.msgid.link/E1tIUrj-006IU6-ON@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/bcm84881.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c index 97da3aee4942..47405bded677 100644 --- a/drivers/net/phy/bcm84881.c +++ b/drivers/net/phy/bcm84881.c @@ -235,11 +235,21 @@ static int bcm84881_read_status(struct phy_device *phydev) return genphy_c45_read_mdix(phydev); } +/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII + * or 802.3z control word, so inband will not work. + */ +static unsigned int bcm84881_inband_caps(struct phy_device *phydev, + phy_interface_t interface) +{ + return LINK_INBAND_DISABLE; +} + static struct phy_driver bcm84881_drivers[] = { { .phy_id = 0xae025150, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM84881", + .inband_caps = bcm84881_inband_caps, .config_init = bcm84881_config_init, .probe = bcm84881_probe, .get_features = bcm84881_get_features, -- 2.51.0 From d51b2838d0daaf2ca36abb4dd616b7ba170a2992 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:12 +0000 Subject: [PATCH 041/517] net: phy: marvell: implement phy_inband_caps() method Provide an implementation for phy_inband_caps() for Marvell PHYs used on SFP modules, so that phylink knows the PHYs capabilities. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUro-006IUC-Rq@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 9964bf3dea2f..53f6711df93b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -716,6 +716,20 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev) return genphy_check_and_restart_aneg(phydev, changed); } +static unsigned int m88e1111_inband_caps(struct phy_device *phydev, + phy_interface_t interface) +{ + /* In 1000base-X and SGMII modes, the inband mode can be changed + * through the Fibre page BMCR ANENABLE bit. + */ + if (interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_SGMII) + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE | + LINK_INBAND_BYPASS; + + return 0; +} + static int m88e1111_config_aneg(struct phy_device *phydev) { int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); @@ -3667,6 +3681,7 @@ static struct phy_driver marvell_drivers[] = { .name = "Marvell 88E1112", /* PHY_GBIT_FEATURES */ .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, .config_init = m88e1112_config_init, .config_aneg = marvell_config_aneg, .config_intr = marvell_config_intr, @@ -3688,6 +3703,7 @@ static struct phy_driver marvell_drivers[] = { /* PHY_GBIT_FEATURES */ .flags = PHY_POLL_CABLE_TEST, .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, @@ -3711,6 +3727,7 @@ static struct phy_driver marvell_drivers[] = { .name = "Marvell 88E1111 (Finisar)", /* PHY_GBIT_FEATURES */ .probe = marvell_probe, + .inband_caps = m88e1111_inband_caps, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, -- 2.51.0 From 3f3d8f3025892a86b501b3b2247438dc6d23f3bd Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:18 +0000 Subject: [PATCH 042/517] net: phy: add phy_config_inband() Add a method to configure the PHY's in-band mode. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUru-006IUI-08@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy.c | 32 ++++++++++++++++++++++++++++++++ include/linux/phy.h | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 8d91922d3bb9..1ab58bb5e6db 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1069,6 +1069,38 @@ unsigned int phy_inband_caps(struct phy_device *phydev, } EXPORT_SYMBOL_GPL(phy_inband_caps); +/** + * phy_config_inband - configure the desired PHY in-band mode + * @phydev: the phy_device struct + * @modes: in-band modes to configure + * + * Description: disables, enables or enables-with-bypass in-band signalling + * between the PHY and host system. + * + * Returns: zero on success, or negative errno value. + */ +int phy_config_inband(struct phy_device *phydev, unsigned int modes) +{ + int err; + + if (!!(modes & LINK_INBAND_DISABLE) + + !!(modes & LINK_INBAND_ENABLE) + + !!(modes & LINK_INBAND_BYPASS) != 1) + return -EINVAL; + + mutex_lock(&phydev->lock); + if (!phydev->drv) + err = -EIO; + else if (!phydev->drv->config_inband) + err = -EOPNOTSUPP; + else + err = phydev->drv->config_inband(phydev, modes); + mutex_unlock(&phydev->lock); + + return err; +} +EXPORT_SYMBOL(phy_config_inband); + /** * _phy_start_aneg - start auto-negotiation for this PHY device * @phydev: the phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index fee0fad7538d..81c504d9850e 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -979,6 +979,11 @@ struct phy_driver { unsigned int (*inband_caps)(struct phy_device *phydev, phy_interface_t interface); + /** + * @config_inband: configure in-band mode for the PHY + */ + int (*config_inband)(struct phy_device *phydev, unsigned int modes); + /** * @get_rate_matching: Get the supported type of rate matching for a * particular phy interface. This is used by phy consumers to determine @@ -1860,6 +1865,7 @@ int phy_start_aneg(struct phy_device *phydev); int phy_aneg_done(struct phy_device *phydev); unsigned int phy_inband_caps(struct phy_device *phydev, phy_interface_t interface); +int phy_config_inband(struct phy_device *phydev, unsigned int modes); int phy_speed_down(struct phy_device *phydev, bool sync); int phy_speed_up(struct phy_device *phydev); bool phy_check_valid(int speed, int duplex, unsigned long *features); -- 2.51.0 From e46d8359ab3011442c642952753d45c2482a605c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:23 +0000 Subject: [PATCH 043/517] net: phy: marvell: implement config_inband() method Implement the config_inband() method for Marvell 88E1112, 88E1111, and Finisar's 88E1111 variant. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUrz-006IUO-3r@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/marvell.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 53f6711df93b..b7d2951d979d 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -730,6 +730,34 @@ static unsigned int m88e1111_inband_caps(struct phy_device *phydev, return 0; } +static int m88e1111_config_inband(struct phy_device *phydev, unsigned int modes) +{ + u16 extsr, bmcr; + int err; + + if (phydev->interface != PHY_INTERFACE_MODE_1000BASEX && + phydev->interface != PHY_INTERFACE_MODE_SGMII) + return -EINVAL; + + if (modes == LINK_INBAND_BYPASS) + extsr = MII_M1111_HWCFG_SERIAL_AN_BYPASS; + else + extsr = 0; + + if (modes == LINK_INBAND_DISABLE) + bmcr = 0; + else + bmcr = BMCR_ANENABLE; + + err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, + MII_M1111_HWCFG_SERIAL_AN_BYPASS, extsr); + if (err < 0) + return extsr; + + return phy_modify_paged(phydev, MII_MARVELL_FIBER_PAGE, MII_BMCR, + BMCR_ANENABLE, bmcr); +} + static int m88e1111_config_aneg(struct phy_device *phydev) { int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); @@ -3682,6 +3710,7 @@ static struct phy_driver marvell_drivers[] = { /* PHY_GBIT_FEATURES */ .probe = marvell_probe, .inband_caps = m88e1111_inband_caps, + .config_inband = m88e1111_config_inband, .config_init = m88e1112_config_init, .config_aneg = marvell_config_aneg, .config_intr = marvell_config_intr, @@ -3704,6 +3733,7 @@ static struct phy_driver marvell_drivers[] = { .flags = PHY_POLL_CABLE_TEST, .probe = marvell_probe, .inband_caps = m88e1111_inband_caps, + .config_inband = m88e1111_config_inband, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, @@ -3728,6 +3758,7 @@ static struct phy_driver marvell_drivers[] = { /* PHY_GBIT_FEATURES */ .probe = marvell_probe, .inband_caps = m88e1111_inband_caps, + .config_inband = m88e1111_config_inband, .config_init = m88e1111gbe_config_init, .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, -- 2.51.0 From 53185318bdfaf4dbfcc0568513e3b3883e30520c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:28 +0000 Subject: [PATCH 044/517] net: phylink: add pcs_inband_caps() method Add a pcs_inband_caps() method to query the PCS for its inband link capabilities, and use this to determine whether link modes used with optical SFPs can be supported. When a PCS does not provide a method, we allow inband negotiation to be either on or off, making this a no-op until the pcs_inband_caps() method is implemented by a PCS driver. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUs4-006IUU-7K@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 60 +++++++++++++++++++++++++++++++++++++++ include/linux/phylink.h | 17 +++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index aa89c1f4706e..c358ab5c16a7 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1007,6 +1007,15 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state) } } +static unsigned int phylink_pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + if (pcs && pcs->ops->pcs_inband_caps) + return pcs->ops->pcs_inband_caps(pcs, interface); + + return 0; +} + static void phylink_pcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) { @@ -1060,6 +1069,24 @@ static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex); } +/* Query inband for a specific interface mode, asking the MAC for the + * PCS which will be used to handle the interface mode. + */ +static unsigned int phylink_inband_caps(struct phylink *pl, + phy_interface_t interface) +{ + struct phylink_pcs *pcs; + + if (!pl->mac_ops->mac_select_pcs) + return 0; + + pcs = pl->mac_ops->mac_select_pcs(pl->config, interface); + if (!pcs) + return 0; + + return phylink_pcs_inband_caps(pcs, interface); +} + static void phylink_pcs_poll_stop(struct phylink *pl) { if (pl->cfg_link_an_mode == MLO_AN_INBAND) @@ -2530,6 +2557,26 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, } EXPORT_SYMBOL_GPL(phylink_ethtool_ksettings_get); +static bool phylink_validate_pcs_inband_autoneg(struct phylink *pl, + phy_interface_t interface, + unsigned long *adv) +{ + unsigned int inband = phylink_inband_caps(pl, interface); + unsigned int mask; + + /* If the PCS doesn't implement inband support, be permissive. */ + if (!inband) + return true; + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, adv)) + mask = LINK_INBAND_ENABLE; + else + mask = LINK_INBAND_DISABLE; + + /* Check whether the PCS implements the required mode */ + return !!(inband & mask); +} + /** * phylink_ethtool_ksettings_set() - set the link settings * @pl: a pointer to a &struct phylink returned from phylink_create() @@ -2665,6 +2712,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, phylink_is_empty_linkmode(config.advertising)) return -EINVAL; + /* Validate the autonegotiation state. We don't have a PHY in this + * situation, so the PCS is the media-facing entity. + */ + if (!phylink_validate_pcs_inband_autoneg(pl, config.interface, + config.advertising)) + return -EINVAL; + mutex_lock(&pl->state_mutex); pl->link_config.speed = config.speed; pl->link_config.duplex = config.duplex; @@ -3349,6 +3403,12 @@ static int phylink_sfp_config_optical(struct phylink *pl) phylink_dbg(pl, "optical SFP: chosen %s interface\n", phy_modes(interface)); + if (!phylink_validate_pcs_inband_autoneg(pl, interface, + config.advertising)) { + phylink_err(pl, "autoneg setting not compatible with PCS"); + return -EINVAL; + } + config.interface = interface; /* Ignore errors if we're expecting a PHY to attach later */ diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 5c01048860c4..5462cc6a37dc 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -419,6 +419,7 @@ struct phylink_pcs { /** * struct phylink_pcs_ops - MAC PCS operations structure. * @pcs_validate: validate the link configuration. + * @pcs_inband_caps: query inband support for interface mode. * @pcs_enable: enable the PCS. * @pcs_disable: disable the PCS. * @pcs_pre_config: pre-mac_config method (for errata) @@ -434,6 +435,8 @@ struct phylink_pcs { struct phylink_pcs_ops { int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, const struct phylink_link_state *state); + unsigned int (*pcs_inband_caps)(struct phylink_pcs *pcs, + phy_interface_t interface); int (*pcs_enable)(struct phylink_pcs *pcs); void (*pcs_disable)(struct phylink_pcs *pcs); void (*pcs_pre_config)(struct phylink_pcs *pcs, @@ -470,6 +473,20 @@ struct phylink_pcs_ops { int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported, const struct phylink_link_state *state); +/** + * pcs_inband_caps - query PCS in-band capabilities for interface mode. + * @pcs: a pointer to a &struct phylink_pcs. + * @interface: interface mode to be queried + * + * Returns zero if it is unknown what in-band signalling is supported by the + * PHY (e.g. because the PHY driver doesn't implement the method.) Otherwise, + * returns a bit mask of the LINK_INBAND_* values from + * &enum link_inband_signalling to describe which inband modes are supported + * for this interface mode. + */ +unsigned int pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface); + /** * pcs_enable() - enable the PCS. * @pcs: a pointer to a &struct phylink_pcs. -- 2.51.0 From d39d93def7796638ddfe476907564390b4a97191 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:33 +0000 Subject: [PATCH 045/517] net: mvneta: implement pcs_inband_caps() method Report the PCS in-band capabilities to phylink for Marvell NETA interfaces. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUs9-006IUb-Au@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/mvneta.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d72b2d5f96db..0a5b93857fb5 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3960,20 +3960,27 @@ static struct mvneta_port *mvneta_pcs_to_port(struct phylink_pcs *pcs) return container_of(pcs, struct mvneta_port, phylink_pcs); } -static int mvneta_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) +static unsigned int mvneta_pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) { - /* We only support QSGMII, SGMII, 802.3z and RGMII modes. - * When in 802.3z mode, we must have AN enabled: + /* When operating in an 802.3z mode, we must have AN enabled: * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... * When = 1 (1000BASE-X) this field must be set to 1." + * Therefore, inband is "required". */ - if (phy_interface_mode_is_8023z(state->interface) && - !phylink_test(state->advertising, Autoneg)) - return -EINVAL; + if (phy_interface_mode_is_8023z(interface)) + return LINK_INBAND_ENABLE; - return 0; + /* QSGMII, SGMII and RGMII can be configured to use inband + * signalling of the AN result. Indicate these as "possible". + */ + if (interface == PHY_INTERFACE_MODE_SGMII || + interface == PHY_INTERFACE_MODE_QSGMII || + phy_interface_mode_is_rgmii(interface)) + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + /* For any other modes, indicate that inband is not supported. */ + return LINK_INBAND_DISABLE; } static void mvneta_pcs_get_state(struct phylink_pcs *pcs, @@ -4071,7 +4078,7 @@ static void mvneta_pcs_an_restart(struct phylink_pcs *pcs) } static const struct phylink_pcs_ops mvneta_phylink_pcs_ops = { - .pcs_validate = mvneta_pcs_validate, + .pcs_inband_caps = mvneta_pcs_inband_caps, .pcs_get_state = mvneta_pcs_get_state, .pcs_config = mvneta_pcs_config, .pcs_an_restart = mvneta_pcs_an_restart, -- 2.51.0 From a1520f83646272782f463024a858f31623494124 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:38 +0000 Subject: [PATCH 046/517] net: mvpp2: implement pcs_inband_caps() method Report the PCS in-band capabilities to phylink for Marvell PP2 interfaces. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUsE-006IUh-E7@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 66b5a80c9c28..ebb49c04a7a0 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -6237,19 +6237,26 @@ static const struct phylink_pcs_ops mvpp2_phylink_xlg_pcs_ops = { .pcs_config = mvpp2_xlg_pcs_config, }; -static int mvpp2_gmac_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) +static unsigned int mvpp2_gmac_pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) { - /* When in 802.3z mode, we must have AN enabled: + /* When operating in an 802.3z mode, we must have AN enabled: * Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... * When = 1 (1000BASE-X) this field must be set to 1. + * Therefore, inband is "required". */ - if (phy_interface_mode_is_8023z(state->interface) && - !phylink_test(state->advertising, Autoneg)) - return -EINVAL; + if (phy_interface_mode_is_8023z(interface)) + return LINK_INBAND_ENABLE; - return 0; + /* SGMII and RGMII can be configured to use inband signalling of the + * AN result. Indicate these as "possible". + */ + if (interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_rgmii(interface)) + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + /* For any other modes, indicate that inband is not supported. */ + return LINK_INBAND_DISABLE; } static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs, @@ -6356,7 +6363,7 @@ static void mvpp2_gmac_pcs_an_restart(struct phylink_pcs *pcs) } static const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = { - .pcs_validate = mvpp2_gmac_pcs_validate, + .pcs_inband_caps = mvpp2_gmac_pcs_inband_caps, .pcs_get_state = mvpp2_gmac_pcs_get_state, .pcs_config = mvpp2_gmac_pcs_config, .pcs_an_restart = mvpp2_gmac_pcs_an_restart, -- 2.51.0 From c34544c535d20859435b80f2dd0052323036eb9e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:43 +0000 Subject: [PATCH 047/517] net: phylink: add negotiation of in-band capabilities Support for in-band signalling with Serdes links is uncertain. Some PHYs do not support in-band for e.g. SGMII. Some PCS do not support in-band for 2500Base-X. Some PCS require in-band for Base-X protocols. Simply using what is in DT is insufficient when we have hot-pluggable PHYs e.g. in the form of SFP modules, which may not provide the in-band signalling. In order to address this, we have introduced phy_inband_caps() and pcs_inband_caps() functions to allow phylink to retrieve the capabilities from each end of the PCS/PHY link. This commit adds code to resolve whether in-band will be used in the various scenarios that we have: In-band not being used, PHY present using SGMII or Base-X, PHY not present. We also deal with no capabilties provided. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUsJ-006IUn-H3@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 154 +++++++++++++++++++++++++++++++++++--- 1 file changed, 144 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index c358ab5c16a7..f07c674816db 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -75,6 +75,7 @@ struct phylink { struct mutex state_mutex; struct phylink_link_state phy_state; + unsigned int phy_ib_mode; struct work_struct resolve; unsigned int pcs_neg_mode; unsigned int pcs_state; @@ -1170,10 +1171,18 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, phy_interface_t interface, const unsigned long *advertising) { + unsigned int pcs_ib_caps = 0; + unsigned int phy_ib_caps = 0; unsigned int neg_mode, mode; + enum { + INBAND_CISCO_SGMII, + INBAND_BASEX, + } type; mode = pl->req_link_an_mode; + pl->phy_ib_mode = 0; + switch (interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: @@ -1185,10 +1194,7 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, * inband communication. Note: there exist PHYs that run * with SGMII but do not send the inband data. */ - if (!phylink_autoneg_inband(mode)) - neg_mode = PHYLINK_PCS_NEG_OUTBAND; - else - neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + type = INBAND_CISCO_SGMII; break; case PHY_INTERFACE_MODE_1000BASEX: @@ -1199,18 +1205,139 @@ static void phylink_pcs_neg_mode(struct phylink *pl, struct phylink_pcs *pcs, * as well, but drivers may not support this, so may * need to override this. */ - if (!phylink_autoneg_inband(mode)) + type = INBAND_BASEX; + break; + + default: + pl->pcs_neg_mode = PHYLINK_PCS_NEG_NONE; + pl->act_link_an_mode = mode; + return; + } + + if (pcs) + pcs_ib_caps = phylink_pcs_inband_caps(pcs, interface); + + if (pl->phydev) + phy_ib_caps = phy_inband_caps(pl->phydev, interface); + + phylink_dbg(pl, "interface %s inband modes: pcs=%02x phy=%02x\n", + phy_modes(interface), pcs_ib_caps, phy_ib_caps); + + if (!phylink_autoneg_inband(mode)) { + bool pcs_ib_only = false; + bool phy_ib_only = false; + + if (pcs_ib_caps && pcs_ib_caps != LINK_INBAND_DISABLE) { + /* PCS supports reporting in-band capabilities, and + * supports more than disable mode. + */ + if (pcs_ib_caps & LINK_INBAND_DISABLE) + neg_mode = PHYLINK_PCS_NEG_OUTBAND; + else if (pcs_ib_caps & LINK_INBAND_ENABLE) + pcs_ib_only = true; + } + + if (phy_ib_caps && phy_ib_caps != LINK_INBAND_DISABLE) { + /* PHY supports in-band capabilities, and supports + * more than disable mode. + */ + if (phy_ib_caps & LINK_INBAND_DISABLE) + pl->phy_ib_mode = LINK_INBAND_DISABLE; + else if (phy_ib_caps & LINK_INBAND_BYPASS) + pl->phy_ib_mode = LINK_INBAND_BYPASS; + else if (phy_ib_caps & LINK_INBAND_ENABLE) + phy_ib_only = true; + } + + /* If either the PCS or PHY requires inband to be enabled, + * this is an invalid configuration. Provide a diagnostic + * message for this case, but don't try to force the issue. + */ + if (pcs_ib_only || phy_ib_only) + phylink_warn(pl, + "firmware wants %s mode, but %s%s%s requires inband\n", + phylink_an_mode_str(mode), + pcs_ib_only ? "PCS" : "", + pcs_ib_only && phy_ib_only ? " and " : "", + phy_ib_only ? "PHY" : ""); + + neg_mode = PHYLINK_PCS_NEG_OUTBAND; + } else if (type == INBAND_CISCO_SGMII || pl->phydev) { + /* For SGMII modes which are designed to be used with PHYs, or + * Base-X with a PHY, we try to use in-band mode where-ever + * possible. However, there are some PHYs e.g. BCM84881 which + * do not support in-band. + */ + const unsigned int inband_ok = LINK_INBAND_ENABLE | + LINK_INBAND_BYPASS; + const unsigned int outband_ok = LINK_INBAND_DISABLE | + LINK_INBAND_BYPASS; + /* PCS PHY + * D E D E + * 0 0 0 0 no information inband enabled + * 1 0 0 0 pcs doesn't support outband + * 0 1 0 0 pcs required inband enabled + * 1 1 0 0 pcs optional inband enabled + * 0 0 1 0 phy doesn't support outband + * 1 0 1 0 pcs+phy doesn't support outband + * 0 1 1 0 pcs required, phy doesn't support, invalid + * 1 1 1 0 pcs optional, phy doesn't support, outband + * 0 0 0 1 phy required inband enabled + * 1 0 0 1 pcs doesn't support, phy required, invalid + * 0 1 0 1 pcs+phy required inband enabled + * 1 1 0 1 pcs optional, phy required inband enabled + * 0 0 1 1 phy optional inband enabled + * 1 0 1 1 pcs doesn't support, phy optional, outband + * 0 1 1 1 pcs required, phy optional inband enabled + * 1 1 1 1 pcs+phy optional inband enabled + */ + if ((!pcs_ib_caps || pcs_ib_caps & inband_ok) && + (!phy_ib_caps || phy_ib_caps & inband_ok)) { + /* In-band supported or unknown at both ends. Enable + * in-band mode with or without bypass at the PHY. + */ + if (phy_ib_caps & LINK_INBAND_ENABLE) + pl->phy_ib_mode = LINK_INBAND_ENABLE; + else if (phy_ib_caps & LINK_INBAND_BYPASS) + pl->phy_ib_mode = LINK_INBAND_BYPASS; + + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + } else if ((!pcs_ib_caps || pcs_ib_caps & outband_ok) && + (!phy_ib_caps || phy_ib_caps & outband_ok)) { + /* Either in-band not supported at at least one end. + * In-band bypass at the other end is possible. + */ + if (phy_ib_caps & LINK_INBAND_DISABLE) + pl->phy_ib_mode = LINK_INBAND_DISABLE; + else if (phy_ib_caps & LINK_INBAND_BYPASS) + pl->phy_ib_mode = LINK_INBAND_BYPASS; + neg_mode = PHYLINK_PCS_NEG_OUTBAND; + if (pl->phydev) + mode = MLO_AN_PHY; + } else { + /* invalid */ + phylink_warn(pl, "%s: incompatible in-band capabilities, trying in-band", + phy_modes(interface)); + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + } + } else { + /* For Base-X without a PHY */ + if (pcs_ib_caps == LINK_INBAND_DISABLE) + /* If the PCS doesn't support inband, then inband must + * be disabled. + */ + neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; + else if (pcs_ib_caps == LINK_INBAND_ENABLE) + /* If the PCS requires inband, then inband must always + * be enabled. + */ + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; else neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; - break; - - default: - neg_mode = PHYLINK_PCS_NEG_NONE; - break; } pl->pcs_neg_mode = neg_mode; @@ -1309,6 +1436,13 @@ static void phylink_major_config(struct phylink *pl, bool restart, ERR_PTR(err)); } + if (pl->phydev && pl->phy_ib_mode) { + err = phy_config_inband(pl->phydev, pl->phy_ib_mode); + if (err < 0) + phylink_err(pl, "phy_config_inband: %pe\n", + ERR_PTR(err)); + } + if (pl->sfp_bus) { rate_kbd = phylink_interface_signal_rate(state->interface); if (rate_kbd) -- 2.51.0 From 99013b966414b56578184ade8275d7065a49d243 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 3 Dec 2024 15:31:48 +0000 Subject: [PATCH 048/517] net: phylink: remove phylink_phy_no_inband() Remove phylink_phy_no_inband() now that we are handling the lack of inband negotiation by querying the capabilities of the PHY and PCS, and the BCM84881 PHY driver provides us the information necessary to make the decision. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tIUsO-006IUt-KN@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f07c674816db..ede93109f9c5 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3394,10 +3394,11 @@ static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl, return interface; } -static void phylink_sfp_set_config(struct phylink *pl, u8 mode, +static void phylink_sfp_set_config(struct phylink *pl, unsigned long *supported, struct phylink_link_state *state) { + u8 mode = MLO_AN_INBAND; bool changed = false; phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", @@ -3431,8 +3432,7 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, phylink_mac_initial_config(pl, false); } -static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, - struct phy_device *phy) +static int phylink_sfp_config_phy(struct phylink *pl, struct phy_device *phy) { __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); __ETHTOOL_DECLARE_LINK_MODE_MASK(support); @@ -3472,7 +3472,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, if (ret) { phylink_err(pl, "validation of %s/%s with support %*pb failed: %pe\n", - phylink_an_mode_str(mode), + phylink_an_mode_str(pl->req_link_an_mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support, ERR_PTR(ret)); @@ -3481,7 +3481,7 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, pl->link_port = pl->sfp_port; - phylink_sfp_set_config(pl, mode, support, &config); + phylink_sfp_set_config(pl, support, &config); return 0; } @@ -3556,7 +3556,7 @@ static int phylink_sfp_config_optical(struct phylink *pl) pl->link_port = pl->sfp_port; - phylink_sfp_set_config(pl, MLO_AN_INBAND, pl->sfp_support, &config); + phylink_sfp_set_config(pl, pl->sfp_support, &config); return 0; } @@ -3627,20 +3627,10 @@ static void phylink_sfp_link_up(void *upstream) phylink_enable_and_run_resolve(pl, PHYLINK_DISABLE_LINK); } -/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII - * or 802.3z control word, so inband will not work. - */ -static bool phylink_phy_no_inband(struct phy_device *phy) -{ - return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1], - 0xae025150, 0xfffffff0); -} - static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) { struct phylink *pl = upstream; phy_interface_t interface; - u8 mode; int ret; /* @@ -3652,17 +3642,12 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) */ phy_support_asym_pause(phy); - if (phylink_phy_no_inband(phy)) - mode = MLO_AN_PHY; - else - mode = MLO_AN_INBAND; - /* Set the PHY's host supported interfaces */ phy_interface_and(phy->host_interfaces, phylink_sfp_interfaces, pl->config->supported_interfaces); /* Do the initial configuration */ - ret = phylink_sfp_config_phy(pl, mode, phy); + ret = phylink_sfp_config_phy(pl, phy); if (ret < 0) return ret; -- 2.51.0 From 68b5488d76a29ee77592a116997e837791415755 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 5 Dec 2024 09:42:24 +0000 Subject: [PATCH 049/517] net: pcs: pcs-lynx: implement pcs_inband_caps() method Report the PCS in-band capabilities to phylink for the Lynx PCS. Reviewed-by: Maxime Chevallier Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tJ8NM-006L5J-AH@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index b79aedad855b..767a8c0714ac 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -35,6 +35,27 @@ enum sgmii_speed { #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs) #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs) +static unsigned int lynx_pcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_2500BASEX: + return LINK_INBAND_DISABLE; + + case PHY_INTERFACE_MODE_USXGMII: + return LINK_INBAND_ENABLE; + + default: + return 0; + } +} + static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs, struct phylink_link_state *state) { @@ -306,6 +327,7 @@ static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, } static const struct phylink_pcs_ops lynx_pcs_phylink_ops = { + .pcs_inband_caps = lynx_pcs_inband_caps, .pcs_get_state = lynx_pcs_get_state, .pcs_config = lynx_pcs_config, .pcs_an_restart = lynx_pcs_an_restart, -- 2.51.0 From 82dcb9cbcc5292ffb27082e1f6376298cca39999 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 5 Dec 2024 09:42:29 +0000 Subject: [PATCH 050/517] net: pcs: pcs-mtk-lynxi: implement pcs_inband_caps() method Report the PCS in-band capabilities to phylink for the LynxI PCS. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tJ8NR-006L5P-E3@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-mtk-lynxi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 4f63abe638c4..7de804535229 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -88,6 +88,21 @@ static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) return container_of(pcs, struct mtk_pcs_lynxi, pcs); } +static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + default: + return 0; + } +} + static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { @@ -241,6 +256,7 @@ static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs) } static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { + .pcs_inband_caps = mtk_pcs_lynxi_inband_caps, .pcs_get_state = mtk_pcs_lynxi_get_state, .pcs_config = mtk_pcs_lynxi_config, .pcs_an_restart = mtk_pcs_lynxi_restart_an, -- 2.51.0 From 4e4de8707612bd5ed15b49af0be4f10efdaec455 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 5 Dec 2024 09:42:34 +0000 Subject: [PATCH 051/517] net: pcs: xpcs: implement pcs_inband_caps() method Report the PCS inband capabilities to phylink for XPCS. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1tJ8NW-006L5V-I9@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 82463f9d50c8..1f0ec847895c 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -608,6 +608,33 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, return 0; } +static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); + const struct dw_xpcs_compat *compat; + + compat = xpcs_find_compat(xpcs->desc, interface); + if (!compat) + return 0; + + switch (compat->an_mode) { + case DW_AN_C73: + return LINK_INBAND_ENABLE; + + case DW_AN_C37_SGMII: + case DW_AN_C37_1000BASEX: + return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; + + case DW_10GBASER: + case DW_2500BASEX: + return LINK_INBAND_DISABLE; + + default: + return 0; + } +} + void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) { int i, j; @@ -1365,6 +1392,7 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = { static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_validate = xpcs_validate, + .pcs_inband_caps = xpcs_inband_caps, .pcs_config = xpcs_config, .pcs_get_state = xpcs_get_state, .pcs_an_restart = xpcs_an_restart, -- 2.51.0 From 7c06d850aae8abcc6caefb76d9bebe7013353c3e Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 27 Oct 2024 21:48:28 -0700 Subject: [PATCH 052/517] net: dsa: use ethtool string helpers These are the preferred way to copy ethtool strings. Avoids incrementing pointers all over the place. Signed-off-by: Rosen Penev (for hellcreek driver) Reviewed-by: Kurt Kanzenbach Link: https://patch.msgid.link/20241028044828.1639668-1-rosenp@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index c903c6fcc666..ad07efa44c55 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1086,8 +1086,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, if (stringset == ETH_SS_STATS) { for (i = 0; i < mib_size; i++) - strscpy(data + i * ETH_GSTRING_LEN, - mibs[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, mibs[i].name); } else if (stringset == ETH_SS_PHY_STATS) { phydev = b53_get_phy_device(ds, port); if (!phydev) -- 2.51.0 From 6eb6aee9c622b03602f9189203fd73d5f11bfc6b Mon Sep 17 00:00:00 2001 From: Torben Nielsen Date: Mon, 17 Feb 2025 09:05:01 +0100 Subject: [PATCH 053/517] net: dsa: b53: mdio: add support for BCM53101 BCM53101 is a ethernet switch, very similar to the BCM53115. Enable support for it, in the existing b53 dsa driver. Signed-off-by: Torben Nielsen Signed-off-by: Claus Stovgaard Link: https://patch.msgid.link/20250217080503.1390282-1-claus.stovgaard@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 14 ++++++++++++++ drivers/net/dsa/b53/b53_mdio.c | 1 + drivers/net/dsa/b53/b53_priv.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index ad07efa44c55..0598c8c60c85 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2583,6 +2583,19 @@ static const struct b53_chip_data b53_switch_chips[] = { .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, }, + { + .chip_id = BCM53101_DEVICE_ID, + .dev_name = "BCM53101", + .vlans = 4096, + .enabled_ports = 0x11f, + .arl_bins = 4, + .arl_buckets = 512, + .vta_regs = B53_VTA_REGS, + .imp_port = 8, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, { .chip_id = BCM53115_DEVICE_ID, .dev_name = "BCM53115", @@ -2964,6 +2977,7 @@ int b53_switch_detect(struct b53_device *dev) return ret; switch (id32) { + case BCM53101_DEVICE_ID: case BCM53115_DEVICE_ID: case BCM53125_DEVICE_ID: case BCM53128_DEVICE_ID: diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index 31d070bf161a..43a3b37b731b 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -374,6 +374,7 @@ static void b53_mdio_shutdown(struct mdio_device *mdiodev) static const struct of_device_id b53_of_match[] = { { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm53101" }, { .compatible = "brcm,bcm53115" }, { .compatible = "brcm,bcm53125" }, { .compatible = "brcm,bcm53128" }, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index e908397e8b9a..4b52a4807029 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -66,6 +66,7 @@ enum { BCM5395_DEVICE_ID = 0x95, BCM5397_DEVICE_ID = 0x97, BCM5398_DEVICE_ID = 0x98, + BCM53101_DEVICE_ID = 0x53101, BCM53115_DEVICE_ID = 0x53115, BCM53125_DEVICE_ID = 0x53125, BCM53128_DEVICE_ID = 0x53128, @@ -190,6 +191,7 @@ static inline int is531x5(struct b53_device *dev) { return dev->chip_id == BCM53115_DEVICE_ID || dev->chip_id == BCM53125_DEVICE_ID || + dev->chip_id == BCM53101_DEVICE_ID || dev->chip_id == BCM53128_DEVICE_ID || dev->chip_id == BCM53134_DEVICE_ID; } -- 2.51.0 From 427c593a29ae93f1675b83cc6ee5562c7a05ee23 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sat, 10 May 2025 11:22:11 +0200 Subject: [PATCH 054/517] net: dsa: b53: implement setting ageing time b53 supported switches support configuring ageing time between 1 and 1,048,575 seconds, so add an appropriate setter. This allows b53 to pass the FDB learning test for both vlan aware and vlan unaware bridges. Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250510092211.276541-1-jonas.gorski@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 28 ++++++++++++++++++++++++++++ drivers/net/dsa/b53/b53_priv.h | 1 + drivers/net/dsa/b53/b53_regs.h | 7 +++++++ 3 files changed, 36 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0598c8c60c85..d3589b94c356 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1227,6 +1228,10 @@ static int b53_setup(struct dsa_switch *ds) */ ds->untag_vlan_aware_bridge_pvid = true; + /* Ageing time is set in seconds */ + ds->ageing_time_min = 1 * 1000; + ds->ageing_time_max = AGE_TIME_MAX * 1000; + ret = b53_reset_switch(dev); if (ret) { dev_err(ds->dev, "failed to reset switch\n"); @@ -2444,6 +2449,28 @@ static int b53_get_max_mtu(struct dsa_switch *ds, int port) return B53_MAX_MTU; } +int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +{ + struct b53_device *dev = ds->priv; + u32 atc; + int reg; + + if (is63xx(dev)) + reg = B53_AGING_TIME_CONTROL_63XX; + else + reg = B53_AGING_TIME_CONTROL; + + atc = DIV_ROUND_CLOSEST(msecs, 1000); + + if (!is5325(dev) && !is5365(dev)) + atc |= AGE_CHANGE; + + b53_write32(dev, B53_MGMT_PAGE, reg, atc); + + return 0; +} +EXPORT_SYMBOL_GPL(b53_set_ageing_time); + static const struct phylink_mac_ops b53_phylink_mac_ops = { .mac_select_pcs = b53_phylink_mac_select_pcs, .mac_config = b53_phylink_mac_config, @@ -2468,6 +2495,7 @@ static const struct dsa_switch_ops b53_switch_ops = { .support_eee = b53_support_eee, .get_mac_eee = b53_get_mac_eee, .set_mac_eee = b53_set_mac_eee, + .set_ageing_time = b53_set_ageing_time, .port_bridge_join = b53_br_join, .port_bridge_leave = b53_br_leave, .port_pre_bridge_flags = b53_br_flags_pre, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 4b52a4807029..72f00f9e177c 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -343,6 +343,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); int b53_get_sset_count(struct dsa_switch *ds, int port, int sset); void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data); +int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, bool *tx_fwd_offload, struct netlink_ext_ack *extack); void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge); diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index 5741231e0841..f2caf8fe5699 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -225,6 +225,13 @@ #define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ #define BRCM_HDR_P7_EN BIT(2) /* Enable tagging on port 7 */ +/* Aging Time control register (32 bit) */ +#define B53_AGING_TIME_CONTROL 0x06 +#define B53_AGING_TIME_CONTROL_63XX 0x08 +#define AGE_CHANGE BIT(20) +#define AGE_TIME_MASK 0x7ffff +#define AGE_TIME_MAX 1048575 + /* Mirror capture control register (16 bit) */ #define B53_MIR_CAP_CTL 0x10 #define CAP_PORT_MASK 0xf -- 2.51.0 From 3198631f2e9d7a63611917584f509b56dfbd7401 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 2 Jun 2025 21:39:51 +0200 Subject: [PATCH 055/517] net: dsa: b53: do not configure bcm63xx's IMP port interface The IMP port is not a valid RGMII interface, but hard wired to internal, so we shouldn't touch the undefined register B53_RGMII_CTRL_IMP. While this does not seem to have any side effects, let's not touch it at all, so limit RGMII configuration on bcm63xx to the actual RGMII ports. Fixes: ce3bf94871f7 ("net: dsa: b53: add support for BCM63xx RGMIIs") Signed-off-by: Jonas Gorski Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250602193953.1010487-4-jonas.gorski@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/dsa/b53/b53_common.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index d3589b94c356..d7a56dbc7d07 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1360,24 +1361,17 @@ static void b53_adjust_63xx_rgmii(struct dsa_switch *ds, int port, phy_interface_t interface) { struct b53_device *dev = ds->priv; - u8 rgmii_ctrl = 0, off; - - if (port == dev->imp_port) - off = B53_RGMII_CTRL_IMP; - else - off = B53_RGMII_CTRL_P(port); + u8 rgmii_ctrl = 0; - b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); + b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl); rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC); - if (port != dev->imp_port) { - if (is63268(dev)) - rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; + if (is63268(dev)) + rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; - rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; - } + rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; - b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); + b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl); dev_dbg(ds->dev, "Configured port %d for %s\n", port, phy_modes(interface)); @@ -1528,7 +1522,7 @@ static void b53_phylink_mac_config(struct phylink_config *config, struct b53_device *dev = ds->priv; int port = dp->index; - if (is63xx(dev) && port >= B53_63XX_RGMII0) + if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4)) b53_adjust_63xx_rgmii(ds, port, interface); if (mode == MLO_AN_FIXED) { -- 2.51.0 From 58ff441b8e9051c9495e489887994c702ad0abe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:47 +0200 Subject: [PATCH 056/517] net: dsa: tag_brcm: legacy: reorganize functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move brcm_leg_tag_rcv() definition to top. This function is going to be shared between two different tags. Reviewed-by: Florian Fainelli Signed-off-by: Álvaro Fernández Rojas Link: https://patch.msgid.link/20250614080000.1884236-2-noltari@gmail.com Signed-off-by: Jakub Kicinski --- net/dsa/tag_brcm.c | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index fe75821623a4..9f4b0bcd95cd 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -213,6 +213,38 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME); #endif #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) +static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, + struct net_device *dev) +{ + int len = BRCM_LEG_TAG_LEN; + int source_port; + u8 *brcm_tag; + + if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) + return NULL; + + brcm_tag = dsa_etype_header_pos_rx(skb); + + source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; + + skb->dev = dsa_conduit_find_user(dev, 0, source_port); + if (!skb->dev) + return NULL; + + /* VLAN tag is added by BCM63xx internal switch */ + if (netdev_uses_dsa(skb->dev)) + len += VLAN_HLEN; + + /* Remove Broadcom tag and update checksum */ + skb_pull_rcsum(skb, len); + + dsa_default_offload_fwd_mark(skb); + + dsa_strip_etype_header(skb, len); + + return skb; +} + static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -250,38 +282,6 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, return skb; } -static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, - struct net_device *dev) -{ - int len = BRCM_LEG_TAG_LEN; - int source_port; - u8 *brcm_tag; - - if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) - return NULL; - - brcm_tag = dsa_etype_header_pos_rx(skb); - - source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; - - skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) - return NULL; - - /* VLAN tag is added by BCM63xx internal switch */ - if (netdev_uses_dsa(skb->dev)) - len += VLAN_HLEN; - - /* Remove Broadcom tag and update checksum */ - skb_pull_rcsum(skb, len); - - dsa_default_offload_fwd_mark(skb); - - dsa_strip_etype_header(skb, len); - - return skb; -} - static const struct dsa_device_ops brcm_legacy_netdev_ops = { .name = BRCM_LEGACY_NAME, .proto = DSA_TAG_PROTO_BRCM_LEGACY, -- 2.51.0 From fe2df740c952ccd825ba3eea0797b7eb5690ef1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:48 +0200 Subject: [PATCH 057/517] net: dsa: tag_brcm: add support for legacy FCS tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for legacy Broadcom FCS tags, which are similar to DSA_TAG_PROTO_BRCM_LEGACY. BCM5325 and BCM5365 switches require including the original FCS value and length, as opposed to BCM63xx switches. Adding the original FCS value and length to DSA_TAG_PROTO_BRCM_LEGACY would impact performance of BCM63xx switches, so it's better to create a new tag. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250614080000.1884236-3-noltari@gmail.com Signed-off-by: Jakub Kicinski --- include/net/dsa.h | 2 ++ net/dsa/Kconfig | 16 ++++++++-- net/dsa/tag_brcm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 877f9b270cf6..6f2a397fbe1c 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -54,11 +54,13 @@ struct tc_action; #define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26 #define DSA_TAG_PROTO_LAN937X_VALUE 27 #define DSA_TAG_PROTO_VSC73XX_8021Q_VALUE 28 +#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE 29 enum dsa_tag_protocol { DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, DSA_TAG_PROTO_BRCM = DSA_TAG_PROTO_BRCM_VALUE, DSA_TAG_PROTO_BRCM_LEGACY = DSA_TAG_PROTO_BRCM_LEGACY_VALUE, + DSA_TAG_PROTO_BRCM_LEGACY_FCS = DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE, DSA_TAG_PROTO_BRCM_PREPEND = DSA_TAG_PROTO_BRCM_PREPEND_VALUE, DSA_TAG_PROTO_DSA = DSA_TAG_PROTO_DSA_VALUE, DSA_TAG_PROTO_EDSA = DSA_TAG_PROTO_EDSA_VALUE, diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 2dfe9063613f..869cbe57162f 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig @@ -42,12 +42,24 @@ config NET_DSA_TAG_BRCM Broadcom switches which place the tag after the MAC source address. config NET_DSA_TAG_BRCM_LEGACY - tristate "Tag driver for Broadcom legacy switches using in-frame headers" + tristate "Tag driver for BCM63xx legacy switches using in-frame headers" select NET_DSA_TAG_BRCM_COMMON help Say Y if you want to enable support for tagging frames for the - Broadcom legacy switches which place the tag after the MAC source + BCM63xx legacy switches which place the tag after the MAC source address. + This tag is used in BCM63xx legacy switches which work without the + original FCS and length before the tag insertion. + +config NET_DSA_TAG_BRCM_LEGACY_FCS + tristate "Tag driver for BCM53xx legacy switches using in-frame headers" + select NET_DSA_TAG_BRCM_COMMON + help + Say Y if you want to enable support for tagging frames for the + BCM53xx legacy switches which place the tag after the MAC source + address. + This tag is used in BCM53xx legacy switches which expect original + FCS and length before the tag insertion to be present. config NET_DSA_TAG_BRCM_PREPEND tristate "Tag driver for Broadcom switches using prepended headers" diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index 9f4b0bcd95cd..26bb657ceac3 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -15,6 +15,7 @@ #define BRCM_NAME "brcm" #define BRCM_LEGACY_NAME "brcm-legacy" +#define BRCM_LEGACY_FCS_NAME "brcm-legacy-fcs" #define BRCM_PREPEND_NAME "brcm-prepend" /* Legacy Broadcom tag (6 bytes) */ @@ -32,6 +33,10 @@ #define BRCM_LEG_MULTICAST (1 << 5) #define BRCM_LEG_EGRESS (2 << 5) #define BRCM_LEG_INGRESS (3 << 5) +#define BRCM_LEG_LEN_HI(x) (((x) >> 8) & 0x7) + +/* 4th byte in the tag */ +#define BRCM_LEG_LEN_LO(x) ((x) & 0xff) /* 6th byte in the tag */ #define BRCM_LEG_PORT_ID (0xf) @@ -212,7 +217,8 @@ DSA_TAG_DRIVER(brcm_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME); #endif -#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) || \ + IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, struct net_device *dev) { @@ -244,7 +250,9 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, return skb; } +#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY || CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */ +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -294,6 +302,66 @@ DSA_TAG_DRIVER(brcm_legacy_netdev_ops); MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME); #endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */ +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) +static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct dsa_port *dp = dsa_user_to_port(dev); + unsigned int fcs_len; + __le32 fcs_val; + u8 *brcm_tag; + + /* The Ethernet switch we are interfaced with needs packets to be at + * least 64 bytes (including FCS) otherwise they will be discarded when + * they enter the switch port logic. When Broadcom tags are enabled, we + * need to make sure that packets are at least 70 bytes (including FCS + * and tag) because the length verification is done after the Broadcom + * tag is stripped off the ingress packet. + * + * Let dsa_user_xmit() free the SKB. + */ + if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) + return NULL; + + fcs_len = skb->len; + fcs_val = cpu_to_le32(crc32_le(~0, skb->data, fcs_len) ^ ~0); + + skb_push(skb, BRCM_LEG_TAG_LEN); + + dsa_alloc_etype_header(skb, BRCM_LEG_TAG_LEN); + + brcm_tag = skb->data + 2 * ETH_ALEN; + + /* Broadcom tag type */ + brcm_tag[0] = BRCM_LEG_TYPE_HI; + brcm_tag[1] = BRCM_LEG_TYPE_LO; + + /* Broadcom tag value */ + brcm_tag[2] = BRCM_LEG_EGRESS | BRCM_LEG_LEN_HI(fcs_len); + brcm_tag[3] = BRCM_LEG_LEN_LO(fcs_len); + brcm_tag[4] = 0; + brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID; + + /* Original FCS value */ + if (__skb_pad(skb, ETH_FCS_LEN, false)) + return NULL; + skb_put_data(skb, &fcs_val, ETH_FCS_LEN); + + return skb; +} + +static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = { + .name = BRCM_LEGACY_FCS_NAME, + .proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS, + .xmit = brcm_leg_fcs_tag_xmit, + .rcv = brcm_leg_tag_rcv, + .needed_headroom = BRCM_LEG_TAG_LEN, +}; + +DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops); +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME); +#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */ + #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb, struct net_device *dev) @@ -328,6 +396,9 @@ static struct dsa_tag_driver *dsa_tag_driver_array[] = { #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY) &DSA_TAG_DRIVER_NAME(brcm_legacy_netdev_ops), #endif +#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS) + &DSA_TAG_DRIVER_NAME(brcm_legacy_fcs_netdev_ops), +#endif #if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM_PREPEND) &DSA_TAG_DRIVER_NAME(brcm_prepend_netdev_ops), #endif -- 2.51.0 From 57d5fd907ba1839df4933da2fd6c7f3924f4030c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:49 +0200 Subject: [PATCH 058/517] net: dsa: b53: support legacy FCS tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 46c5176c586c ("net: dsa: b53: support legacy tags") introduced support for legacy tags, but it turns out that BCM5325 and BCM5365 switches require the original FCS value and length, so they have to be treated differently. Reviewed-by: Florian Fainelli Signed-off-by: Álvaro Fernández Rojas Link: https://patch.msgid.link/20250614080000.1884236-4-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/Kconfig | 1 + drivers/net/dsa/b53/b53_common.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/b53/Kconfig b/drivers/net/dsa/b53/Kconfig index ebaa4a80d544..915008e8eff5 100644 --- a/drivers/net/dsa/b53/Kconfig +++ b/drivers/net/dsa/b53/Kconfig @@ -5,6 +5,7 @@ menuconfig B53 select NET_DSA_TAG_NONE select NET_DSA_TAG_BRCM select NET_DSA_TAG_BRCM_LEGACY + select NET_DSA_TAG_BRCM_LEGACY_FCS select NET_DSA_TAG_BRCM_PREPEND help This driver adds support for Broadcom managed switch chips. It supports diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index d7a56dbc7d07..4291f2be7de4 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2285,8 +2285,11 @@ enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port, goto out; } - /* Older models require a different 6 byte tag */ - if (is5325(dev) || is5365(dev) || is63xx(dev)) { + /* Older models require different 6 byte tags */ + if (is5325(dev) || is5365(dev)) { + dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY_FCS; + goto out; + } else if (is63xx(dev)) { dev->tag_protocol = DSA_TAG_PROTO_BRCM_LEGACY; goto out; } -- 2.51.0 From 9341e0f0fe6412e8a855c2f0188d38091904152c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:50 +0200 Subject: [PATCH 059/517] net: dsa: b53: detect BCM5325 variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to be able to differentiate the BCM5325 variants because: - BCM5325M switches lack the ARLIO_PAGE->VLAN_ID_IDX register. - BCM5325E have less 512 ARL buckets instead of 1024. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250614080000.1884236-5-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 24 +++++++++++++++++++++--- drivers/net/dsa/b53/b53_priv.h | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 4291f2be7de4..1b4445d90612 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1816,7 +1816,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, /* Perform a read for the given MAC and VID */ b53_write48(dev, B53_ARLIO_PAGE, B53_MAC_ADDR_IDX, mac); - b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); + if (!is5325m(dev)) + b53_write16(dev, B53_ARLIO_PAGE, B53_VLAN_ID_IDX, vid); /* Issue a read operation for this MAC */ ret = b53_arl_rw_op(dev, 1); @@ -2884,6 +2885,9 @@ static int b53_switch_init(struct b53_device *dev) } } + if (is5325e(dev)) + dev->num_arl_buckets = 512; + dev->num_ports = fls(dev->enabled_ports); dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS); @@ -2985,10 +2989,24 @@ int b53_switch_detect(struct b53_device *dev) b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); - if (tmp == 0xf) + if (tmp == 0xf) { + u32 phy_id; + int val; + dev->chip_id = BCM5325_DEVICE_ID; - else + + val = b53_phy_read16(dev->ds, 0, MII_PHYSID1); + phy_id = (val & 0xffff) << 16; + val = b53_phy_read16(dev->ds, 0, MII_PHYSID2); + phy_id |= (val & 0xfff0); + + if (phy_id == 0x00406330) + dev->variant_id = B53_VARIANT_5325M; + else if (phy_id == 0x0143bc30) + dev->variant_id = B53_VARIANT_5325E; + } else { dev->chip_id = BCM5365_DEVICE_ID; + } break; case BCM5389_DEVICE_ID: case BCM5395_DEVICE_ID: diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 72f00f9e177c..6bf8f591cdc1 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -84,6 +84,12 @@ enum { BCM53134_DEVICE_ID = 0x5075, }; +enum b53_variant_id { + B53_VARIANT_NONE = 0, + B53_VARIANT_5325E, + B53_VARIANT_5325M, +}; + struct b53_pcs { struct phylink_pcs pcs; struct b53_device *dev; @@ -118,6 +124,7 @@ struct b53_device { /* chip specific data */ u32 chip_id; + enum b53_variant_id variant_id; u8 core_rev; u8 vta_regs[3]; u8 duplex_reg; @@ -165,6 +172,18 @@ static inline int is5325(struct b53_device *dev) return dev->chip_id == BCM5325_DEVICE_ID; } +static inline int is5325e(struct b53_device *dev) +{ + return is5325(dev) && + dev->variant_id == B53_VARIANT_5325E; +} + +static inline int is5325m(struct b53_device *dev) +{ + return is5325(dev) && + dev->variant_id == B53_VARIANT_5325M; +} + static inline int is5365(struct b53_device *dev) { #ifdef CONFIG_BCM47XX -- 2.51.0 From 3fccfaadb3356a5d30d38bcec04eca1ef60691c5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 14 Jun 2025 09:59:51 +0200 Subject: [PATCH 060/517] net: dsa: b53: add support for FDB operations on 5325/5365 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM5325 and BCM5365 are part of a much older generation of switches which, due to their limited number of ports and VLAN entries (up to 256) allowed a single 64-bit register to hold a full ARL entry. This requires a little bit of massaging when reading, writing and converting ARL entries in both directions. Signed-off-by: Florian Fainelli Signed-off-by: Álvaro Fernández Rojas Link: https://patch.msgid.link/20250614080000.1884236-6-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 101 +++++++++++++++++++++++++------ drivers/net/dsa/b53/b53_priv.h | 29 +++++++++ drivers/net/dsa/b53/b53_regs.h | 7 ++- 3 files changed, 115 insertions(+), 22 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 1b4445d90612..807c49880932 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1802,6 +1802,45 @@ static int b53_arl_read(struct b53_device *dev, u64 mac, return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; } +static int b53_arl_read_25(struct b53_device *dev, u64 mac, + u16 vid, struct b53_arl_entry *ent, u8 *idx) +{ + DECLARE_BITMAP(free_bins, B53_ARLTBL_MAX_BIN_ENTRIES); + unsigned int i; + int ret; + + ret = b53_arl_op_wait(dev); + if (ret) + return ret; + + bitmap_zero(free_bins, dev->num_arl_bins); + + /* Read the bins */ + for (i = 0; i < dev->num_arl_bins; i++) { + u64 mac_vid; + + b53_read64(dev, B53_ARLIO_PAGE, + B53_ARLTBL_MAC_VID_ENTRY(i), &mac_vid); + + b53_arl_to_entry_25(ent, mac_vid); + + if (!(mac_vid & ARLTBL_VALID_25)) { + set_bit(i, free_bins); + continue; + } + if ((mac_vid & ARLTBL_MAC_MASK) != mac) + continue; + if (dev->vlan_enabled && + ((mac_vid >> ARLTBL_VID_S_65) & ARLTBL_VID_MASK_25) != vid) + continue; + *idx = i; + return 0; + } + + *idx = find_first_bit(free_bins, dev->num_arl_bins); + return *idx >= dev->num_arl_bins ? -ENOSPC : -ENOENT; +} + static int b53_arl_op(struct b53_device *dev, int op, int port, const unsigned char *addr, u16 vid, bool is_valid) { @@ -1824,7 +1863,10 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, if (ret) return ret; - ret = b53_arl_read(dev, mac, vid, &ent, &idx); + if (is5325(dev) || is5365(dev)) + ret = b53_arl_read_25(dev, mac, vid, &ent, &idx); + else + ret = b53_arl_read(dev, mac, vid, &ent, &idx); /* If this is a read, just finish now */ if (op) @@ -1868,12 +1910,17 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, ent.is_static = true; ent.is_age = false; memcpy(ent.mac, addr, ETH_ALEN); - b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); + if (is5325(dev) || is5365(dev)) + b53_arl_from_entry_25(&mac_vid, &ent); + else + b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); b53_write64(dev, B53_ARLIO_PAGE, B53_ARLTBL_MAC_VID_ENTRY(idx), mac_vid); - b53_write32(dev, B53_ARLIO_PAGE, - B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); + + if (!is5325(dev) && !is5365(dev)) + b53_write32(dev, B53_ARLIO_PAGE, + B53_ARLTBL_DATA_ENTRY(idx), fwd_entry); return b53_arl_rw_op(dev, 0); } @@ -1885,12 +1932,6 @@ int b53_fdb_add(struct dsa_switch *ds, int port, struct b53_device *priv = ds->priv; int ret; - /* 5325 and 5365 require some more massaging, but could - * be supported eventually - */ - if (is5325(priv) || is5365(priv)) - return -EOPNOTSUPP; - mutex_lock(&priv->arl_mutex); ret = b53_arl_op(priv, 0, port, addr, vid, true); mutex_unlock(&priv->arl_mutex); @@ -1917,10 +1958,15 @@ EXPORT_SYMBOL(b53_fdb_del); static int b53_arl_search_wait(struct b53_device *dev) { unsigned int timeout = 1000; - u8 reg; + u8 reg, offset; + + if (is5325(dev) || is5365(dev)) + offset = B53_ARL_SRCH_CTL_25; + else + offset = B53_ARL_SRCH_CTL; do { - b53_read8(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, ®); + b53_read8(dev, B53_ARLIO_PAGE, offset, ®); if (!(reg & ARL_SRCH_STDN)) return 0; @@ -1937,13 +1983,24 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx, struct b53_arl_entry *ent) { u64 mac_vid; - u32 fwd_entry; - b53_read64(dev, B53_ARLIO_PAGE, - B53_ARL_SRCH_RSTL_MACVID(idx), &mac_vid); - b53_read32(dev, B53_ARLIO_PAGE, - B53_ARL_SRCH_RSTL(idx), &fwd_entry); - b53_arl_to_entry(ent, mac_vid, fwd_entry); + if (is5325(dev)) { + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_25, + &mac_vid); + b53_arl_to_entry_25(ent, mac_vid); + } else if (is5365(dev)) { + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_0_MACVID_65, + &mac_vid); + b53_arl_to_entry_25(ent, mac_vid); + } else { + u32 fwd_entry; + + b53_read64(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL_MACVID(idx), + &mac_vid); + b53_read32(dev, B53_ARLIO_PAGE, B53_ARL_SRCH_RSTL(idx), + &fwd_entry); + b53_arl_to_entry(ent, mac_vid, fwd_entry); + } } static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, @@ -1964,14 +2021,20 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, struct b53_device *priv = ds->priv; struct b53_arl_entry results[2]; unsigned int count = 0; + u8 offset; int ret; u8 reg; mutex_lock(&priv->arl_mutex); + if (is5325(priv) || is5365(priv)) + offset = B53_ARL_SRCH_CTL_25; + else + offset = B53_ARL_SRCH_CTL; + /* Start search operation */ reg = ARL_SRCH_STDN; - b53_write8(priv, B53_ARLIO_PAGE, B53_ARL_SRCH_CTL, reg); + b53_write8(priv, offset, B53_ARL_SRCH_CTL, reg); do { ret = b53_arl_search_wait(priv); diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 6bf8f591cdc1..3e8204c7c02e 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -317,6 +317,19 @@ static inline void b53_arl_to_entry(struct b53_arl_entry *ent, ent->vid = mac_vid >> ARLTBL_VID_S; } +static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent, + u64 mac_vid) +{ + memset(ent, 0, sizeof(*ent)); + ent->port = (mac_vid >> ARLTBL_DATA_PORT_ID_S_25) & + ARLTBL_DATA_PORT_ID_MASK_25; + ent->is_valid = !!(mac_vid & ARLTBL_VALID_25); + ent->is_age = !!(mac_vid & ARLTBL_AGE_25); + ent->is_static = !!(mac_vid & ARLTBL_STATIC_25); + u64_to_ether_addr(mac_vid, ent->mac); + ent->vid = mac_vid >> ARLTBL_VID_S_65; +} + static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, const struct b53_arl_entry *ent) { @@ -331,6 +344,22 @@ static inline void b53_arl_from_entry(u64 *mac_vid, u32 *fwd_entry, *fwd_entry |= ARLTBL_AGE; } +static inline void b53_arl_from_entry_25(u64 *mac_vid, + const struct b53_arl_entry *ent) +{ + *mac_vid = ether_addr_to_u64(ent->mac); + *mac_vid |= (u64)(ent->port & ARLTBL_DATA_PORT_ID_MASK_25) << + ARLTBL_DATA_PORT_ID_S_25; + *mac_vid |= (u64)(ent->vid & ARLTBL_VID_MASK_25) << + ARLTBL_VID_S_65; + if (ent->is_valid) + *mac_vid |= ARLTBL_VALID_25; + if (ent->is_static) + *mac_vid |= ARLTBL_STATIC_25; + if (ent->is_age) + *mac_vid |= ARLTBL_AGE_25; +} + #ifdef CONFIG_BCM47XX #include diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index f2caf8fe5699..b6ef32d481ca 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -329,9 +329,10 @@ #define ARLTBL_VID_MASK 0xfff #define ARLTBL_DATA_PORT_ID_S_25 48 #define ARLTBL_DATA_PORT_ID_MASK_25 0xf -#define ARLTBL_AGE_25 BIT(61) -#define ARLTBL_STATIC_25 BIT(62) -#define ARLTBL_VALID_25 BIT(63) +#define ARLTBL_VID_S_65 53 +#define ARLTBL_AGE_25 BIT_ULL(61) +#define ARLTBL_STATIC_25 BIT_ULL(62) +#define ARLTBL_VALID_25 BIT_ULL(63) /* ARL Table Data Entry N Registers (32 bit) */ #define B53_ARLTBL_DATA_ENTRY(n) ((0x10 * (n)) + 0x18) -- 2.51.0 From ca4b9423fc2d29191875ce73e57afc26bfd12194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:52 +0200 Subject: [PATCH 061/517] net: dsa: b53: prevent FAST_AGE access on BCM5325 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM5325 doesn't implement FAST_AGE registers so we should avoid reading or writing them. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250614080000.1884236-7-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 807c49880932..8606eabcaaa8 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -492,6 +492,9 @@ static int b53_flush_arl(struct b53_device *dev, u8 mask) { unsigned int i; + if (is5325(dev)) + return 0; + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask); @@ -516,6 +519,9 @@ static int b53_flush_arl(struct b53_device *dev, u8 mask) static int b53_fast_age_port(struct b53_device *dev, int port) { + if (is5325(dev)) + return 0; + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_PORT_CTRL, port); return b53_flush_arl(dev, FAST_AGE_PORT); @@ -523,6 +529,9 @@ static int b53_fast_age_port(struct b53_device *dev, int port) static int b53_fast_age_vlan(struct b53_device *dev, u16 vid) { + if (is5325(dev)) + return 0; + b53_write16(dev, B53_CTRL_PAGE, B53_FAST_AGE_VID_CTRL, vid); return b53_flush_arl(dev, FAST_AGE_VLAN); -- 2.51.0 From 3d97487faefb90c06ad9e3d5b52d2f4c80bf96a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:56 +0200 Subject: [PATCH 062/517] net: dsa: b53: prevent BRCM_HDR access on older devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older switches don't implement BRCM_HDR register so we should avoid reading or writing it. Reviewed-by: Florian Fainelli Signed-off-by: Álvaro Fernández Rojas Link: https://patch.msgid.link/20250614080000.1884236-11-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 8606eabcaaa8..f3c01ac88e3a 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -747,6 +747,11 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port) hdr_ctl |= GC_FRM_MGMT_PORT_M; b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, hdr_ctl); + /* B53_BRCM_HDR not present on devices with legacy tags */ + if (dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY || + dev->tag_protocol == DSA_TAG_PROTO_BRCM_LEGACY_FCS) + return; + /* Enable Broadcom tags for IMP port */ b53_read8(dev, B53_MGMT_PAGE, B53_BRCM_HDR, &hdr_ctl); if (tag_en) -- 2.51.0 From 1f5369fdb49ca6051756ed11be3600e0c3535e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 14 Jun 2025 09:59:58 +0200 Subject: [PATCH 063/517] net: dsa: b53: fix unicast/multicast flooding on BCM5325 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM5325 doesn't implement UC_FLOOD_MASK, MC_FLOOD_MASK and IPMC_FLOOD_MASK registers. This has to be handled differently with other pages and registers. Signed-off-by: Álvaro Fernández Rojas Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20250614080000.1884236-13-noltari@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 60 ++++++++++++++++++++++---------- drivers/net/dsa/b53/b53_regs.h | 13 +++++++ 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index f3c01ac88e3a..051d9504b0de 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -564,12 +564,24 @@ static void b53_port_set_ucast_flood(struct b53_device *dev, int port, { u16 uc; - b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); - if (unicast) - uc |= BIT(port); - else - uc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); + if (is5325(dev)) { + if (port == B53_CPU_PORT_25) + port = B53_CPU_PORT; + + b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, &uc); + if (unicast) + uc |= BIT(port) | B53_IEEE_UCAST_DROP_EN; + else + uc &= ~BIT(port); + b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_UCAST_DLF, uc); + } else { + b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); + if (unicast) + uc |= BIT(port); + else + uc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); + } } static void b53_port_set_mcast_flood(struct b53_device *dev, int port, @@ -577,19 +589,31 @@ static void b53_port_set_mcast_flood(struct b53_device *dev, int port, { u16 mc; - b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); - if (multicast) - mc |= BIT(port); - else - mc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); + if (is5325(dev)) { + if (port == B53_CPU_PORT_25) + port = B53_CPU_PORT; - b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); - if (multicast) - mc |= BIT(port); - else - mc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); + b53_read16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, &mc); + if (multicast) + mc |= BIT(port) | B53_IEEE_MCAST_DROP_EN; + else + mc &= ~BIT(port); + b53_write16(dev, B53_IEEE_PAGE, B53_IEEE_MCAST_DLF, mc); + } else { + b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); + if (multicast) + mc |= BIT(port); + else + mc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); + + b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); + if (multicast) + mc |= BIT(port); + else + mc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); + } } static void b53_port_set_learning(struct b53_device *dev, int port, diff --git a/drivers/net/dsa/b53/b53_regs.h b/drivers/net/dsa/b53/b53_regs.h index b6ef32d481ca..309fe0e46dad 100644 --- a/drivers/net/dsa/b53/b53_regs.h +++ b/drivers/net/dsa/b53/b53_regs.h @@ -29,6 +29,7 @@ #define B53_ARLIO_PAGE 0x05 /* ARL Access */ #define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ #define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ +#define B53_IEEE_PAGE 0x0a /* IEEE 802.1X */ /* PHY Registers */ #define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ @@ -371,6 +372,18 @@ #define B53_ARL_SRCH_RSTL_MACVID(x) (B53_ARL_SRCH_RSTL_0_MACVID + ((x) * 0x10)) #define B53_ARL_SRCH_RSTL(x) (B53_ARL_SRCH_RSTL_0 + ((x) * 0x10)) +/************************************************************************* + * IEEE 802.1X Registers + *************************************************************************/ + +/* Multicast DLF Drop Control register (16 bit) */ +#define B53_IEEE_MCAST_DLF 0x94 +#define B53_IEEE_MCAST_DROP_EN BIT(11) + +/* Unicast DLF Drop Control register (16 bit) */ +#define B53_IEEE_UCAST_DLF 0x96 +#define B53_IEEE_UCAST_DROP_EN BIT(11) + /************************************************************************* * Port VLAN Registers *************************************************************************/ -- 2.51.0 From ca931dc100c6aa5d9857b962ed84febb44c3b8d1 Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Sat, 1 Mar 2025 21:55:16 +0800 Subject: [PATCH 064/517] ppp: use IFF_NO_QUEUE in virtual interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For PPPoE, PPTP, and PPPoL2TP, the start_xmit() function directly forwards packets to the underlying network stack and never returns anything other than 1. So these interfaces do not require a qdisc, and the IFF_NO_QUEUE flag should be set. Introduces a direct_xmit flag in struct ppp_channel to indicate when IFF_NO_QUEUE should be applied. The flag is set in ppp_connect_channel() for relevant protocols. While at it, remove the usused latency member from struct ppp_channel. Signed-off-by: Qingfang Deng Reviewed-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20250301135517.695809-1-dqfext@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ppp/ppp_generic.c | 4 ++++ drivers/net/ppp/pppoe.c | 1 + drivers/net/ppp/pptp.c | 1 + include/linux/ppp_channel.h | 3 +-- net/l2tp/l2tp_ppp.c | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index afc1566488b3..9b8ddf644ac3 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -3504,6 +3504,10 @@ ppp_connect_channel(struct channel *pch, int unit) ret = -ENOTCONN; goto outl; } + if (pch->chan->direct_xmit) + ppp->dev->priv_flags |= IFF_NO_QUEUE; + else + ppp->dev->priv_flags &= ~IFF_NO_QUEUE; spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 2ea4f4890d23..68e631718ab0 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -693,6 +693,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; po->chan.private = sk; po->chan.ops = &pppoe_chan_ops; + po->chan.direct_xmit = true; error = ppp_register_net_channel(dev_net(dev), &po->chan); if (error) { diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index cec3bb22471b..90737cb71892 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -469,6 +469,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); + po->chan.direct_xmit = true; error = ppp_register_channel(&po->chan); if (error) { pr_err("PPTP: failed to register PPP channel (%d)\n", error); diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h index 45e6e427ceb8..f73fbea0dbc2 100644 --- a/include/linux/ppp_channel.h +++ b/include/linux/ppp_channel.h @@ -42,8 +42,7 @@ struct ppp_channel { int hdrlen; /* amount of headroom channel needs */ void *ppp; /* opaque to channel */ int speed; /* transfer rate (bytes/second) */ - /* the following is not used at present */ - int latency; /* overhead time in milliseconds */ + bool direct_xmit; /* no qdisc, xmit directly */ }; #ifdef __KERNEL__ diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 16c514f628ea..5e12e7ce17d8 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -796,6 +796,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.private = sk; po->chan.ops = &pppol2tp_chan_ops; po->chan.mtu = pppol2tp_tunnel_mtu(tunnel); + po->chan.direct_xmit = true; error = ppp_register_net_channel(sock_net(sk), &po->chan); if (error) { -- 2.51.0 From 1bdc62e6e933d77990348c17ebbff861f37e160a Mon Sep 17 00:00:00 2001 From: Shengyu Qu Date: Mon, 14 Apr 2025 18:56:01 +0800 Subject: [PATCH 065/517] net: bridge: locally receive all multicast packets if IFF_ALLMULTI is set If multicast snooping is enabled, multicast packets may not always end up on the local bridge interface, if the host is not a member of the multicast group. Similar to how IFF_PROMISC allows all packets to be received locally, let IFF_ALLMULTI allow all multicast packets to be received. OpenWrt uses a user space daemon for DHCPv6/RA/NDP handling, and in relay mode it sets the ALLMULTI flag in order to receive all relevant queries on the network. This works for normal network interfaces and non-snooping bridges, but not snooping bridges (unless multicast routing is enabled). Reported-by: Felix Fietkau Closes: https://github.com/openwrt/openwrt/issues/15857#issuecomment-2662851243 Signed-off-by: Shengyu Qu Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Link: https://patch.msgid.link/OSZPR01MB8434308370ACAFA90A22980798B32@OSZPR01MB8434.jpnprd01.prod.outlook.com Signed-off-by: Jakub Kicinski --- net/bridge/br_input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index ceaa5a89b947..c059e5657db3 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -184,7 +184,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) { if ((mdst && mdst->host_joined) || - br_multicast_is_router(brmctx, skb)) { + br_multicast_is_router(brmctx, skb) || + br->dev->flags & IFF_ALLMULTI) { local_rcv = true; DEV_STATS_INC(br->dev, multicast); } -- 2.51.0 From a0238cb711e97c201f11e6686882562dab61e6d4 Mon Sep 17 00:00:00 2001 From: Rui Salvaterra Date: Wed, 5 Mar 2025 11:53:56 +0000 Subject: [PATCH 066/517] igc: enable HW vlan tag insertion/stripping by default This is enabled by default in other Intel drivers I've checked (e1000, e1000e, iavf, igb and ice). Fixes an out-of-the-box performance issue when running OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q VLAN configurations, as ethtool isn't part of the default packages and sane defaults are expected. In my specific case, with an Intel N100-based machine with four I226-V Ethernet controllers, my upload performance increased from under 30 Mb/s to the expected ~1 Gb/s. Signed-off-by: Rui Salvaterra --- drivers/net/ethernet/intel/igc/igc_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 9ba41a427e14..cbe751d963bc 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7070,6 +7070,9 @@ static int igc_probe(struct pci_dev *pdev, netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_XSK_ZEROCOPY; + /* enable HW vlan tag insertion/stripping by default */ + netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + /* MTU range: 68 - 9216 */ netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; -- 2.51.0 From d358cb92d517772c5cf4267a1ecf504178bd5439 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 17 Oct 2024 11:22:11 +0800 Subject: [PATCH 067/517] net: phy: mediatek-ge-soc: Fix coding style This patch fixes spelling errors, re-arrange vars with reverse Xmas tree and remove unnecessary parens in mediatek-ge-soc.c. Signed-off-by: SkyLake.Huang Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn --- drivers/net/phy/mediatek-ge-soc.c | 36 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c index f4f9412d0cd7..e9c422f4e24b 100644 --- a/drivers/net/phy/mediatek-ge-soc.c +++ b/drivers/net/phy/mediatek-ge-soc.c @@ -408,16 +408,17 @@ static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) { - int i; - int bias[16] = {}; - const int vals_9461[16] = { 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7 }; const int vals_9481[16] = { 10, 6, 6, 10, 10, 6, 6, 10, 10, 6, 6, 10, 10, 6, 6, 10 }; + const int vals_9461[16] = { 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7 }; + int bias[16] = {}; + int i; + switch (phydev->drv->phy_id) { case MTK_GPHY_ID_MT7981: /* We add some calibration to efuse values @@ -1069,10 +1070,10 @@ static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, static int mt798x_phy_calibration(struct phy_device *phydev) { + struct nvmem_cell *cell; int ret = 0; - u32 *buf; size_t len; - struct nvmem_cell *cell; + u32 *buf; cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); if (IS_ERR(cell)) { @@ -1210,14 +1211,15 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev, return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF)); } -static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | - BIT(TRIGGER_NETDEV_HALF_DUPLEX) | - BIT(TRIGGER_NETDEV_LINK) | - BIT(TRIGGER_NETDEV_LINK_10) | - BIT(TRIGGER_NETDEV_LINK_100) | - BIT(TRIGGER_NETDEV_LINK_1000) | - BIT(TRIGGER_NETDEV_RX) | - BIT(TRIGGER_NETDEV_TX)); +static const unsigned long supported_triggers = + BIT(TRIGGER_NETDEV_FULL_DUPLEX) | + BIT(TRIGGER_NETDEV_HALF_DUPLEX) | + BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX); static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules) @@ -1415,7 +1417,7 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) * LED_C and LED_D respectively. At the same time those pins are used to * bootstrap configuration of the reference clock source (LED_A), * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D). - * In practise this is done using a LED and a resistor pulling the pin + * In practice this is done using a LED and a resistor pulling the pin * either to GND or to VIO. * The detected value at boot time is accessible at run-time using the * TPBANK0 register located in the gpio base of the pinctrl, in order -- 2.51.0 From 450ae2beafadb9d3a78227c4c882e9635a55b0f3 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 17 Oct 2024 11:22:12 +0800 Subject: [PATCH 068/517] net: phy: mediatek-ge-soc: Shrink line wrapping to 80 characters This patch shrinks line wrapping to 80 chars. Also, in tx_amp_fill_result(), use FIELD_PREP() to prettify code. Signed-off-by: SkyLake.Huang Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn --- drivers/net/phy/mediatek-ge-soc.c | 125 +++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 37 deletions(-) diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c index e9c422f4e24b..1d7719b6c351 100644 --- a/drivers/net/phy/mediatek-ge-soc.c +++ b/drivers/net/phy/mediatek-ge-soc.c @@ -342,7 +342,8 @@ static int cal_cycle(struct phy_device *phydev, int devad, ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_CLK, reg_val, reg_val & MTK_PHY_DA_CAL_CLK, 500, - ANALOG_INTERNAL_OPERATION_MAX_US, false); + ANALOG_INTERNAL_OPERATION_MAX_US, + false); if (ret) { phydev_err(phydev, "Calibration cycle timeout\n"); return ret; @@ -441,40 +442,72 @@ static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) } phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, - MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); + MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, + buf[0] + bias[0])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, - MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); + MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, + buf[0] + bias[1])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, - MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); + MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, + buf[0] + bias[2])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, - MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); + MTK_PHY_DA_TX_I2MPB_A_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK, + buf[0] + bias[3])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, - MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); + MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, + buf[1] + bias[4])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, - MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); + MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, + buf[1] + bias[5])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, - MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); + MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, + buf[1] + bias[6])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, - MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); + MTK_PHY_DA_TX_I2MPB_B_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK, + buf[1] + bias[7])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, - MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); + MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, + buf[2] + bias[8])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, - MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); + MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, + buf[2] + bias[9])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, - MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); + MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, + buf[2] + bias[10])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, - MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); + MTK_PHY_DA_TX_I2MPB_C_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK, + buf[2] + bias[11])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, - MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); + MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, + buf[3] + bias[12])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, - MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); + MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, + buf[3] + bias[13])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, - MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); + MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, + buf[3] + bias[14])); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, - MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); + MTK_PHY_DA_TX_I2MPB_D_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK, + buf[3] + bias[15])); return 0; } @@ -663,7 +696,8 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) goto restore; /* We calibrate TX-VCM in different logic. Check upper index and then - * lower index. If this calibration is valid, apply lower index's result. + * lower index. If this calibration is valid, apply lower index's + * result. */ ret = upper_ret - lower_ret; if (ret == 1) { @@ -692,7 +726,8 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && lower_ret == 0) { ret = 0; - phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n", + phydev_warn(phydev, + "TX-VCM SW cal result at high margin 0x%x\n", upper_idx); } else { ret = -EINVAL; @@ -796,7 +831,8 @@ static void mt7981_phy_finetune(struct phy_device *phydev) /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, - MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | + MTK_PHY_LPF_X_AVERAGE_MASK, BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); /* rg_tr_lpf_cnt_val = 512 */ @@ -865,7 +901,8 @@ static void mt7988_phy_finetune(struct phy_device *phydev) /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, - MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | + MTK_PHY_LPF_X_AVERAGE_MASK, BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa)); /* rg_tr_lpf_cnt_val = 1023 */ @@ -977,7 +1014,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); - __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK, + __phy_modify(phydev, MTK_PHY_LPI_REG_14, + MTK_PHY_LPI_WAKE_TIMER_1000_MASK, FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, @@ -987,7 +1025,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, - FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff)); + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + 0xff)); } static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, @@ -1147,7 +1186,8 @@ static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, (index ? 16 : 0), &priv->led_state); if (changed) return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED1_ON_CTRL : + MTK_PHY_LED0_ON_CTRL, MTK_PHY_LED_ON_MASK, on ? MTK_PHY_LED_ON_FORCE_ON : 0); else @@ -1157,7 +1197,8 @@ static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking) { - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); struct mtk_socphy_priv *priv = phydev->priv; bool changed; @@ -1170,8 +1211,10 @@ static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, (index ? 16 : 0), &priv->led_state); if (changed) return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL, - blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0); + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, + blinking ? + MTK_PHY_LED_BLINK_FORCE_BLINK : 0); else return 0; } @@ -1237,7 +1280,8 @@ static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, unsigned long *rules) { - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); struct mtk_socphy_priv *priv = phydev->priv; @@ -1258,8 +1302,8 @@ static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, if (blink < 0) return -EIO; - if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | - MTK_PHY_LED_ON_LINKDOWN)) || + if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | + MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX))) set_bit(bit_netdev, &priv->led_state); else @@ -1333,17 +1377,23 @@ static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, if (rules & BIT(TRIGGER_NETDEV_RX)) { blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) : + (((on & MTK_PHY_LED_ON_LINK10) ? + MTK_PHY_LED_BLINK_10RX : 0) | + ((on & MTK_PHY_LED_ON_LINK100) ? + MTK_PHY_LED_BLINK_100RX : 0) | + ((on & MTK_PHY_LED_ON_LINK1000) ? + MTK_PHY_LED_BLINK_1000RX : 0)) : MTK_PHY_LED_BLINK_RX; } if (rules & BIT(TRIGGER_NETDEV_TX)) { blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) : + (((on & MTK_PHY_LED_ON_LINK10) ? + MTK_PHY_LED_BLINK_10TX : 0) | + ((on & MTK_PHY_LED_ON_LINK100) ? + MTK_PHY_LED_BLINK_100TX : 0) | + ((on & MTK_PHY_LED_ON_LINK1000) ? + MTK_PHY_LED_BLINK_1000TX : 0)) : MTK_PHY_LED_BLINK_TX; } @@ -1400,7 +1450,8 @@ static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev) /* Only now setup pinctrl to avoid bogus blinking */ pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); if (IS_ERR(pinctrl)) - dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n"); + dev_err(&phydev->mdio.bus->dev, + "Failed to setup PHY LED pinctrl\n"); return 0; } -- 2.51.0 From 2c093d2f19967ec88a8f318d63fbad315b3435df Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 17 Oct 2024 11:22:13 +0800 Subject: [PATCH 069/517] net: phy: mediatek-ge-soc: Propagate error code correctly in cal_cycle() This patch propagates error code correctly in cal_cycle() and improve with FIELD_GET(). Signed-off-by: SkyLake.Huang Reviewed-by: Simon Horman Signed-off-by: Andrew Lunn --- drivers/net/phy/mediatek-ge-soc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c index 1d7719b6c351..a931832b1418 100644 --- a/drivers/net/phy/mediatek-ge-soc.c +++ b/drivers/net/phy/mediatek-ge-soc.c @@ -110,7 +110,7 @@ #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) #define MTK_PHY_RG_AD_CAL_COMP 0x17a -#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) +#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8) #define MTK_PHY_RG_AD_CAL_CLK 0x17b #define MTK_PHY_DA_CAL_CLK BIT(0) @@ -351,8 +351,10 @@ static int cal_cycle(struct phy_device *phydev, int devad, phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, MTK_PHY_DA_CALIN_FLAG); - ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> - MTK_PHY_AD_CAL_COMP_OUT_SHIFT; + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP); + if (ret < 0) + return ret; + ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret); phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); return ret; -- 2.51.0 From d0e33fc271ee343d7da7e84dbbc07e3999b2b5af Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Sat, 9 Nov 2024 00:34:51 +0800 Subject: [PATCH 070/517] net: phy: mediatek: Re-organize MediaTek ethernet phy drivers Re-organize MediaTek ethernet phy driver files and get ready to integrate some common functions and add new 2.5G phy driver. mtk-ge.c: MT7530 Gphy on MT7621 & MT7531 Gphy mtk-ge-soc.c: Built-in Gphy on MT7981 & Built-in switch Gphy on MT7988 mtk-2p5ge.c: Planned for built-in 2.5G phy on MT7988 Reviewed-by: Andrew Lunn Signed-off-by: SkyLake.Huang Signed-off-by: David S. Miller --- MAINTAINERS | 4 ++-- drivers/net/phy/Kconfig | 17 +------------- drivers/net/phy/Makefile | 3 +-- drivers/net/phy/mediatek/Kconfig | 22 +++++++++++++++++++ drivers/net/phy/mediatek/Makefile | 3 +++ .../mtk-ge-soc.c} | 0 .../phy/{mediatek-ge.c => mediatek/mtk-ge.c} | 0 7 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 drivers/net/phy/mediatek/Kconfig create mode 100644 drivers/net/phy/mediatek/Makefile rename drivers/net/phy/{mediatek-ge-soc.c => mediatek/mtk-ge-soc.c} (100%) rename drivers/net/phy/{mediatek-ge.c => mediatek/mtk-ge.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index d0f18fdba068..7aab943889e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14427,8 +14427,8 @@ M: Qingfang Deng M: SkyLake Huang L: netdev@vger.kernel.org S: Maintained -F: drivers/net/phy/mediatek-ge-soc.c -F: drivers/net/phy/mediatek-ge.c +F: drivers/net/phy/mediatek/mtk-ge-soc.c +F: drivers/net/phy/mediatek/mtk-ge.c F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c MEDIATEK I2C CONTROLLER DRIVER diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 01b235b3bb7e..4e78a4d8fd2a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -266,22 +266,7 @@ config MAXLINEAR_GPHY Support for the Maxlinear GPY115, GPY211, GPY212, GPY215, GPY241, GPY245 PHYs. -config MEDIATEK_GE_PHY - tristate "MediaTek Gigabit Ethernet PHYs" - help - Supports the MediaTek Gigabit Ethernet PHYs. - -config MEDIATEK_GE_SOC_PHY - tristate "MediaTek SoC Ethernet PHYs" - depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST - depends on NVMEM_MTK_EFUSE - help - Supports MediaTek SoC built-in Gigabit Ethernet PHYs. - - Include support for built-in Ethernet PHYs which are present in - the MT7981 and MT7988 SoCs. These PHYs need calibration data - present in the SoCs efuse and will dynamically calibrate VCM - (common-mode voltage) during startup. +source "drivers/net/phy/mediatek/Kconfig" config MICREL_PHY tristate "Micrel PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 90f886844381..e6145153e837 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o -obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o -obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o +obj-y += mediatek/ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig new file mode 100644 index 000000000000..112d9c0f219c --- /dev/null +++ b/drivers/net/phy/mediatek/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +config MEDIATEK_GE_PHY + tristate "MediaTek Gigabit Ethernet PHYs" + help + Supports the MediaTek non-built-in Gigabit Ethernet PHYs. + + Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531. + You may find mt7530 inside mt7621. This driver shares some + common operations with MediaTek SoC built-in Gigabit + Ethernet PHYs. + +config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + depends on NVMEM_MTK_EFUSE + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. + + Include support for built-in Ethernet PHYs which are present in + the MT7981 and MT7988 SoCs. These PHYs need calibration data + present in the SoCs efuse and will dynamically calibrate VCM + (common-mode voltage) during startup. diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile new file mode 100644 index 000000000000..005bde26c1d7 --- /dev/null +++ b/drivers/net/phy/mediatek/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o +obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c similarity index 100% rename from drivers/net/phy/mediatek-ge-soc.c rename to drivers/net/phy/mediatek/mtk-ge-soc.c diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek/mtk-ge.c similarity index 100% rename from drivers/net/phy/mediatek-ge.c rename to drivers/net/phy/mediatek/mtk-ge.c -- 2.51.0 From fcd36b51e49bdef0ba98bc6e63df359b475f2870 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Sat, 9 Nov 2024 00:34:52 +0800 Subject: [PATCH 071/517] net: phy: mediatek: Move LED helper functions into mtk phy lib This patch creates mtk-phy-lib.c & mtk-phy.h and integrates mtk-ge-soc.c's LED helper functions so that we can use those helper functions in other MTK's ethernet phy driver. Reviewed-by: Andrew Lunn Signed-off-by: SkyLake.Huang Signed-off-by: David S. Miller --- MAINTAINERS | 2 + drivers/net/phy/mediatek/Kconfig | 4 + drivers/net/phy/mediatek/Makefile | 1 + drivers/net/phy/mediatek/mtk-ge-soc.c | 280 +++---------------------- drivers/net/phy/mediatek/mtk-phy-lib.c | 254 ++++++++++++++++++++++ drivers/net/phy/mediatek/mtk.h | 86 ++++++++ 6 files changed, 372 insertions(+), 255 deletions(-) create mode 100644 drivers/net/phy/mediatek/mtk-phy-lib.c create mode 100644 drivers/net/phy/mediatek/mtk.h diff --git a/MAINTAINERS b/MAINTAINERS index 7aab943889e0..7d694e7b4f42 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14428,7 +14428,9 @@ M: SkyLake Huang L: netdev@vger.kernel.org S: Maintained F: drivers/net/phy/mediatek/mtk-ge-soc.c +F: drivers/net/phy/mediatek/mtk-phy-lib.c F: drivers/net/phy/mediatek/mtk-ge.c +F: drivers/net/phy/mediatek/mtk.h F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c MEDIATEK I2C CONTROLLER DRIVER diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index 112d9c0f219c..19b5d23e7cd0 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only +config MTK_NET_PHYLIB + tristate + config MEDIATEK_GE_PHY tristate "MediaTek Gigabit Ethernet PHYs" help @@ -13,6 +16,7 @@ config MEDIATEK_GE_SOC_PHY tristate "MediaTek SoC Ethernet PHYs" depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST depends on NVMEM_MTK_EFUSE + select MTK_NET_PHYLIB help Supports MediaTek SoC built-in Gigabit Ethernet PHYs. diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile index 005bde26c1d7..814879d0abe5 100644 --- a/drivers/net/phy/mediatek/Makefile +++ b/drivers/net/phy/mediatek/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index a931832b1418..d3a8b3946056 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -8,6 +8,8 @@ #include #include +#include "mtk.h" + #define MTK_GPHY_ID_MT7981 0x03a29461 #define MTK_GPHY_ID_MT7988 0x03a29481 @@ -210,41 +212,6 @@ #define MTK_PHY_DA_TX_R50_PAIR_D 0x540 /* Registers on MDIO_MMD_VEND2 */ -#define MTK_PHY_LED0_ON_CTRL 0x24 -#define MTK_PHY_LED1_ON_CTRL 0x26 -#define MTK_PHY_LED_ON_MASK GENMASK(6, 0) -#define MTK_PHY_LED_ON_LINK1000 BIT(0) -#define MTK_PHY_LED_ON_LINK100 BIT(1) -#define MTK_PHY_LED_ON_LINK10 BIT(2) -#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\ - MTK_PHY_LED_ON_LINK100 |\ - MTK_PHY_LED_ON_LINK1000) -#define MTK_PHY_LED_ON_LINKDOWN BIT(3) -#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ -#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ -#define MTK_PHY_LED_ON_FORCE_ON BIT(6) -#define MTK_PHY_LED_ON_POLARITY BIT(14) -#define MTK_PHY_LED_ON_ENABLE BIT(15) - -#define MTK_PHY_LED0_BLINK_CTRL 0x25 -#define MTK_PHY_LED1_BLINK_CTRL 0x27 -#define MTK_PHY_LED_BLINK_1000TX BIT(0) -#define MTK_PHY_LED_BLINK_1000RX BIT(1) -#define MTK_PHY_LED_BLINK_100TX BIT(2) -#define MTK_PHY_LED_BLINK_100RX BIT(3) -#define MTK_PHY_LED_BLINK_10TX BIT(4) -#define MTK_PHY_LED_BLINK_10RX BIT(5) -#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\ - MTK_PHY_LED_BLINK_100RX |\ - MTK_PHY_LED_BLINK_1000RX) -#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\ - MTK_PHY_LED_BLINK_100TX |\ - MTK_PHY_LED_BLINK_1000TX) -#define MTK_PHY_LED_BLINK_COLLISION BIT(6) -#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) -#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) -#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) - #define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1) #define MTK_PHY_RG_BG_RASEL 0x115 @@ -299,14 +266,6 @@ enum CAL_MODE { SW_M }; -#define MTK_PHY_LED_STATE_FORCE_ON 0 -#define MTK_PHY_LED_STATE_FORCE_BLINK 1 -#define MTK_PHY_LED_STATE_NETDEV 2 - -struct mtk_socphy_priv { - unsigned long led_state; -}; - struct mtk_socphy_shared { u32 boottrap; struct mtk_socphy_priv priv[4]; @@ -1172,76 +1131,23 @@ static int mt798x_phy_config_init(struct phy_device *phydev) return mt798x_phy_calibration(phydev); } -static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, - bool on) -{ - unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - bool changed; - - if (on) - changed = !test_and_set_bit(bit_on, &priv->led_state); - else - changed = !!test_and_clear_bit(bit_on, &priv->led_state); - - changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + - (index ? 16 : 0), &priv->led_state); - if (changed) - return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : - MTK_PHY_LED0_ON_CTRL, - MTK_PHY_LED_ON_MASK, - on ? MTK_PHY_LED_ON_FORCE_ON : 0); - else - return 0; -} - -static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, - bool blinking) -{ - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + - (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - bool changed; - - if (blinking) - changed = !test_and_set_bit(bit_blink, &priv->led_state); - else - changed = !!test_and_clear_bit(bit_blink, &priv->led_state); - - changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + - (index ? 16 : 0), &priv->led_state); - if (changed) - return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_BLINK_CTRL : - MTK_PHY_LED0_BLINK_CTRL, - blinking ? - MTK_PHY_LED_BLINK_FORCE_BLINK : 0); - else - return 0; -} - static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index, unsigned long *delay_on, unsigned long *delay_off) { bool blinking = false; - int err = 0; - - if (index > 1) - return -EINVAL; + int err; - if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { - blinking = true; - *delay_on = 50; - *delay_off = 50; - } + err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking); + if (err < 0) + return err; - err = mt798x_phy_hw_led_blink_set(phydev, index, blinking); + err = mtk_phy_hw_led_blink_set(phydev, index, blinking); if (err) return err; - return mt798x_phy_hw_led_on_set(phydev, index, false); + return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, + false); } static int mt798x_phy_led_brightness_set(struct phy_device *phydev, @@ -1249,11 +1155,12 @@ static int mt798x_phy_led_brightness_set(struct phy_device *phydev, { int err; - err = mt798x_phy_hw_led_blink_set(phydev, index, false); + err = mtk_phy_hw_led_blink_set(phydev, index, false); if (err) return err; - return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF)); + return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, + (value != LED_OFF)); } static const unsigned long supported_triggers = @@ -1269,155 +1176,26 @@ static const unsigned long supported_triggers = static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules) { - if (index > 1) - return -EINVAL; - - /* All combinations of the supported triggers are allowed */ - if (rules & ~supported_triggers) - return -EOPNOTSUPP; - - return 0; -}; + return mtk_phy_led_hw_is_supported(phydev, index, rules, + supported_triggers); +} static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, unsigned long *rules) { - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + - (index ? 16 : 0); - unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); - unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - int on, blink; - - if (index > 1) - return -EINVAL; - - on = phy_read_mmd(phydev, MDIO_MMD_VEND2, - index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); - - if (on < 0) - return -EIO; - - blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, - index ? MTK_PHY_LED1_BLINK_CTRL : - MTK_PHY_LED0_BLINK_CTRL); - if (blink < 0) - return -EIO; - - if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | - MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || - (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX))) - set_bit(bit_netdev, &priv->led_state); - else - clear_bit(bit_netdev, &priv->led_state); - - if (on & MTK_PHY_LED_ON_FORCE_ON) - set_bit(bit_on, &priv->led_state); - else - clear_bit(bit_on, &priv->led_state); - - if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) - set_bit(bit_blink, &priv->led_state); - else - clear_bit(bit_blink, &priv->led_state); - - if (!rules) - return 0; - - if (on & MTK_PHY_LED_ON_LINK) - *rules |= BIT(TRIGGER_NETDEV_LINK); - - if (on & MTK_PHY_LED_ON_LINK10) - *rules |= BIT(TRIGGER_NETDEV_LINK_10); - - if (on & MTK_PHY_LED_ON_LINK100) - *rules |= BIT(TRIGGER_NETDEV_LINK_100); - - if (on & MTK_PHY_LED_ON_LINK1000) - *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - - if (on & MTK_PHY_LED_ON_FDX) - *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); - - if (on & MTK_PHY_LED_ON_HDX) - *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); - - if (blink & MTK_PHY_LED_BLINK_RX) - *rules |= BIT(TRIGGER_NETDEV_RX); - - if (blink & MTK_PHY_LED_BLINK_TX) - *rules |= BIT(TRIGGER_NETDEV_TX); - - return 0; + return mtk_phy_led_hw_ctrl_get(phydev, index, rules, + MTK_GPHY_LED_ON_SET, + MTK_GPHY_LED_RX_BLINK_SET, + MTK_GPHY_LED_TX_BLINK_SET); }; static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, unsigned long rules) { - unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - u16 on = 0, blink = 0; - int ret; - - if (index > 1) - return -EINVAL; - - if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) - on |= MTK_PHY_LED_ON_FDX; - - if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) - on |= MTK_PHY_LED_ON_HDX; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK10; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK100; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK1000; - - if (rules & BIT(TRIGGER_NETDEV_RX)) { - blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? - MTK_PHY_LED_BLINK_10RX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? - MTK_PHY_LED_BLINK_100RX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? - MTK_PHY_LED_BLINK_1000RX : 0)) : - MTK_PHY_LED_BLINK_RX; - } - - if (rules & BIT(TRIGGER_NETDEV_TX)) { - blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? - MTK_PHY_LED_BLINK_10TX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? - MTK_PHY_LED_BLINK_100TX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? - MTK_PHY_LED_BLINK_1000TX : 0)) : - MTK_PHY_LED_BLINK_TX; - } - - if (blink || on) - set_bit(bit_netdev, &priv->led_state); - else - clear_bit(bit_netdev, &priv->led_state); - - ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : - MTK_PHY_LED0_ON_CTRL, - MTK_PHY_LED_ON_FDX | - MTK_PHY_LED_ON_HDX | - MTK_PHY_LED_ON_LINK, - on); - - if (ret) - return ret; - - return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_BLINK_CTRL : - MTK_PHY_LED0_BLINK_CTRL, blink); + return mtk_phy_led_hw_ctrl_set(phydev, index, rules, + MTK_GPHY_LED_ON_SET, + MTK_GPHY_LED_RX_BLINK_SET, + MTK_GPHY_LED_TX_BLINK_SET); }; static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num) @@ -1492,14 +1270,6 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) return 0; } -static void mt798x_phy_leds_state_init(struct phy_device *phydev) -{ - int i; - - for (i = 0; i < 2; ++i) - mt798x_phy_led_hw_control_get(phydev, i, NULL); -} - static int mt7988_phy_probe(struct phy_device *phydev) { struct mtk_socphy_shared *shared; @@ -1525,7 +1295,7 @@ static int mt7988_phy_probe(struct phy_device *phydev) phydev->priv = priv; - mt798x_phy_leds_state_init(phydev); + mtk_phy_leds_state_init(phydev); err = mt7988_phy_fix_leds_polarities(phydev); if (err) @@ -1552,7 +1322,7 @@ static int mt7981_phy_probe(struct phy_device *phydev) phydev->priv = priv; - mt798x_phy_leds_state_init(phydev); + mtk_phy_leds_state_init(phydev); return mt798x_phy_calibration(phydev); } diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c new file mode 100644 index 000000000000..34b0957b201b --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include "mtk.h" + +int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers) +{ + if (index > 1) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported); + +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + int on, blink; + + if (index > 1) + return -EINVAL; + + on = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); + + if (on < 0) + return -EIO; + + blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL); + if (blink < 0) + return -EIO; + + if ((on & (on_set | MTK_PHY_LED_ON_FDX | + MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || + (blink & (rx_blink_set | tx_blink_set))) + set_bit(bit_netdev, &priv->led_state); + else + clear_bit(bit_netdev, &priv->led_state); + + if (on & MTK_PHY_LED_ON_FORCE_ON) + set_bit(bit_on, &priv->led_state); + else + clear_bit(bit_on, &priv->led_state); + + if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) + set_bit(bit_blink, &priv->led_state); + else + clear_bit(bit_blink, &priv->led_state); + + if (!rules) + return 0; + + if (on & on_set) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (on & MTK_PHY_LED_ON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (on & MTK_PHY_LED_ON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (on & MTK_PHY_LED_ON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if (on & MTK_PHY_LED_ON_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + + if (on & MTK_PHY_LED_ON_FDX) + *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); + + if (on & MTK_PHY_LED_ON_HDX) + *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); + + if (blink & rx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_RX); + + if (blink & tx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_TX); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get); + +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + u16 on = 0, blink = 0; + int ret; + + if (index > 1) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) + on |= MTK_PHY_LED_ON_FDX; + + if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) + on |= MTK_PHY_LED_ON_HDX; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK10; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK100; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK1000; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK2500; + + if (rules & BIT(TRIGGER_NETDEV_RX)) { + blink |= (on & on_set) ? + (((on & MTK_PHY_LED_ON_LINK10) ? + MTK_PHY_LED_BLINK_10RX : 0) | + ((on & MTK_PHY_LED_ON_LINK100) ? + MTK_PHY_LED_BLINK_100RX : 0) | + ((on & MTK_PHY_LED_ON_LINK1000) ? + MTK_PHY_LED_BLINK_1000RX : 0) | + ((on & MTK_PHY_LED_ON_LINK2500) ? + MTK_PHY_LED_BLINK_2500RX : 0)) : + rx_blink_set; + } + + if (rules & BIT(TRIGGER_NETDEV_TX)) { + blink |= (on & on_set) ? + (((on & MTK_PHY_LED_ON_LINK10) ? + MTK_PHY_LED_BLINK_10TX : 0) | + ((on & MTK_PHY_LED_ON_LINK100) ? + MTK_PHY_LED_BLINK_100TX : 0) | + ((on & MTK_PHY_LED_ON_LINK1000) ? + MTK_PHY_LED_BLINK_1000TX : 0) | + ((on & MTK_PHY_LED_ON_LINK2500) ? + MTK_PHY_LED_BLINK_2500TX : 0)) : + tx_blink_set; + } + + if (blink || on) + set_bit(bit_netdev, &priv->led_state); + else + clear_bit(bit_netdev, &priv->led_state); + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set, + on); + + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, blink); +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set); + +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking) +{ + if (index > 1) + return -EINVAL; + + if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { + *blinking = true; + *delay_on = 50; + *delay_off = 50; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg); + +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + u16 led_on_mask, bool on) +{ + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + bool changed; + + if (on) + changed = !test_and_set_bit(bit_on, &priv->led_state); + else + changed = !!test_and_clear_bit(bit_on, &priv->led_state); + + changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : + MTK_PHY_LED0_ON_CTRL, + led_on_mask, + on ? MTK_PHY_LED_ON_FORCE_ON : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set); + +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + bool changed; + + if (blinking) + changed = !test_and_set_bit(bit_blink, &priv->led_state); + else + changed = !!test_and_clear_bit(bit_blink, &priv->led_state); + + changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, + blinking ? + MTK_PHY_LED_BLINK_FORCE_BLINK : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set); + +void mtk_phy_leds_state_init(struct phy_device *phydev) +{ + int i; + + for (i = 0; i < 2; ++i) + phydev->drv->led_hw_control_get(phydev, i, NULL); +} +EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init); + +MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common"); +MODULE_AUTHOR("Sky Huang "); +MODULE_AUTHOR("Daniel Golle "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h new file mode 100644 index 000000000000..9aaff2c2270d --- /dev/null +++ b/drivers/net/phy/mediatek/mtk.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Common definition for Mediatek Ethernet PHYs + * Author: SkyLake Huang + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef _MTK_EPHY_H_ +#define _MTK_EPHY_H_ + +#define MTK_EXT_PAGE_ACCESS 0x1f + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0) +#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0) +#define MTK_PHY_LED_ON_LINK1000 BIT(0) +#define MTK_PHY_LED_ON_LINK100 BIT(1) +#define MTK_PHY_LED_ON_LINK10 BIT(2) +#define MTK_PHY_LED_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED_ON_FORCE_ON BIT(6) +#define MTK_PHY_LED_ON_LINK2500 BIT(7) +#define MTK_PHY_LED_ON_POLARITY BIT(14) +#define MTK_PHY_LED_ON_ENABLE BIT(15) + +#define MTK_PHY_LED0_BLINK_CTRL 0x25 +#define MTK_PHY_LED1_BLINK_CTRL 0x27 +#define MTK_PHY_LED_BLINK_1000TX BIT(0) +#define MTK_PHY_LED_BLINK_1000RX BIT(1) +#define MTK_PHY_LED_BLINK_100TX BIT(2) +#define MTK_PHY_LED_BLINK_100RX BIT(3) +#define MTK_PHY_LED_BLINK_10TX BIT(4) +#define MTK_PHY_LED_BLINK_10RX BIT(5) +#define MTK_PHY_LED_BLINK_COLLISION BIT(6) +#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) +#define MTK_PHY_LED_BLINK_2500TX BIT(10) +#define MTK_PHY_LED_BLINK_2500RX BIT(11) + +#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \ + MTK_PHY_LED_ON_LINK100 | \ + MTK_PHY_LED_ON_LINK10) +#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) +#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) + +#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ + MTK_GPHY_LED_ON_SET) +#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_RX_BLINK_SET) +#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_TX_BLINK_SET) + +#define MTK_PHY_LED_STATE_FORCE_ON 0 +#define MTK_PHY_LED_STATE_FORCE_BLINK 1 +#define MTK_PHY_LED_STATE_NETDEV 2 + +struct mtk_socphy_priv { + unsigned long led_state; +}; + +int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers); +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking); +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + u16 led_on_mask, bool on); +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + bool blinking); +void mtk_phy_leds_state_init(struct phy_device *phydev); + +#endif /* _MTK_EPHY_H_ */ -- 2.51.0 From 6dc997fe3e72a302032cfcc171a4a7ee5f4faf5c Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Sat, 9 Nov 2024 00:34:53 +0800 Subject: [PATCH 072/517] net: phy: mediatek: Improve readability of mtk-phy-lib.c's mtk_phy_led_hw_ctrl_set() This patch removes parens around TRIGGER_NETDEV_RX/TRIGGER_NETDEV_TX in mtk_phy_led_hw_ctrl_set(), which improves readability. Reviewed-by: Andrew Lunn Signed-off-by: SkyLake.Huang Signed-off-by: David S. Miller --- drivers/net/phy/mediatek/mtk-phy-lib.c | 44 ++++++++++++++------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index 34b0957b201b..8d795bcc8b2d 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -129,29 +129,33 @@ int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, on |= MTK_PHY_LED_ON_LINK2500; if (rules & BIT(TRIGGER_NETDEV_RX)) { - blink |= (on & on_set) ? - (((on & MTK_PHY_LED_ON_LINK10) ? - MTK_PHY_LED_BLINK_10RX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? - MTK_PHY_LED_BLINK_100RX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? - MTK_PHY_LED_BLINK_1000RX : 0) | - ((on & MTK_PHY_LED_ON_LINK2500) ? - MTK_PHY_LED_BLINK_2500RX : 0)) : - rx_blink_set; + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10RX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100RX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000RX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500RX; + } else { + blink |= rx_blink_set; + } } if (rules & BIT(TRIGGER_NETDEV_TX)) { - blink |= (on & on_set) ? - (((on & MTK_PHY_LED_ON_LINK10) ? - MTK_PHY_LED_BLINK_10TX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? - MTK_PHY_LED_BLINK_100TX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? - MTK_PHY_LED_BLINK_1000TX : 0) | - ((on & MTK_PHY_LED_ON_LINK2500) ? - MTK_PHY_LED_BLINK_2500TX : 0)) : - tx_blink_set; + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10TX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100TX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000TX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500TX; + } else { + blink |= tx_blink_set; + } } if (blink || on) -- 2.51.0 From 2d3dc5ebaa6a3858e2132c14bbf9245f26979f40 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Sat, 9 Nov 2024 00:34:54 +0800 Subject: [PATCH 073/517] net: phy: mediatek: Integrate read/write page helper functions This patch integrates read/write page helper functions as MTK phy lib. They are basically the same in mtk-ge.c & mtk-ge-soc.c. Signed-off-by: SkyLake.Huang Signed-off-by: David S. Miller --- drivers/net/phy/mediatek/Kconfig | 1 + drivers/net/phy/mediatek/mtk-ge-soc.c | 18 ++++-------------- drivers/net/phy/mediatek/mtk-ge.c | 20 ++++++-------------- drivers/net/phy/mediatek/mtk-phy-lib.c | 12 ++++++++++++ drivers/net/phy/mediatek/mtk.h | 3 +++ 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index 19b5d23e7cd0..2a8ac5aed0f8 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -4,6 +4,7 @@ config MTK_NET_PHYLIB config MEDIATEK_GE_PHY tristate "MediaTek Gigabit Ethernet PHYs" + select MTK_NET_PHYLIB help Supports the MediaTek non-built-in Gigabit Ethernet PHYs. diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index d3a8b3946056..38dc898eaf7b 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -271,16 +271,6 @@ struct mtk_socphy_shared { struct mtk_socphy_priv priv[4]; }; -static int mtk_socphy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -} - -static int mtk_socphy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); -} - /* One calibration cycle consists of: * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high * until AD_CAL_COMP is ready to output calibration result. @@ -1337,8 +1327,8 @@ static struct phy_driver mtk_socphy_driver[] = { .probe = mt7981_phy_probe, .suspend = genphy_suspend, .resume = genphy_resume, - .read_page = mtk_socphy_read_page, - .write_page = mtk_socphy_write_page, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, .led_blink_set = mt798x_phy_led_blink_set, .led_brightness_set = mt798x_phy_led_brightness_set, .led_hw_is_supported = mt798x_phy_led_hw_is_supported, @@ -1354,8 +1344,8 @@ static struct phy_driver mtk_socphy_driver[] = { .probe = mt7988_phy_probe, .suspend = genphy_suspend, .resume = genphy_resume, - .read_page = mtk_socphy_read_page, - .write_page = mtk_socphy_write_page, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, .led_blink_set = mt798x_phy_led_blink_set, .led_brightness_set = mt798x_phy_led_brightness_set, .led_hw_is_supported = mt798x_phy_led_hw_is_supported, diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index 54ea64a37ab3..912289928fb3 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -3,6 +3,8 @@ #include #include +#include "mtk.h" + #define MTK_EXT_PAGE_ACCESS 0x1f #define MTK_PHY_PAGE_STANDARD 0x0000 #define MTK_PHY_PAGE_EXTENDED 0x0001 @@ -11,16 +13,6 @@ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 -static int mtk_gephy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -} - -static int mtk_gephy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); -} - static void mtk_gephy_config_init(struct phy_device *phydev) { /* Enable HW auto downshift */ @@ -77,8 +69,8 @@ static struct phy_driver mtk_gephy_driver[] = { .handle_interrupt = genphy_handle_interrupt_no_ack, .suspend = genphy_suspend, .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, }, { PHY_ID_MATCH_EXACT(0x03a29441), @@ -91,8 +83,8 @@ static struct phy_driver mtk_gephy_driver[] = { .handle_interrupt = genphy_handle_interrupt_no_ack, .suspend = genphy_suspend, .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, }, }; diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index 8d795bcc8b2d..98a09d670e9c 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -6,6 +6,18 @@ #include "mtk.h" +int mtk_phy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +} +EXPORT_SYMBOL_GPL(mtk_phy_read_page); + +int mtk_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +} +EXPORT_SYMBOL_GPL(mtk_phy_write_page); + int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules, unsigned long supported_triggers) diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index 9aaff2c2270d..63d9fe179b8f 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -66,6 +66,9 @@ struct mtk_socphy_priv { unsigned long led_state; }; +int mtk_phy_read_page(struct phy_device *phydev); +int mtk_phy_write_page(struct phy_device *phydev, int page); + int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules, unsigned long supported_triggers); -- 2.51.0 From c856cf37c2c09bc633f445f7b106868ecbecf773 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Sat, 9 Nov 2024 00:34:55 +0800 Subject: [PATCH 074/517] net: phy: mediatek: add MT7530 & MT7531's PHY ID macros This patch adds MT7530 & MT7531's PHY ID macros in mtk-ge.c so that it follows the same rule of mtk-ge-soc.c. Reviewed-by: Andrew Lunn Signed-off-by: SkyLake.Huang Signed-off-by: David S. Miller --- drivers/net/phy/mediatek/mtk-ge.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index 912289928fb3..ed2617bc20f4 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -5,6 +5,9 @@ #include "mtk.h" +#define MTK_GPHY_ID_MT7530 0x03a29412 +#define MTK_GPHY_ID_MT7531 0x03a29441 + #define MTK_EXT_PAGE_ACCESS 0x1f #define MTK_PHY_PAGE_STANDARD 0x0000 #define MTK_PHY_PAGE_EXTENDED 0x0001 @@ -59,7 +62,7 @@ static int mt7531_phy_config_init(struct phy_device *phydev) static struct phy_driver mtk_gephy_driver[] = { { - PHY_ID_MATCH_EXACT(0x03a29412), + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530), .name = "MediaTek MT7530 PHY", .config_init = mt7530_phy_config_init, /* Interrupts are handled by the switch, not the PHY @@ -73,7 +76,7 @@ static struct phy_driver mtk_gephy_driver[] = { .write_page = mtk_phy_write_page, }, { - PHY_ID_MATCH_EXACT(0x03a29441), + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531), .name = "MediaTek MT7531 PHY", .config_init = mt7531_phy_config_init, /* Interrupts are handled by the switch, not the PHY @@ -91,8 +94,8 @@ static struct phy_driver mtk_gephy_driver[] = { module_phy_driver(mtk_gephy_driver); static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { - { PHY_ID_MATCH_EXACT(0x03a29441) }, - { PHY_ID_MATCH_EXACT(0x03a29412) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) }, { } }; -- 2.51.0 From 7a3462a3d00deab364b02b53bb9dd57e767b0a38 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 12 Jan 2025 15:14:50 +0100 Subject: [PATCH 075/517] net: phy: Constify struct mdio_device_id 'struct mdio_device_id' is not modified in these drivers. Constifying these structures moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig, as an example: Before: ====== text data bss dec hex filename 27014 12792 0 39806 9b7e drivers/net/phy/broadcom.o After: ===== text data bss dec hex filename 27206 12600 0 39806 9b7e drivers/net/phy/broadcom.o Signed-off-by: Christophe JAILLET Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/403c381b7d9156b67ad68ffc44b8eee70c5e86a9.1736691226.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- drivers/net/phy/adin.c | 2 +- drivers/net/phy/adin1100.c | 2 +- drivers/net/phy/air_en8811h.c | 2 +- drivers/net/phy/amd.c | 2 +- drivers/net/phy/aquantia/aquantia_main.c | 2 +- drivers/net/phy/ax88796b.c | 2 +- drivers/net/phy/bcm-cygnus.c | 2 +- drivers/net/phy/bcm54140.c | 2 +- drivers/net/phy/bcm63xx.c | 2 +- drivers/net/phy/bcm7xxx.c | 2 +- drivers/net/phy/bcm84881.c | 2 +- drivers/net/phy/broadcom.c | 2 +- drivers/net/phy/cicada.c | 2 +- drivers/net/phy/cortina.c | 2 +- drivers/net/phy/davicom.c | 2 +- drivers/net/phy/dp83640.c | 2 +- drivers/net/phy/dp83822.c | 2 +- drivers/net/phy/dp83848.c | 2 +- drivers/net/phy/dp83867.c | 2 +- drivers/net/phy/dp83869.c | 2 +- drivers/net/phy/dp83tc811.c | 2 +- drivers/net/phy/dp83td510.c | 2 +- drivers/net/phy/dp83tg720.c | 2 +- drivers/net/phy/et1011c.c | 2 +- drivers/net/phy/icplus.c | 2 +- drivers/net/phy/intel-xway.c | 2 +- drivers/net/phy/lxt.c | 2 +- drivers/net/phy/marvell-88q2xxx.c | 2 +- drivers/net/phy/marvell-88x2222.c | 2 +- drivers/net/phy/marvell.c | 2 +- drivers/net/phy/marvell10g.c | 2 +- drivers/net/phy/mediatek/mtk-ge-soc.c | 2 +- drivers/net/phy/mediatek/mtk-ge.c | 2 +- drivers/net/phy/meson-gxl.c | 2 +- drivers/net/phy/micrel.c | 2 +- drivers/net/phy/microchip.c | 2 +- drivers/net/phy/microchip_t1.c | 2 +- drivers/net/phy/microchip_t1s.c | 2 +- drivers/net/phy/mscc/mscc_main.c | 2 +- drivers/net/phy/mxl-gpy.c | 2 +- drivers/net/phy/national.c | 2 +- drivers/net/phy/ncn26000.c | 2 +- drivers/net/phy/nxp-c45-tja11xx.c | 2 +- drivers/net/phy/nxp-cbtx.c | 2 +- drivers/net/phy/nxp-tja11xx.c | 2 +- drivers/net/phy/qcom/at803x.c | 2 +- drivers/net/phy/qcom/qca807x.c | 2 +- drivers/net/phy/qcom/qca808x.c | 2 +- drivers/net/phy/qcom/qca83xx.c | 2 +- drivers/net/phy/qsemi.c | 2 +- drivers/net/phy/rockchip.c | 2 +- drivers/net/phy/smsc.c | 2 +- drivers/net/phy/ste10Xp.c | 2 +- drivers/net/phy/teranetics.c | 2 +- drivers/net/phy/uPD60620.c | 2 +- drivers/net/phy/vitesse.c | 2 +- 56 files changed, 56 insertions(+), 56 deletions(-) diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index 2e1a46e121d9..fcd5eecbbf77 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -1040,7 +1040,7 @@ static struct phy_driver adin_driver[] = { module_phy_driver(adin_driver); -static struct mdio_device_id __maybe_unused adin_tbl[] = { +static const struct mdio_device_id __maybe_unused adin_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1200) }, { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1300) }, { } diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index 85f910e2d4fb..6bb469429b9d 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -340,7 +340,7 @@ static struct phy_driver adin_driver[] = { module_phy_driver(adin_driver); -static struct mdio_device_id __maybe_unused adin_tbl[] = { +static const struct mdio_device_id __maybe_unused adin_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) }, { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1110) }, { PHY_ID_MATCH_MODEL(PHY_ID_ADIN2111) }, diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c index 8d076b9609fd..e9fd24cb7270 100644 --- a/drivers/net/phy/air_en8811h.c +++ b/drivers/net/phy/air_en8811h.c @@ -1075,7 +1075,7 @@ static struct phy_driver en8811h_driver[] = { module_phy_driver(en8811h_driver); -static struct mdio_device_id __maybe_unused en8811h_tbl[] = { +static const struct mdio_device_id __maybe_unused en8811h_tbl[] = { { PHY_ID_MATCH_MODEL(EN8811H_PHY_ID) }, { } }; diff --git a/drivers/net/phy/amd.c b/drivers/net/phy/amd.c index 930b15fa6ce9..75b5fe65500a 100644 --- a/drivers/net/phy/amd.c +++ b/drivers/net/phy/amd.c @@ -111,7 +111,7 @@ static struct phy_driver am79c_drivers[] = { module_phy_driver(am79c_drivers); -static struct mdio_device_id __maybe_unused amd_tbl[] = { +static const struct mdio_device_id __maybe_unused amd_tbl[] = { { PHY_ID_AC101L, 0xfffffff0 }, { PHY_ID_AM79C874, 0xfffffff0 }, { } diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index c33a5ef34ba0..840ef5ad07ff 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -1096,7 +1096,7 @@ static struct phy_driver aqr_driver[] = { module_phy_driver(aqr_driver); -static struct mdio_device_id __maybe_unused aqr_tbl[] = { +static const struct mdio_device_id __maybe_unused aqr_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, diff --git a/drivers/net/phy/ax88796b.c b/drivers/net/phy/ax88796b.c index eb74a8cf8df1..694df1401aa2 100644 --- a/drivers/net/phy/ax88796b.c +++ b/drivers/net/phy/ax88796b.c @@ -121,7 +121,7 @@ static struct phy_driver asix_driver[] = { module_phy_driver(asix_driver); -static struct mdio_device_id __maybe_unused asix_tbl[] = { +static const struct mdio_device_id __maybe_unused asix_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) }, { PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) }, { PHY_ID_ASIX_AX88796B, 0xfffffff0 }, diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c index da8f7cb41b44..15cbef8202bc 100644 --- a/drivers/net/phy/bcm-cygnus.c +++ b/drivers/net/phy/bcm-cygnus.c @@ -278,7 +278,7 @@ static struct phy_driver bcm_cygnus_phy_driver[] = { } }; -static struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { +static const struct mdio_device_id __maybe_unused bcm_cygnus_phy_tbl[] = { { PHY_ID_BCM_CYGNUS, 0xfffffff0, }, { PHY_ID_BCM_OMEGA, 0xfffffff0, }, { } diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c index 2eea3d09b1e6..7969345f6b35 100644 --- a/drivers/net/phy/bcm54140.c +++ b/drivers/net/phy/bcm54140.c @@ -883,7 +883,7 @@ static struct phy_driver bcm54140_drivers[] = { }; module_phy_driver(bcm54140_drivers); -static struct mdio_device_id __maybe_unused bcm54140_tbl[] = { +static const struct mdio_device_id __maybe_unused bcm54140_tbl[] = { { PHY_ID_BCM54140, BCM54140_PHY_ID_MASK }, { } }; diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c index 0eb33be824f1..b46a736a3130 100644 --- a/drivers/net/phy/bcm63xx.c +++ b/drivers/net/phy/bcm63xx.c @@ -93,7 +93,7 @@ static struct phy_driver bcm63xx_driver[] = { module_phy_driver(bcm63xx_driver); -static struct mdio_device_id __maybe_unused bcm63xx_tbl[] = { +static const struct mdio_device_id __maybe_unused bcm63xx_tbl[] = { { 0x00406000, 0xfffffc00 }, { 0x002bdc00, 0xfffffc00 }, { } diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 97638ba7ae85..00e8fa14aa77 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -929,7 +929,7 @@ static struct phy_driver bcm7xxx_driver[] = { BCM7XXX_16NM_EPHY(PHY_ID_BCM7712, "Broadcom BCM7712"), }; -static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { +static const struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { { PHY_ID_BCM72113, 0xfffffff0 }, { PHY_ID_BCM72116, 0xfffffff0, }, { PHY_ID_BCM72165, 0xfffffff0, }, diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c index 47405bded677..d7f7cc44c532 100644 --- a/drivers/net/phy/bcm84881.c +++ b/drivers/net/phy/bcm84881.c @@ -262,7 +262,7 @@ static struct phy_driver bcm84881_drivers[] = { module_phy_driver(bcm84881_drivers); /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */ -static struct mdio_device_id __maybe_unused bcm84881_tbl[] = { +static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = { { 0xae025150, 0xfffffff0 }, { }, }; diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 9260c822e467..f4b1d98d6b18 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -1734,7 +1734,7 @@ static struct phy_driver broadcom_drivers[] = { module_phy_driver(broadcom_drivers); -static struct mdio_device_id __maybe_unused broadcom_tbl[] = { +static const struct mdio_device_id __maybe_unused broadcom_tbl[] = { { PHY_ID_BCM5411, 0xfffffff0 }, { PHY_ID_BCM5421, 0xfffffff0 }, { PHY_ID_BCM54210E, 0xfffffff0 }, diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c index ef5f412e101f..d87cf8b94cf8 100644 --- a/drivers/net/phy/cicada.c +++ b/drivers/net/phy/cicada.c @@ -145,7 +145,7 @@ static struct phy_driver cis820x_driver[] = { module_phy_driver(cis820x_driver); -static struct mdio_device_id __maybe_unused cicada_tbl[] = { +static const struct mdio_device_id __maybe_unused cicada_tbl[] = { { 0x000fc410, 0x000ffff0 }, { 0x000fc440, 0x000fffc0 }, { } diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index 40514a94e6ff..3b65f37f1c57 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -87,7 +87,7 @@ static struct phy_driver cortina_driver[] = { module_phy_driver(cortina_driver); -static struct mdio_device_id __maybe_unused cortina_tbl[] = { +static const struct mdio_device_id __maybe_unused cortina_tbl[] = { { PHY_ID_CS4340, 0xffffffff}, {}, }; diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index 4ac4bce1bf32..fa3692508f16 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -209,7 +209,7 @@ static struct phy_driver dm91xx_driver[] = { module_phy_driver(dm91xx_driver); -static struct mdio_device_id __maybe_unused davicom_tbl[] = { +static const struct mdio_device_id __maybe_unused davicom_tbl[] = { { 0x0181b880, 0x0ffffff0 }, { 0x0181b8b0, 0x0ffffff0 }, { 0x0181b8a0, 0x0ffffff0 }, diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 075d2beea716..85e231451093 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1548,7 +1548,7 @@ MODULE_LICENSE("GPL"); module_init(dp83640_init); module_exit(dp83640_exit); -static struct mdio_device_id __maybe_unused dp83640_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83640_tbl[] = { { DP83640_PHY_ID, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 3ab64e04a01c..537e152dd156 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -825,7 +825,7 @@ static struct phy_driver dp83822_driver[] = { }; module_phy_driver(dp83822_driver); -static struct mdio_device_id __maybe_unused dp83822_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83822_tbl[] = { { DP83822_PHY_ID, 0xfffffff0 }, { DP83825I_PHY_ID, 0xfffffff0 }, { DP83826C_PHY_ID, 0xfffffff0 }, diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index 351411f0aa6f..d88b1999d596 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -123,7 +123,7 @@ static int dp83848_config_init(struct phy_device *phydev) return 0; } -static struct mdio_device_id __maybe_unused dp83848_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83848_tbl[] = { { TI_DP83848C_PHY_ID, 0xfffffff0 }, { NS_DP83848C_PHY_ID, 0xfffffff0 }, { TI_DP83620_PHY_ID, 0xfffffff0 }, diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 4120385c5a79..c1451df430ac 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -1210,7 +1210,7 @@ static struct phy_driver dp83867_driver[] = { }; module_phy_driver(dp83867_driver); -static struct mdio_device_id __maybe_unused dp83867_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83867_tbl[] = { { DP83867_PHY_ID, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index b6b38caf9c0e..a62cd838a9ea 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -928,7 +928,7 @@ static struct phy_driver dp83869_driver[] = { }; module_phy_driver(dp83869_driver); -static struct mdio_device_id __maybe_unused dp83869_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83869_tbl[] = { { PHY_ID_MATCH_MODEL(DP83869_PHY_ID) }, { PHY_ID_MATCH_MODEL(DP83561_PHY_ID) }, { } diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c index 7ea32fb77190..e480c2a07450 100644 --- a/drivers/net/phy/dp83tc811.c +++ b/drivers/net/phy/dp83tc811.c @@ -403,7 +403,7 @@ static struct phy_driver dp83811_driver[] = { }; module_phy_driver(dp83811_driver); -static struct mdio_device_id __maybe_unused dp83811_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83811_tbl[] = { { DP83TC811_PHY_ID, 0xfffffff0 }, { }, }; diff --git a/drivers/net/phy/dp83td510.c b/drivers/net/phy/dp83td510.c index 92aa3a2b9744..56ae24ad6c90 100644 --- a/drivers/net/phy/dp83td510.c +++ b/drivers/net/phy/dp83td510.c @@ -605,7 +605,7 @@ static struct phy_driver dp83td510_driver[] = { } }; module_phy_driver(dp83td510_driver); -static struct mdio_device_id __maybe_unused dp83td510_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83td510_tbl[] = { { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) }, { } }; diff --git a/drivers/net/phy/dp83tg720.c b/drivers/net/phy/dp83tg720.c index 0ef4d7dba065..da9230b1ba30 100644 --- a/drivers/net/phy/dp83tg720.c +++ b/drivers/net/phy/dp83tg720.c @@ -361,7 +361,7 @@ static struct phy_driver dp83tg720_driver[] = { } }; module_phy_driver(dp83tg720_driver); -static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { +static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) }, { } }; diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c index be1b71d7cab7..6cd8d77586fd 100644 --- a/drivers/net/phy/et1011c.c +++ b/drivers/net/phy/et1011c.c @@ -94,7 +94,7 @@ static struct phy_driver et1011c_driver[] = { { module_phy_driver(et1011c_driver); -static struct mdio_device_id __maybe_unused et1011c_tbl[] = { +static const struct mdio_device_id __maybe_unused et1011c_tbl[] = { { 0x0282f014, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index a00a667454a9..feed270ab4ea 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -624,7 +624,7 @@ static struct phy_driver icplus_driver[] = { module_phy_driver(icplus_driver); -static struct mdio_device_id __maybe_unused icplus_tbl[] = { +static const struct mdio_device_id __maybe_unused icplus_tbl[] = { { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) }, { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) }, { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) }, diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index 3c032868ef04..fad411b93c15 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -456,7 +456,7 @@ static struct phy_driver xway_gphy[] = { }; module_phy_driver(xway_gphy); -static struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { +static const struct mdio_device_id __maybe_unused xway_gphy_tbl[] = { { PHY_ID_PHY11G_1_3, 0xffffffff }, { PHY_ID_PHY22F_1_3, 0xffffffff }, { PHY_ID_PHY11G_1_4, 0xffffffff }, diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index e3bf827b7959..5251a61c8b0f 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -348,7 +348,7 @@ static struct phy_driver lxt97x_driver[] = { module_phy_driver(lxt97x_driver); -static struct mdio_device_id __maybe_unused lxt_tbl[] = { +static const struct mdio_device_id __maybe_unused lxt_tbl[] = { { 0x78100000, 0xfffffff0 }, { 0x001378e0, 0xfffffff0 }, { 0x00137a10, 0xfffffff0 }, diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index b3a5a0af19da..d0856a06a9e7 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -940,7 +940,7 @@ static struct phy_driver mv88q2xxx_driver[] = { module_phy_driver(mv88q2xxx_driver); -static struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = { +static const struct mdio_device_id __maybe_unused mv88q2xxx_tbl[] = { { MARVELL_PHY_ID_88Q2110, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88Q2220, MARVELL_PHY_ID_MASK }, { /*sentinel*/ } diff --git a/drivers/net/phy/marvell-88x2222.c b/drivers/net/phy/marvell-88x2222.c index 0b777cdd7078..fad2f54c1eac 100644 --- a/drivers/net/phy/marvell-88x2222.c +++ b/drivers/net/phy/marvell-88x2222.c @@ -613,7 +613,7 @@ static struct phy_driver mv2222_drivers[] = { }; module_phy_driver(mv2222_drivers); -static struct mdio_device_id __maybe_unused mv2222_tbl[] = { +static const struct mdio_device_id __maybe_unused mv2222_tbl[] = { { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK }, { } }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index b7d2951d979d..9c761b855026 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -4181,7 +4181,7 @@ static struct phy_driver marvell_drivers[] = { module_phy_driver(marvell_drivers); -static struct mdio_device_id __maybe_unused marvell_tbl[] = { +static const struct mdio_device_id __maybe_unused marvell_tbl[] = { { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E3082, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 6642eb642d4b..623bdb8466b8 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -1484,7 +1484,7 @@ static struct phy_driver mv3310_drivers[] = { module_phy_driver(mv3310_drivers); -static struct mdio_device_id __maybe_unused mv3310_tbl[] = { +static const struct mdio_device_id __maybe_unused mv3310_tbl[] = { { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, { }, diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index 38dc898eaf7b..bdf99b327029 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -1356,7 +1356,7 @@ static struct phy_driver mtk_socphy_driver[] = { module_phy_driver(mtk_socphy_driver); -static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { +static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, { } diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index ed2617bc20f4..b517ca8573e7 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -93,7 +93,7 @@ static struct phy_driver mtk_gephy_driver[] = { module_phy_driver(mtk_gephy_driver); -static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { +static const struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) }, { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) }, { } diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index bb9b33b6bce2..962ebbbc1348 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -221,7 +221,7 @@ static struct phy_driver meson_gxl_phy[] = { }, }; -static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { +static const struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { { PHY_ID_MATCH_VENDOR(0x01814400) }, { PHY_ID_MATCH_VENDOR(0x01803301) }, { } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 92e9eb4146d9..655769765bc8 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -5701,7 +5701,7 @@ MODULE_DESCRIPTION("Micrel PHY driver"); MODULE_AUTHOR("David J. Choi"); MODULE_LICENSE("GPL"); -static struct mdio_device_id __maybe_unused micrel_tbl[] = { +static const struct mdio_device_id __maybe_unused micrel_tbl[] = { { PHY_ID_KSZ9021, 0x000ffffe }, { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK }, diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index ffca1cec4ec9..55822d36889c 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -509,7 +509,7 @@ static struct phy_driver microchip_phy_driver[] = { module_phy_driver(microchip_phy_driver); -static struct mdio_device_id __maybe_unused microchip_tbl[] = { +static const struct mdio_device_id __maybe_unused microchip_tbl[] = { { 0x0007c132, 0xfffffff2 }, { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX) }, { } diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c index a5ef8fe50704..4ddc407e405c 100644 --- a/drivers/net/phy/microchip_t1.c +++ b/drivers/net/phy/microchip_t1.c @@ -1886,7 +1886,7 @@ static struct phy_driver microchip_t1_phy_driver[] = { module_phy_driver(microchip_t1_phy_driver); -static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { +static const struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) }, { PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) }, { PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) }, diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index 3614839a8e51..78c54d826c97 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -323,7 +323,7 @@ static struct phy_driver microchip_t1s_driver[] = { module_phy_driver(microchip_t1s_driver); -static struct mdio_device_id __maybe_unused tbl[] = { +static const struct mdio_device_id __maybe_unused tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) }, { } diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 19983b206405..cc2bb9ed4fd2 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2710,7 +2710,7 @@ static struct phy_driver vsc85xx_driver[] = { module_phy_driver(vsc85xx_driver); -static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { +static const struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) }, { } }; diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index e5f8ac4b4604..d145b67a067f 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -1047,7 +1047,7 @@ static struct phy_driver gpy_drivers[] = { }; module_phy_driver(gpy_drivers); -static struct mdio_device_id __maybe_unused gpy_tbl[] = { +static const struct mdio_device_id __maybe_unused gpy_tbl[] = { {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)}, {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK}, {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)}, diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c index 9ae9cc6b23c2..7f3ff322892e 100644 --- a/drivers/net/phy/national.c +++ b/drivers/net/phy/national.c @@ -173,7 +173,7 @@ MODULE_DESCRIPTION("NatSemi PHY driver"); MODULE_AUTHOR("Stuart Menefy"); MODULE_LICENSE("GPL"); -static struct mdio_device_id __maybe_unused ns_tbl[] = { +static const struct mdio_device_id __maybe_unused ns_tbl[] = { { DP83865_PHY_ID, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c index 5680584f659e..cabdd83c614f 100644 --- a/drivers/net/phy/ncn26000.c +++ b/drivers/net/phy/ncn26000.c @@ -159,7 +159,7 @@ static struct phy_driver ncn26000_driver[] = { module_phy_driver(ncn26000_driver); -static struct mdio_device_id __maybe_unused ncn26000_tbl[] = { +static const struct mdio_device_id __maybe_unused ncn26000_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_NCN26000) }, { } }; diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 99a5eee77bec..9d6b336f9971 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -2102,7 +2102,7 @@ static struct phy_driver nxp_c45_driver[] = { module_phy_driver(nxp_c45_driver); -static struct mdio_device_id __maybe_unused nxp_c45_tbl[] = { +static const struct mdio_device_id __maybe_unused nxp_c45_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103) }, { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120) }, { /*sentinel*/ }, diff --git a/drivers/net/phy/nxp-cbtx.c b/drivers/net/phy/nxp-cbtx.c index 145703f0a406..d0ff22f68cd2 100644 --- a/drivers/net/phy/nxp-cbtx.c +++ b/drivers/net/phy/nxp-cbtx.c @@ -215,7 +215,7 @@ static struct phy_driver cbtx_driver[] = { module_phy_driver(cbtx_driver); -static struct mdio_device_id __maybe_unused cbtx_tbl[] = { +static const struct mdio_device_id __maybe_unused cbtx_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_CBTX_SJA1110) }, { }, }; diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c index 2c263ae44b4f..ed7fa26bac8e 100644 --- a/drivers/net/phy/nxp-tja11xx.c +++ b/drivers/net/phy/nxp-tja11xx.c @@ -888,7 +888,7 @@ static struct phy_driver tja11xx_driver[] = { module_phy_driver(tja11xx_driver); -static struct mdio_device_id __maybe_unused tja11xx_tbl[] = { +static const struct mdio_device_id __maybe_unused tja11xx_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) }, { PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) }, { PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) }, diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index ac909ad8a87b..8f26e395e39f 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -1071,7 +1071,7 @@ static struct phy_driver at803x_driver[] = { module_phy_driver(at803x_driver); -static struct mdio_device_id __maybe_unused atheros_tbl[] = { +static const struct mdio_device_id __maybe_unused atheros_tbl[] = { { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, diff --git a/drivers/net/phy/qcom/qca807x.c b/drivers/net/phy/qcom/qca807x.c index ec336c3e338d..2ad8c2586d64 100644 --- a/drivers/net/phy/qcom/qca807x.c +++ b/drivers/net/phy/qcom/qca807x.c @@ -828,7 +828,7 @@ static struct phy_driver qca807x_drivers[] = { }; module_phy_driver(qca807x_drivers); -static struct mdio_device_id __maybe_unused qca807x_tbl[] = { +static const struct mdio_device_id __maybe_unused qca807x_tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) }, { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) }, { } diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index c3aad0e6b700..6de16c0eaa08 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -655,7 +655,7 @@ static struct phy_driver qca808x_driver[] = { module_phy_driver(qca808x_driver); -static struct mdio_device_id __maybe_unused qca808x_tbl[] = { +static const struct mdio_device_id __maybe_unused qca808x_tbl[] = { { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, { } }; diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c index a05d0df6fa16..b32c2fbec927 100644 --- a/drivers/net/phy/qcom/qca83xx.c +++ b/drivers/net/phy/qcom/qca83xx.c @@ -261,7 +261,7 @@ static struct phy_driver qca83xx_driver[] = { module_phy_driver(qca83xx_driver); -static struct mdio_device_id __maybe_unused qca83xx_tbl[] = { +static const struct mdio_device_id __maybe_unused qca83xx_tbl[] = { { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index 30d15f7c9b03..7b70ba6cab66 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -155,7 +155,7 @@ static struct phy_driver qs6612_driver[] = { { module_phy_driver(qs6612_driver); -static struct mdio_device_id __maybe_unused qs6612_tbl[] = { +static const struct mdio_device_id __maybe_unused qs6612_tbl[] = { { 0x00181440, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/rockchip.c b/drivers/net/phy/rockchip.c index bb13e75183ee..b338f385e15a 100644 --- a/drivers/net/phy/rockchip.c +++ b/drivers/net/phy/rockchip.c @@ -188,7 +188,7 @@ static struct phy_driver rockchip_phy_driver[] = { module_phy_driver(rockchip_phy_driver); -static struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = { +static const struct mdio_device_id __maybe_unused rockchip_phy_tbl[] = { { INTERNAL_EPHY_ID, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index de66b621eb99..1acac288972d 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -885,7 +885,7 @@ MODULE_DESCRIPTION("SMSC PHY driver"); MODULE_AUTHOR("Herbert Valerio Riedel"); MODULE_LICENSE("GPL"); -static struct mdio_device_id __maybe_unused smsc_tbl[] = { +static const struct mdio_device_id __maybe_unused smsc_tbl[] = { { 0x0007c0a0, 0xfffffff0 }, { 0x0007c0b0, 0xfffffff0 }, { 0x0007c0c0, 0xfffffff0 }, diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c index 309e4c3496c4..d4835d4c50e0 100644 --- a/drivers/net/phy/ste10Xp.c +++ b/drivers/net/phy/ste10Xp.c @@ -124,7 +124,7 @@ static struct phy_driver ste10xp_pdriver[] = { module_phy_driver(ste10xp_pdriver); -static struct mdio_device_id __maybe_unused ste10Xp_tbl[] = { +static const struct mdio_device_id __maybe_unused ste10Xp_tbl[] = { { STE101P_PHY_ID, 0xfffffff0 }, { STE100P_PHY_ID, 0xffffffff }, { } diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 8057ea8dbc21..752d4bf7bb99 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -87,7 +87,7 @@ static struct phy_driver teranetics_driver[] = { module_phy_driver(teranetics_driver); -static struct mdio_device_id __maybe_unused teranetics_tbl[] = { +static const struct mdio_device_id __maybe_unused teranetics_tbl[] = { { PHY_ID_TN2020, 0xffffffff }, { } }; diff --git a/drivers/net/phy/uPD60620.c b/drivers/net/phy/uPD60620.c index 38834347a427..900cb756c366 100644 --- a/drivers/net/phy/uPD60620.c +++ b/drivers/net/phy/uPD60620.c @@ -90,7 +90,7 @@ static struct phy_driver upd60620_driver[1] = { { module_phy_driver(upd60620_driver); -static struct mdio_device_id __maybe_unused upd60620_tbl[] = { +static const struct mdio_device_id __maybe_unused upd60620_tbl[] = { { UPD60620_PHY_ID, 0xfffffffe }, { } }; diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 2377179de017..b1b7bbba284e 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -674,7 +674,7 @@ static struct phy_driver vsc82xx_driver[] = { module_phy_driver(vsc82xx_driver); -static struct mdio_device_id __maybe_unused vitesse_tbl[] = { +static const struct mdio_device_id __maybe_unused vitesse_tbl[] = { { PHY_ID_VSC8234, 0x000ffff0 }, { PHY_ID_VSC8244, 0x000fffc0 }, { PHY_ID_VSC8572, 0x000ffff0 }, -- 2.51.0 From 9c63de87a5aab32fe251f0d50e2da397138cf3a2 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Thu, 13 Feb 2025 16:05:49 +0800 Subject: [PATCH 076/517] net: phy: mediatek: Change to more meaningful macros Replace magic number with more meaningful macros in mtk-ge.c. Also, move some common macros into mtk-phy-lib.c. Signed-off-by: Sky Huang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250213080553.921434-2-SkyLake.Huang@mediatek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge-soc.c | 1 - drivers/net/phy/mediatek/mtk-ge.c | 71 +++++++++++++++++++++------ drivers/net/phy/mediatek/mtk.h | 2 + 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index bdf99b327029..69cd6a1cbad4 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -24,7 +24,6 @@ #define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 -#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 #define ANALOG_INTERNAL_OPERATION_MAX_US 20 #define TXRESERVE_MIN 0 diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index b517ca8573e7..75e1b0387710 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -8,18 +8,38 @@ #define MTK_GPHY_ID_MT7530 0x03a29412 #define MTK_GPHY_ID_MT7531 0x03a29441 -#define MTK_EXT_PAGE_ACCESS 0x1f -#define MTK_PHY_PAGE_STANDARD 0x0000 -#define MTK_PHY_PAGE_EXTENDED 0x0001 -#define MTK_PHY_PAGE_EXTENDED_2 0x0002 -#define MTK_PHY_PAGE_EXTENDED_3 0x0003 -#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 -#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 +#define MTK_PHY_PAGE_EXTENDED_1 0x0001 +#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 +#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) + +#define MTK_PHY_PAGE_EXTENDED_2 0x0002 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11 + +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13 +#define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14 +#define MTK_TX_DELAY_PAIR_B_MASK GENMASK(10, 8) +#define MTK_TX_DELAY_PAIR_D_MASK GENMASK(2, 0) + +#define MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL 0xa6 +#define MTK_MCC_NEARECHO_OFFSET_MASK GENMASK(15, 8) + +#define MTK_PHY_RXADC_CTRL_RG7 0xc6 +#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123 0x123 +#define MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK GENMASK(15, 8) +#define MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK GENMASK(7, 0) static void mtk_gephy_config_init(struct phy_device *phydev) { /* Enable HW auto downshift */ - phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4)); + phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, + MTK_PHY_AUX_CTRL_AND_STATUS, + 0, MTK_PHY_ENABLE_DOWNSHIFT); /* Increase SlvDPSready time */ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); @@ -29,10 +49,20 @@ static void mtk_gephy_config_init(struct phy_device *phydev) phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); /* Adjust 100_mse_threshold */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff); - - /* Disable mcc */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG123, + MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK | + MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_LO_THRESH100_MASK, + 0xff) | + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH100_MASK, + 0xff)); + + /* If echo time is narrower than 0x3, it will be regarded as noise */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_MCC_CTRL_AND_TX_POWER_CTRL, + MTK_MCC_NEARECHO_OFFSET_MASK, + FIELD_PREP(MTK_MCC_NEARECHO_OFFSET_MASK, 0x3)); } static int mt7530_phy_config_init(struct phy_device *phydev) @@ -40,7 +70,8 @@ static int mt7530_phy_config_init(struct phy_device *phydev) mtk_gephy_config_init(phydev); /* Increase post_update_timer */ - phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b); + phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11, 0x4b); return 0; } @@ -51,11 +82,19 @@ static int mt7531_phy_config_init(struct phy_device *phydev) /* PHY link down power saving enable */ phy_set_bits(phydev, 0x17, BIT(4)); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, + FIELD_PREP(MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3)); /* Set TX Pair delay selection */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_GBE_MODE_TX_DELAY_SEL, + MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK, + FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | + FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TEST_MODE_TX_DELAY_SEL, + MTK_TX_DELAY_PAIR_B_MASK | MTK_TX_DELAY_PAIR_D_MASK, + FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | + FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); return 0; } diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index 63d9fe179b8f..a888e2e1dd6b 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -9,6 +9,8 @@ #define _MTK_EPHY_H_ #define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 /* Registers on MDIO_MMD_VEND2 */ #define MTK_PHY_LED0_ON_CTRL 0x24 -- 2.51.0 From 0b2e6555cf36c1011c636b73e0202590247ca124 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Thu, 13 Feb 2025 16:05:50 +0800 Subject: [PATCH 077/517] net: phy: mediatek: Add token ring access helper functions in mtk-phy-lib This patch adds TR(token ring) manipulations and adds correct macro names for those magic numbers. TR is a way to access proprietary registers on page 52b5. Use these helper functions so we can see which fields we're going to modify/set/clear. TR functions with __* prefix mean that the operations inside aren't wrapped by page select/restore functions. This patch doesn't really change registers' settings but just enhances readability and maintainability. Signed-off-by: Sky Huang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250213080553.921434-3-SkyLake.Huang@mediatek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge-soc.c | 231 +++++++++++++++++-------- drivers/net/phy/mediatek/mtk-ge.c | 11 +- drivers/net/phy/mediatek/mtk-phy-lib.c | 63 +++++++ drivers/net/phy/mediatek/mtk.h | 5 + 4 files changed, 230 insertions(+), 80 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index 69cd6a1cbad4..5d7373793659 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -25,6 +25,90 @@ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */ +/* NormMseLoThresh */ +#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8) + +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +/* RemAckCntLimitCtrl */ +#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1) + +/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */ +/* VcoSlicerThreshBitsHigh */ +#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */ +/* DfeTailEnableVgaThresh1000 */ +#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */ +/* MrvlTrFix100Kp */ +#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20) +/* MrvlTrFix100Kf */ +#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17) +/* MrvlTrFix1000Kp */ +#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14) +/* MrvlTrFix1000Kf */ +#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */ +/* VgaDecRate */ +#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */ +/* SlvDSPreadyTime */ +#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15) +/* MasDSPreadyTime */ +#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */ +/* ResetSyncOffset */ +#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */ +/* FfeUpdGainForceVal */ +#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7) +/* FfeUpdGainForce */ +#define FFE_UPDATE_GAIN_FORCE BIT(6) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */ +/* SS: Steady-state, KP: Proportional Gain */ +/* SSTrKp100 */ +#define SS_TR_KP100_MASK GENMASK(21, 19) +/* SSTrKf100 */ +#define SS_TR_KF100_MASK GENMASK(18, 16) +/* SSTrKp1000Mas */ +#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13) +/* SSTrKf1000Mas */ +#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10) +/* SSTrKp1000Slv */ +#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7) +/* SSTrKf1000Slv */ +#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */ +/* RegEEE_st2TrKf1000 */ +#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */ +/* RegEEE_slv_waketr_timer_tar */ +#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11) +/* RegEEE_slv_remtx_timer_tar */ +#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */ +/* RegEEE_slv_wake_int_timer_tar */ +#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */ +/* RegEEE_trfreeze_timer2 */ +#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */ +/* RegEEE100Stg1_tar */ +#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0) + #define ANALOG_INTERNAL_OPERATION_MAX_US 20 #define TXRESERVE_MIN 0 #define TXRESERVE_MAX 7 @@ -700,40 +784,41 @@ static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) static void mt798x_phy_common_finetune(struct phy_device *phydev) { phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ - __phy_write(phydev, 0x11, 0xc71); - __phy_write(phydev, 0x12, 0xc); - __phy_write(phydev, 0x10, 0x8fae); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x17, + SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK, + FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) | + FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18)); /* EnabRandUpdTrig = 1 */ __phy_write(phydev, 0x11, 0x2f00); __phy_write(phydev, 0x12, 0xe); __phy_write(phydev, 0x10, 0x8fb0); - /* NormMseLoThresh = 85 */ - __phy_write(phydev, 0x11, 0x55a0); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x83aa); + __mtk_tr_modify(phydev, 0x0, 0x7, 0x15, + NORMAL_MSE_LO_THRESH_MASK, + FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55)); - /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */ - __phy_write(phydev, 0x11, 0x240); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9680); + __mtk_tr_modify(phydev, 0x2, 0xd, 0x0, + FFE_UPDATE_GAIN_FORCE_VAL_MASK, + FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) | + FFE_UPDATE_GAIN_FORCE); /* TrFreeze = 0 (mt7988 default) */ __phy_write(phydev, 0x11, 0x0); __phy_write(phydev, 0x12, 0x0); __phy_write(phydev, 0x10, 0x9686); - /* SSTrKp100 = 5 */ - /* SSTrKf100 = 6 */ - /* SSTrKp1000Mas = 5 */ - /* SSTrKf1000Mas = 6 */ - /* SSTrKp1000Slv = 5 */ - /* SSTrKf1000Slv = 6 */ - __phy_write(phydev, 0x11, 0xbaef); - __phy_write(phydev, 0x12, 0x2e); - __phy_write(phydev, 0x10, 0x968c); + __mtk_tr_modify(phydev, 0x2, 0xd, 0x6, + SS_TR_KP100_MASK | SS_TR_KF100_MASK | + SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK | + SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK, + FIELD_PREP(SS_TR_KP100_MASK, 0x5) | + FIELD_PREP(SS_TR_KF100_MASK, 0x6) | + FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) | + FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) | + FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) | + FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); } @@ -756,27 +841,29 @@ static void mt7981_phy_finetune(struct phy_device *phydev) } phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* ResetSyncOffset = 6 */ - __phy_write(phydev, 0x11, 0x600); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8fc0); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x20, + RESET_SYNC_OFFSET_MASK, + FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6)); - /* VgaDecRate = 1 */ - __phy_write(phydev, 0x11, 0x4c2a); - __phy_write(phydev, 0x12, 0x3e); - __phy_write(phydev, 0x10, 0x8fa4); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x12, + VGA_DECIMATION_RATE_MASK, + FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1)); /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 */ - __phy_write(phydev, 0x11, 0xd10a); - __phy_write(phydev, 0x12, 0x34); - __phy_write(phydev, 0x10, 0x8f82); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x1, + MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK | + MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK, + FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) | + FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) | + FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) | + FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2)); /* VcoSlicerThreshBitsHigh */ - __phy_write(phydev, 0x11, 0x5555); - __phy_write(phydev, 0x12, 0x55); - __phy_write(phydev, 0x10, 0x8ec0); + __mtk_tr_modify(phydev, 0x1, 0xd, 0x20, + VCO_SLICER_THRESH_HIGH_MASK, + FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555)); phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ @@ -828,25 +915,23 @@ static void mt7988_phy_finetune(struct phy_device *phydev) phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* ResetSyncOffset = 5 */ - __phy_write(phydev, 0x11, 0x500); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8fc0); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x20, + RESET_SYNC_OFFSET_MASK, + FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x5)); /* VgaDecRate is 1 at default on mt7988 */ - /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7, - * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7 - */ - __phy_write(phydev, 0x11, 0xb90a); - __phy_write(phydev, 0x12, 0x6f); - __phy_write(phydev, 0x10, 0x8f82); - - /* RemAckCntLimitCtrl = 1 */ - __phy_write(phydev, 0x11, 0xfbba); - __phy_write(phydev, 0x12, 0xc3); - __phy_write(phydev, 0x10, 0x87f8); - + __mtk_tr_modify(phydev, 0x1, 0xf, 0x1, + MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK | + MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK, + FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x6) | + FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x7) | + FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x6) | + FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x7)); + + __mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, + REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, + FIELD_PREP(REMOTE_ACK_COUNT_LIMIT_CTRL_MASK, 0x1)); phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ @@ -927,40 +1012,36 @@ static void mt798x_phy_eee(struct phy_device *phydev) __phy_write(phydev, 0x12, 0x0); __phy_write(phydev, 0x10, 0x9690); - /* REG_EEE_st2TrKf1000 = 2 */ - __phy_write(phydev, 0x11, 0x114f); - __phy_write(phydev, 0x12, 0x2); - __phy_write(phydev, 0x10, 0x969a); + __mtk_tr_modify(phydev, 0x2, 0xd, 0xd, + EEE1000_STAGE2_TR_KF_MASK, + FIELD_PREP(EEE1000_STAGE2_TR_KF_MASK, 0x2)); - /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ - __phy_write(phydev, 0x11, 0x3028); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x969e); + __mtk_tr_modify(phydev, 0x2, 0xd, 0xf, + SLAVE_WAKETR_TIMER_MASK | SLAVE_REMTX_TIMER_MASK, + FIELD_PREP(SLAVE_WAKETR_TIMER_MASK, 0x6) | + FIELD_PREP(SLAVE_REMTX_TIMER_MASK, 0x14)); - /* RegEEE_slv_wake_int_timer_tar = 8 */ - __phy_write(phydev, 0x11, 0x5010); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96a0); + __mtk_tr_modify(phydev, 0x2, 0xd, 0x10, + SLAVE_WAKEINT_TIMER_MASK, + FIELD_PREP(SLAVE_WAKEINT_TIMER_MASK, 0x8)); - /* RegEEE_trfreeze_timer2 = 586 */ - __phy_write(phydev, 0x11, 0x24a); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96a8); + __mtk_tr_modify(phydev, 0x2, 0xd, 0x14, + TR_FREEZE_TIMER2_MASK, + FIELD_PREP(TR_FREEZE_TIMER2_MASK, 0x24a)); - /* RegEEE100Stg1_tar = 16 */ - __phy_write(phydev, 0x11, 0x3210); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96b8); + __mtk_tr_modify(phydev, 0x2, 0xd, 0x1c, + EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, + FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, + 0x10)); /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ __phy_write(phydev, 0x11, 0x1463); __phy_write(phydev, 0x12, 0x0); __phy_write(phydev, 0x10, 0x96ca); - /* DfeTailEnableVgaThresh1000 = 27 */ - __phy_write(phydev, 0x11, 0x36); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8f80); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x0, + DFE_TAIL_EANBLE_VGA_TRHESH_1000, + FIELD_PREP(DFE_TAIL_EANBLE_VGA_TRHESH_1000, 0x1b)); phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index 75e1b0387710..a24c5ba469ba 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -18,6 +18,10 @@ #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */ +#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15) + /* Registers on MDIO_MMD_VEND1 */ #define MTK_PHY_GBE_MODE_TX_DELAY_SEL 0x13 #define MTK_PHY_TEST_MODE_TX_DELAY_SEL 0x14 @@ -42,11 +46,8 @@ static void mtk_gephy_config_init(struct phy_device *phydev) 0, MTK_PHY_ENABLE_DOWNSHIFT); /* Increase SlvDPSready time */ - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - __phy_write(phydev, 0x10, 0xafae); - __phy_write(phydev, 0x12, 0x2f); - __phy_write(phydev, 0x10, 0x8fae); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + mtk_tr_modify(phydev, 0x1, 0xf, 0x17, SLAVE_DSP_READY_TIME_MASK, + FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x5e)); /* Adjust 100_mse_threshold */ phy_modify_mmd(phydev, MDIO_MMD_VEND1, diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index 98a09d670e9c..7275e4ee2298 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -6,6 +6,69 @@ #include "mtk.h" +/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is + * mtk_tr* functions: wrapped by page switching operations + * __mtk_tr* functions: no page switching operations + */ + +static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr, + u8 node_addr, u8 data_addr) +{ + u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */ + + if (read) + tr_cmd |= BIT(13); + + tr_cmd |= (((ch_addr & 0x3) << 11) | + ((node_addr & 0xf) << 7) | + ((data_addr & 0x3f) << 1)); + dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd); + __phy_write(phydev, 0x10, tr_cmd); +} + +static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u16 *tr_high, u16 *tr_low) +{ + __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr); + *tr_low = __phy_read(phydev, 0x11); + *tr_high = __phy_read(phydev, 0x12); + dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n", + *tr_high, *tr_low); +} + +static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 tr_data) +{ + __phy_write(phydev, 0x11, tr_data & 0xffff); + __phy_write(phydev, 0x12, tr_data >> 16); + dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n", + tr_data >> 16, tr_data & 0xffff); + __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr); +} + +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + u32 tr_data; + u16 tr_high; + u16 tr_low; + + __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); + tr_data = (tr_high << 16) | tr_low; + tr_data = (tr_data & ~mask) | set; + __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data); +} +EXPORT_SYMBOL_GPL(__mtk_tr_modify); + +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} +EXPORT_SYMBOL_GPL(mtk_tr_modify); + int mtk_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index a888e2e1dd6b..af44d1ad8c9e 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -68,6 +68,11 @@ struct mtk_socphy_priv { unsigned long led_state; }; +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); + int mtk_phy_read_page(struct phy_device *phydev); int mtk_phy_write_page(struct phy_device *phydev, int page); -- 2.51.0 From 3452f1a79d2394d16043c7d1ac424f16db88c232 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Thu, 13 Feb 2025 16:05:51 +0800 Subject: [PATCH 078/517] net: phy: mediatek: Add token ring set bit operation support Previously in mtk-ge-soc.c, we set some register bits via token ring, which were implemented in three __phy_write(). Now we can do the same thing via __mtk_tr_set_bits() helper. Signed-off-by: Sky Huang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250213080553.921434-4-SkyLake.Huang@mediatek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge-soc.c | 10 ++++++---- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 +++++++ drivers/net/phy/mediatek/mtk.h | 2 ++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index 5d7373793659..37777ad104d8 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -62,6 +62,10 @@ /* MasDSPreadyTime */ #define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7) +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */ +/* EnabRandUpdTrig */ +#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8) + /* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */ /* ResetSyncOffset */ #define RESET_SYNC_OFFSET_MASK GENMASK(11, 8) @@ -789,10 +793,8 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) | FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18)); - /* EnabRandUpdTrig = 1 */ - __phy_write(phydev, 0x11, 0x2f00); - __phy_write(phydev, 0x12, 0xe); - __phy_write(phydev, 0x10, 0x8fb0); + __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18, + ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER); __mtk_tr_modify(phydev, 0x0, 0x7, 0x15, NORMAL_MSE_LO_THRESH_MASK, diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index 7275e4ee2298..df8fdadcc0f4 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -69,6 +69,13 @@ void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, } EXPORT_SYMBOL_GPL(mtk_tr_modify); +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set); +} +EXPORT_SYMBOL_GPL(__mtk_tr_set_bits); + int mtk_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index af44d1ad8c9e..2d8e5b934a02 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -72,6 +72,8 @@ void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, u8 data_addr, u32 mask, u32 set); void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, u8 data_addr, u32 mask, u32 set); +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set); int mtk_phy_read_page(struct phy_device *phydev); int mtk_phy_write_page(struct phy_device *phydev, int page); -- 2.51.0 From ed0b08bbd81086c8298ae9dee01d0d935a74f374 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Thu, 13 Feb 2025 16:05:52 +0800 Subject: [PATCH 079/517] net: phy: mediatek: Add token ring clear bit operation support Similar to __mtk_tr_set_bits() support. Previously in mtk-ge-soc.c, we clear some register bits via token ring, which were also implemented in three __phy_write(). Now we can do the same thing via __mtk_tr_clr_bits() helper. Signed-off-by: Sky Huang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250213080553.921434-5-SkyLake.Huang@mediatek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge-soc.c | 30 +++++++++++++++----------- drivers/net/phy/mediatek/mtk-phy-lib.c | 7 ++++++ drivers/net/phy/mediatek/mtk.h | 2 ++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index 37777ad104d8..9de6fbb45564 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -76,6 +76,10 @@ /* FfeUpdGainForce */ #define FFE_UPDATE_GAIN_FORCE BIT(6) +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */ +/* TrFreeze */ +#define TR_FREEZE_MASK GENMASK(11, 0) + /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */ /* SS: Steady-state, KP: Proportional Gain */ /* SSTrKp100 */ @@ -91,6 +95,11 @@ /* SSTrKf1000Slv */ #define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4) +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */ +/* clear this bit if wanna select from AFE */ +/* Regsigdet_sel_1000 */ +#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4) + /* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */ /* RegEEE_st2TrKf1000 */ #define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11) @@ -113,6 +122,10 @@ /* RegEEE100Stg1_tar */ #define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0) +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */ +/* REGEEE_wake_slv_tr_wait_dfesigdet_en */ +#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11) + #define ANALOG_INTERNAL_OPERATION_MAX_US 20 #define TXRESERVE_MIN 0 #define TXRESERVE_MAX 7 @@ -805,10 +818,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev) FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) | FFE_UPDATE_GAIN_FORCE); - /* TrFreeze = 0 (mt7988 default) */ - __phy_write(phydev, 0x11, 0x0); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9686); + __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK); __mtk_tr_modify(phydev, 0x2, 0xd, 0x6, SS_TR_KP100_MASK | SS_TR_KF100_MASK | @@ -1009,10 +1019,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* Regsigdet_sel_1000 = 0 */ - __phy_write(phydev, 0x11, 0xb); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9690); + __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x8, + EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE); __mtk_tr_modify(phydev, 0x2, 0xd, 0xd, EEE1000_STAGE2_TR_KF_MASK, @@ -1036,10 +1044,8 @@ static void mt798x_phy_eee(struct phy_device *phydev) FIELD_PREP(EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK, 0x10)); - /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ - __phy_write(phydev, 0x11, 0x1463); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96ca); + __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x25, + WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN); __mtk_tr_modify(phydev, 0x1, 0xf, 0x0, DFE_TAIL_EANBLE_VGA_TRHESH_1000, diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index df8fdadcc0f4..dfd0f4e439a2 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -76,6 +76,13 @@ void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, } EXPORT_SYMBOL_GPL(__mtk_tr_set_bits); +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0); +} +EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits); + int mtk_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index 2d8e5b934a02..4e4468dc0234 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -74,6 +74,8 @@ void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, u8 data_addr, u32 mask, u32 set); void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, u8 data_addr, u32 set); +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr); int mtk_phy_read_page(struct phy_device *phydev); int mtk_phy_write_page(struct phy_device *phydev, int page); -- 2.51.0 From d3ad9045643e6c80993d9e1e033bf6fc8b4c35a5 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Thu, 13 Feb 2025 16:05:53 +0800 Subject: [PATCH 080/517] net: phy: mediatek: Move some macros to phy-lib for later use Move some macros to phy-lib because MediaTek's 2.5G built-in ethernet PHY will also use them. Signed-off-by: Sky Huang Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250213080553.921434-6-SkyLake.Huang@mediatek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge.c | 4 ---- drivers/net/phy/mediatek/mtk.h | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index a24c5ba469ba..73d9b72f9d9e 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -8,10 +8,6 @@ #define MTK_GPHY_ID_MT7530 0x03a29412 #define MTK_GPHY_ID_MT7531 0x03a29441 -#define MTK_PHY_PAGE_EXTENDED_1 0x0001 -#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 -#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) - #define MTK_PHY_PAGE_EXTENDED_2 0x0002 #define MTK_PHY_PAGE_EXTENDED_3 0x0003 #define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG11 0x11 diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h index 4e4468dc0234..320f76ffa81f 100644 --- a/drivers/net/phy/mediatek/mtk.h +++ b/drivers/net/phy/mediatek/mtk.h @@ -8,7 +8,11 @@ #ifndef _MTK_EPHY_H_ #define _MTK_EPHY_H_ +#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 +#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) + #define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_EXTENDED_1 0x0001 #define MTK_PHY_PAGE_STANDARD 0x0000 #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 -- 2.51.0 From af060cc711880b488a95c56cf7e0fb28f2e71b22 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 10 Apr 2025 12:04:03 +0200 Subject: [PATCH 081/517] net: phy: mediatek: permit to compile test GE SOC PHY driver When commit 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies") fixed the dependency, it should have also introduced an or on COMPILE_TEST to permit this driver to be compile-tested even if NVMEM_MTK_EFUSE wasn't selected. The driver makes use of NVMEM API that are always compiled (return error) so the driver can actually be compiled even without that config. Fix and simplify the dependency condition of this kernel config. Fixes: 462a3daad679 ("net: phy: mediatek: fix compile-test dependencies") Acked-by: Daniel Golle Reviewed-by: Andrew Lunn Signed-off-by: Christian Marangi Acked-by: Arnd Bergmann Link: https://patch.msgid.link/20250410100410.348-1-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index 2a8ac5aed0f8..6a4c2b328c41 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -15,8 +15,7 @@ config MEDIATEK_GE_PHY config MEDIATEK_GE_SOC_PHY tristate "MediaTek SoC Ethernet PHYs" - depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST - depends on NVMEM_MTK_EFUSE + depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST select MTK_NET_PHYLIB help Supports MediaTek SoC built-in Gigabit Ethernet PHYs. -- 2.51.0 From 42073f8fa909d98142b7754ce0f020d96b0bf48e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 10 Apr 2025 12:04:04 +0200 Subject: [PATCH 082/517] net: phy: mediatek: add Airoha PHY ID to SoC driver Airoha AN7581 SoC ship with a Switch based on the MT753x Switch embedded in other SoC like the MT7581 and the MT7988. Similar to these they require configuring some pin to enable LED PHYs. Add support for the PHY ID for the Airoha embedded Switch and define a simple probe function to toggle these pins. Also fill the LED functions and add dedicated function to define LED polarity. Reviewed-by: Andrew Lunn Signed-off-by: Christian Marangi Link: https://patch.msgid.link/20250410100410.348-2-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/Kconfig | 4 +- drivers/net/phy/mediatek/mtk-ge-soc.c | 62 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index 6a4c2b328c41..4308002bb82c 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -15,7 +15,9 @@ config MEDIATEK_GE_PHY config MEDIATEK_GE_SOC_PHY tristate "MediaTek SoC Ethernet PHYs" - depends on (ARM64 && ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || COMPILE_TEST + depends on ARM64 || COMPILE_TEST + depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \ + COMPILE_TEST select MTK_NET_PHYLIB help Supports MediaTek SoC built-in Gigabit Ethernet PHYs. diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index 9de6fbb45564..fea2a55764f1 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -10,8 +10,11 @@ #include "mtk.h" +#define MTK_PHY_MAX_LEDS 2 + #define MTK_GPHY_ID_MT7981 0x03a29461 #define MTK_GPHY_ID_MT7988 0x03a29481 +#define MTK_GPHY_ID_AN7581 0x03a294c1 #define MTK_EXT_PAGE_ACCESS 0x1f #define MTK_PHY_PAGE_STANDARD 0x0000 @@ -1405,6 +1408,53 @@ static int mt7981_phy_probe(struct phy_device *phydev) return mt798x_phy_calibration(phydev); } +static int an7581_phy_probe(struct phy_device *phydev) +{ + struct mtk_socphy_priv *priv; + struct pinctrl *pinctrl; + + /* Toggle pinctrl to enable PHY LED */ + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); + if (IS_ERR(pinctrl)) + dev_err(&phydev->mdio.bus->dev, + "Failed to setup PHY LED pinctrl\n"); + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + u32 mode; + u16 val; + + if (index >= MTK_PHY_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + val = MTK_PHY_LED_ON_POLARITY; + break; + case PHY_LED_ACTIVE_HIGH: + val = 0; + break; + default: + return -EINVAL; + } + } + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY, val); +} + static struct phy_driver mtk_socphy_driver[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), @@ -1440,6 +1490,17 @@ static struct phy_driver mtk_socphy_driver[] = { .led_hw_control_set = mt798x_phy_led_hw_control_set, .led_hw_control_get = mt798x_phy_led_hw_control_get, }, + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581), + .name = "Airoha AN7581 PHY", + .probe = an7581_phy_probe, + .led_blink_set = mt798x_phy_led_blink_set, + .led_brightness_set = mt798x_phy_led_brightness_set, + .led_hw_is_supported = mt798x_phy_led_hw_is_supported, + .led_hw_control_set = mt798x_phy_led_hw_control_set, + .led_hw_control_get = mt798x_phy_led_hw_control_get, + .led_polarity_set = an7581_phy_led_polarity_set, + }, }; module_phy_driver(mtk_socphy_driver); @@ -1447,6 +1508,7 @@ module_phy_driver(mtk_socphy_driver); static const struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_AN7581) }, { } }; -- 2.51.0 From 1b9be68d030e01f77d09abc1307fb7abb7f3a351 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 15 Apr 2025 12:53:05 +0200 Subject: [PATCH 083/517] net: phy: mediatek: init val in .phy_led_polarity_set for AN7581 Fix smatch warning for uninitialised val in .phy_led_polarity_set for AN7581 driver. Correctly init to 0 to set polarity high by default. Reported-by: Simon Horman Fixes: 6a325aed130b ("net: phy: mediatek: add Airoha PHY ID to SoC driver") Signed-off-by: Christian Marangi Link: https://patch.msgid.link/20250415105313.3409-1-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mediatek/mtk-ge-soc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index fea2a55764f1..6be49447d10d 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -1431,8 +1431,8 @@ static int an7581_phy_probe(struct phy_device *phydev) static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) { + u16 val = 0; u32 mode; - u16 val; if (index >= MTK_PHY_MAX_LEDS) return -EINVAL; @@ -1443,7 +1443,6 @@ static int an7581_phy_led_polarity_set(struct phy_device *phydev, int index, val = MTK_PHY_LED_ON_POLARITY; break; case PHY_LED_ACTIVE_HIGH: - val = 0; break; default: return -EINVAL; -- 2.51.0 From 613f6f7764030e9abaace9416e36333b26dbbd65 Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Mon, 17 Feb 2025 17:40:21 +0800 Subject: [PATCH 084/517] net: ethernet: mediatek: add EEE support Add EEE support to MediaTek SoC Ethernet. The register fields are similar to the ones in MT7531, except that the LPI threshold is in milliseconds. Signed-off-by: Qingfang Deng --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 69 +++++++++++++++++++++ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 ++++ 2 files changed, 82 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 64d86068b51e..2a0be107b3d7 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -782,6 +782,7 @@ static void mtk_mac_link_up(struct phylink_config *config, mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | + MAC_MCR_EEE100M | MAC_MCR_EEE1G | MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | MAC_MCR_FORCE_RX_FC); @@ -807,6 +808,15 @@ static void mtk_mac_link_up(struct phylink_config *config, if (rx_pause) mcr |= MAC_MCR_FORCE_RX_FC; + if (mode == MLO_AN_PHY && phy && mac->tx_lpi_enabled && phy_init_eee(phy, false) >= 0) { + mcr |= MAC_MCR_EEE100M | MAC_MCR_EEE1G; + mtk_w32(mac->hw, + FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) | + FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36) | + FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, mac->txidle_thd_ms), + MTK_MAC_EEECR(mac->id)); + } + mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK; mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } @@ -4514,6 +4524,61 @@ static int mtk_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam return phylink_ethtool_set_pauseparam(mac->phylink, pause); } +static int mtk_get_eee(struct net_device *dev, struct ethtool_keee *eee) +{ + struct mtk_mac *mac = netdev_priv(dev); + u32 reg; + int ret; + + ret = phylink_ethtool_get_eee(mac->phylink, eee); + if (ret) + return ret; + + reg = mtk_r32(mac->hw, MTK_MAC_EEECR(mac->id)); + eee->tx_lpi_enabled = mac->tx_lpi_enabled; + eee->tx_lpi_timer = FIELD_GET(MAC_EEE_LPI_TXIDLE_THD, reg) * 1000; + + return 0; +} + +static int mtk_set_eee(struct net_device *dev, struct ethtool_keee *eee) +{ + struct mtk_mac *mac = netdev_priv(dev); + u32 txidle_thd_ms, reg; + int ret; + + /* Tx idle timer in ms */ + txidle_thd_ms = DIV_ROUND_UP(eee->tx_lpi_timer, 1000); + if (!FIELD_FIT(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms)) + return -EINVAL; + + reg = FIELD_PREP(MAC_EEE_LPI_TXIDLE_THD, txidle_thd_ms); + + /* PHY Wake-up time, this field does not have a reset value, so use the + * reset value from MT7531 (36us for 100BaseT and 17us for 1000BaseT). + */ + reg |= FIELD_PREP(MAC_EEE_WAKEUP_TIME_1000, 17) | + FIELD_PREP(MAC_EEE_WAKEUP_TIME_100, 36); + + if (!txidle_thd_ms) + /* Force LPI Mode without a delay */ + reg |= MAC_EEE_LPI_MODE; + + ret = phylink_ethtool_set_eee(mac->phylink, eee); + if (ret) + return ret; + + mac->tx_lpi_enabled = eee->tx_lpi_enabled; + mac->txidle_thd_ms = txidle_thd_ms; + mtk_w32(mac->hw, reg, MTK_MAC_EEECR(mac->id)); + if (eee->eee_enabled && eee->eee_active && eee->tx_lpi_enabled) + mtk_m32(mac->hw, 0, MAC_MCR_EEE100M | MAC_MCR_EEE1G, MTK_MAC_MCR(mac->id)); + else + mtk_m32(mac->hw, MAC_MCR_EEE100M | MAC_MCR_EEE1G, 0, MTK_MAC_MCR(mac->id)); + + return 0; +} + static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { @@ -4546,6 +4611,8 @@ static const struct ethtool_ops mtk_ethtool_ops = { .set_pauseparam = mtk_set_pauseparam, .get_rxnfc = mtk_get_rxnfc, .set_rxnfc = mtk_set_rxnfc, + .get_eee = mtk_get_eee, + .set_eee = mtk_set_eee, }; static const struct net_device_ops mtk_netdev_ops = { @@ -4606,6 +4673,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) } mac = netdev_priv(eth->netdev[id]); eth->mac[id] = mac; + mac->tx_lpi_enabled = true; + mac->txidle_thd_ms = 1; mac->id = id; mac->hw = eth; mac->of_node = np; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 0570623e569d..723475570ff7 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -461,6 +461,8 @@ #define MAC_MCR_RX_FIFO_CLR_DIS BIT(12) #define MAC_MCR_BACKOFF_EN BIT(9) #define MAC_MCR_BACKPR_EN BIT(8) +#define MAC_MCR_EEE1G BIT(7) +#define MAC_MCR_EEE100M BIT(6) #define MAC_MCR_FORCE_RX_FC BIT(5) #define MAC_MCR_FORCE_TX_FC BIT(4) #define MAC_MCR_SPEED_1000 BIT(3) @@ -469,6 +471,15 @@ #define MAC_MCR_FORCE_LINK BIT(0) #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE) +/* Mac EEE control registers */ +#define MTK_MAC_EEECR(x) (0x10104 + (x * 0x100)) +#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24) +#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16) +#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8) +#define MAC_EEE_CKG_TXIDLE BIT(3) +#define MAC_EEE_CKG_RXLPI BIT(2) +#define MAC_EEE_LPI_MODE BIT(0) + /* Mac status registers */ #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100)) #define MAC_MSR_EEE1G BIT(7) @@ -1316,6 +1327,8 @@ struct mtk_mac { int id; phy_interface_t interface; u8 ppe_idx; + bool tx_lpi_enabled; + u8 txidle_thd_ms; int speed; struct device_node *of_node; struct phylink *phylink; -- 2.51.0 From 14f7dbcdc4a40f631df9774ef69d7ba583ad830d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 4 Oct 2024 17:18:16 +0100 Subject: [PATCH 085/517] net: phy: aquantia: allow forcing order of MDI pairs Despite supporting Auto MDI-X, it looks like Aquantia only supports swapping pair (1,2) with pair (3,6) like it used to be for MDI-X on 100MBit/s networks. When all 4 pairs are in use (for 1000MBit/s or faster) the link does not come up with pair order is not configured correctly, either using MDI_CFG pin or using the "PMA Receive Reserved Vendor Provisioning 1" register. Normally, the order of MDI pairs being either ABCD or DCBA is configured by pulling the MDI_CFG pin. However, some hardware designs require overriding the value configured by that bootstrap pin. The PHY allows doing that by setting a bit in "PMA Receive Reserved Vendor Provisioning 1" register which allows ignoring the state of the MDI_CFG pin and another bit configuring whether the order of MDI pairs should be normal (ABCD) or reverse (DCBA). Pair polarity is not affected and remains identical in both settings. Introduce property "marvell,mdi-cfg-order" which allows forcing either normal or reverse order of the MDI pairs from DT. If the property isn't present, the behavior is unchanged and MDI pair order configuration is untouched (ie. either the result of MDI_CFG pin pull-up/pull-down, or pair order override already configured by the bootloader before Linux is started). Forcing normal pair order is required on the Adtran SDG-8733A Wi-Fi 7 residential gateway. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/9ed760ff87d5fc456f31e407ead548bbb754497d.1728058550.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/aquantia/aquantia_main.c | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 840ef5ad07ff..5cdc16fade22 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "aquantia.h" @@ -71,6 +72,11 @@ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) +#define PMAPMD_RSVD_VEND_PROV 0xe400 +#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0) +#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0) +#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1) + #define MDIO_AN_RX_LP_STAT1 0xe820 #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) @@ -485,6 +491,29 @@ static void aqr107_chip_info(struct phy_device *phydev) fw_major, fw_minor, build_id, prov_id); } +static int aqr107_config_mdi(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + u32 mdi_conf; + int ret; + + ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); + + /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ + if (ret == -ENOENT) + return 0; + + if (ret) + return ret; + + if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE) + return -EINVAL; + + return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV, + PMAPMD_RSVD_VEND_PROV_MDI_CONF, + mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE); +} + static int aqr107_config_init(struct phy_device *phydev) { struct aqr107_priv *priv = phydev->priv; @@ -514,6 +543,10 @@ static int aqr107_config_init(struct phy_device *phydev) if (ret) return ret; + ret = aqr107_config_mdi(phydev); + if (ret) + return ret; + /* Restore LED polarity state after reset */ for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); -- 2.51.0 From 4894e830a84456398eef38e8084612ae21934af3 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 11 Oct 2024 22:28:43 +0100 Subject: [PATCH 086/517] net: phy: aquantia: fix return value check in aqr107_config_mdi() of_property_read_u32() returns -EINVAL in case the property cannot be found rather than -ENOENT. Fix the check to not abort probing in case of the property being missing, and also in case CONFIG_OF is not set which will result in -ENOSYS. Fixes: a2e1ba275eae ("net: phy: aquantia: allow forcing order of MDI pairs") Reported-by: Jon Hunter Closes: https://lore.kernel.org/all/114b4c03-5d16-42ed-945d-cf78eabea12b@nvidia.com/ Suggested-by: Hans-Frieder Vogt Signed-off-by: Daniel Golle --- drivers/net/phy/aquantia/aquantia_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 5cdc16fade22..2c9bc3ea6b7e 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -500,7 +500,7 @@ static int aqr107_config_mdi(struct phy_device *phydev) ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ - if (ret == -ENOENT) + if (ret == -EINVAL || ret == -ENOSYS) return 0; if (ret) -- 2.51.0 From 287435caf87bb50f31293db553d5a838b668c98b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 13:54:19 +0100 Subject: [PATCH 087/517] net: phy: support 'active-high' property for PHY LEDs In addition to 'active-low' and 'inactive-high-impedance' also support 'active-high' property for PHY LED pin configuration. As only either 'active-high' or 'active-low' can be set at the same time, WARN and return an error in case both are set. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/91598487773d768f254d5faf06cf65b13e972f0e.1728558223.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/phy_device.c | 6 ++++++ include/linux/phy.h | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 834624a61060..762f909242b4 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3387,11 +3387,17 @@ static int of_phy_led(struct phy_device *phydev, if (index > U8_MAX) return -EINVAL; + if (of_property_read_bool(led, "active-high")) + set_bit(PHY_LED_ACTIVE_HIGH, &modes); if (of_property_read_bool(led, "active-low")) set_bit(PHY_LED_ACTIVE_LOW, &modes); if (of_property_read_bool(led, "inactive-high-impedance")) set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); + if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) && + modes & BIT(PHY_LED_ACTIVE_HIGH))) + return -EINVAL; + if (modes) { /* Return error if asked to set polarity modes but not supported */ if (!phydev->drv->led_polarity_set) diff --git a/include/linux/phy.h b/include/linux/phy.h index 81c504d9850e..df147d9d302f 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -892,8 +892,9 @@ struct phy_plca_status { /* Modes for PHY LED configuration */ enum phy_led_modes { - PHY_LED_ACTIVE_LOW = 0, - PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1, + PHY_LED_ACTIVE_HIGH = 0, + PHY_LED_ACTIVE_LOW = 1, + PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2, /* keep it last */ __PHY_LED_MODES_NUM, -- 2.51.0 From ade63dd8be886ca940ab87741aa9497e52fec15f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 13:55:00 +0100 Subject: [PATCH 088/517] net: phy: aquantia: correctly describe LED polarity override Use newly defined 'active-high' property to set the VEND1_GLOBAL_LED_DRIVE_VDD bit and let 'active-low' clear that bit. This reflects the technical reality which was inverted in the previous description in which the 'active-low' property was used to actually set the VEND1_GLOBAL_LED_DRIVE_VDD bit, which means that VDD (ie. supply voltage) of the LED is driven rather than GND. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/86a413b4387c42dcb54f587cc2433a06f16aae83.1728558223.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/aquantia/aquantia.h | 1 + drivers/net/phy/aquantia/aquantia_leds.c | 19 ++++++++++++++----- drivers/net/phy/aquantia/aquantia_main.c | 12 +++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index 2465345081f8..0c78bfabace5 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -177,6 +177,7 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = { struct aqr107_priv { u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; unsigned long leds_active_low; + unsigned long leds_active_high; }; #if IS_REACHABLE(CONFIG_HWMON) diff --git a/drivers/net/phy/aquantia/aquantia_leds.c b/drivers/net/phy/aquantia/aquantia_leds.c index 201c8df93fad..00ad2313fed3 100644 --- a/drivers/net/phy/aquantia/aquantia_leds.c +++ b/drivers/net/phy/aquantia/aquantia_leds.c @@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable { return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index), VEND1_GLOBAL_LED_DRIVE_VDD, - enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0); + enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD); } int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) { + bool force_active_low = false, force_active_high = false; struct aqr107_priv *priv = phydev->priv; - bool active_low = false; u32 mode; if (index >= AQR_MAX_LEDS) @@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { switch (mode) { case PHY_LED_ACTIVE_LOW: - active_low = true; + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; break; default: return -EINVAL; @@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long } /* Save LED driver vdd state to restore on SW reset */ - if (active_low) + if (force_active_low) priv->leds_active_low |= BIT(index); - return aqr_phy_led_active_low_set(phydev, index, active_low); + if (force_active_high) + priv->leds_active_high |= BIT(index); + + if (force_active_high || force_active_low) + return aqr_phy_led_active_low_set(phydev, index, force_active_low); + + unreachable(); } diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 2c9bc3ea6b7e..2008b98c689e 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -517,7 +517,7 @@ static int aqr107_config_mdi(struct phy_device *phydev) static int aqr107_config_init(struct phy_device *phydev) { struct aqr107_priv *priv = phydev->priv; - u32 led_active_low; + u32 led_idx; int ret; /* Check that the PHY interface type is compatible */ @@ -548,8 +548,14 @@ static int aqr107_config_init(struct phy_device *phydev) return ret; /* Restore LED polarity state after reset */ - for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { - ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); + for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) { + ret = aqr_phy_led_active_low_set(phydev, led_idx, true); + if (ret) + return ret; + } + + for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) { + ret = aqr_phy_led_active_low_set(phydev, led_idx, false); if (ret) return ret; } -- 2.51.0 From a42b398e079cfe3f521ca96540d1b2c7f5ce4a57 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 1 Oct 2024 01:17:18 +0100 Subject: [PATCH 089/517] net: phy: mxl-gpy: add basic LED support Add basic support for LEDs connected to MaxLinear GPY2xx and GPY115 PHYs. The PHYs allow up to 4 LEDs to be connected. Implement controlling LEDs in software as well as netdev trigger offloading and LED polarity setup. The hardware claims to support 16 PWM brightness levels but there is no documentation on how to use that feature, hence this is not supported. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/b6ec9050339f8244ff898898a1cecc33b13a48fc.1727741563.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/mxl-gpy.c | 218 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index d145b67a067f..9930e6167f89 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -38,6 +38,7 @@ #define PHY_MIISTAT 0x18 /* MII state */ #define PHY_IMASK 0x19 /* interrupt mask */ #define PHY_ISTAT 0x1A /* interrupt status */ +#define PHY_LED 0x1B /* LEDs */ #define PHY_FWV 0x1E /* firmware version */ #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) @@ -61,6 +62,11 @@ PHY_IMASK_ADSC | \ PHY_IMASK_ANC) +#define GPY_MAX_LEDS 4 +#define PHY_LED_POLARITY(idx) BIT(12 + (idx)) +#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx)) +#define PHY_LED_ON(idx) BIT(idx) + #define PHY_FWV_REL_MASK BIT(15) #define PHY_FWV_MAJOR_MASK GENMASK(11, 8) #define PHY_FWV_MINOR_MASK GENMASK(7, 0) @@ -72,6 +78,23 @@ #define PHY_MDI_MDI_X_CD 0x1 #define PHY_MDI_MDI_X_CROSS 0x0 +/* LED */ +#define VSPEC1_LED(idx) (1 + (idx)) +#define VSPEC1_LED_BLINKS GENMASK(15, 12) +#define VSPEC1_LED_PULSE GENMASK(11, 8) +#define VSPEC1_LED_CON GENMASK(7, 4) +#define VSPEC1_LED_BLINKF GENMASK(3, 0) + +#define VSPEC1_LED_LINK10 BIT(0) +#define VSPEC1_LED_LINK100 BIT(1) +#define VSPEC1_LED_LINK1000 BIT(2) +#define VSPEC1_LED_LINK2500 BIT(3) + +#define VSPEC1_LED_TXACT BIT(0) +#define VSPEC1_LED_RXACT BIT(1) +#define VSPEC1_LED_COL BIT(2) +#define VSPEC1_LED_NO_CON BIT(3) + /* SGMII */ #define VSPEC1_SGMII_CTRL 0x08 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ @@ -835,6 +858,156 @@ static int gpy115_loopback(struct phy_device *phydev, bool enable) return genphy_soft_reset(phydev); } +static int gpy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int ret; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + /* clear HWCONTROL and set manual LED state */ + ret = phy_modify(phydev, PHY_LED, + ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) | + PHY_LED_ON(index), + (value == LED_OFF) ? 0 : PHY_LED_ON(index)); + if (ret) + return ret; + + /* ToDo: set PWM brightness */ + + /* clear HW LED setup */ + if (value == LED_OFF) + return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0); + else + return 0; +} + +static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX)); + +static int gpy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} + +static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int val; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index)); + if (val < 0) + return val; + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + + if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 | + VSPEC1_LED_LINK100 | + VSPEC1_LED_LINK1000 | + VSPEC1_LED_LINK2500)) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT) + *rules |= BIT(TRIGGER_NETDEV_TX); + + if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT) + *rules |= BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 val = 0; + int ret; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_10)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_100)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_1000)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_2500)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500); + + if (rules & BIT(TRIGGER_NETDEV_TX)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT); + + if (rules & BIT(TRIGGER_NETDEV_RX)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT); + + /* allow RX/TX pulse without link indication */ + if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) && + !(val & VSPEC1_LED_CON)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val); + if (ret) + return ret; + + return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index)); +} + +static int gpy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool active_low = false; + u32 mode; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + active_low = true; + break; + default: + return -EINVAL; + } + } + + return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index), + active_low ? 0 : PHY_LED_POLARITY(index)); +} + static struct phy_driver gpy_drivers[] = { { PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx), @@ -852,6 +1025,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY115B, @@ -870,6 +1048,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy115_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY115C), @@ -887,6 +1070,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy115_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY211B, @@ -905,6 +1093,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), @@ -922,6 +1115,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY212B, @@ -940,6 +1138,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), @@ -957,6 +1160,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY215B, @@ -975,6 +1183,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), @@ -992,6 +1205,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY241B), -- 2.51.0 From 4f581169cc4a1bc0610a94c19e7a7e7dcee4bc42 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 4 Oct 2024 16:56:35 +0100 Subject: [PATCH 090/517] net: phy: mxl-gpy: add missing support for TRIGGER_NETDEV_LINK_10 The PHY also support 10MBit/s links as well as the corresponding link indication trigger to be offloaded. Add TRIGGER_NETDEV_LINK_10 to the supported triggers. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/cc5da0a989af8b0d49d823656d88053c4de2ab98.1728057367.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/mxl-gpy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index 9930e6167f89..9864b9d2944f 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -884,6 +884,7 @@ static int gpy_led_brightness_set(struct phy_device *phydev, } static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_2500) | -- 2.51.0 From af00b072a7746a00880530c75cd1b9d35e1427e8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 13:55:17 +0100 Subject: [PATCH 091/517] net: phy: mxl-gpy: correctly describe LED polarity According the datasheet covering the LED (0x1b) register: 0B Active High LEDx pin driven high when activated 1B Active Low LEDx pin driven low when activated Make use of the now available 'active-high' property and correctly reflect the polarity setting which was previously inverted. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/180ccafa837f09908b852a8a874a3808c5ecd2d0.1728558223.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/mxl-gpy.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index 9864b9d2944f..e0bdbb66df5c 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -989,7 +989,7 @@ static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index, static int gpy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) { - bool active_low = false; + bool force_active_low = false, force_active_high = false; u32 mode; if (index >= GPY_MAX_LEDS) @@ -998,15 +998,23 @@ static int gpy_led_polarity_set(struct phy_device *phydev, int index, for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { switch (mode) { case PHY_LED_ACTIVE_LOW: - active_low = true; + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; break; default: return -EINVAL; } } - return phy_modify(phydev, PHY_LED, PHY_LED_POLARITY(index), - active_low ? 0 : PHY_LED_POLARITY(index)); + if (force_active_low) + return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); + + if (force_active_high) + return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); + + unreachable(); } static struct phy_driver gpy_drivers[] = { -- 2.51.0 From 7ca1cf2b83a6acbdebc09b38921704e387945d88 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 13:55:29 +0100 Subject: [PATCH 092/517] net: phy: intel-xway: add support for PHY LEDs The intel-xway PHY driver predates the PHY LED framework and currently initializes all LED pins to equal default values. Add PHY LED functions to the drivers and don't set default values if LEDs are defined in device tree. According the datasheets 3 LEDs are supported on all Intel XWAY PHYs. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/81f4717ab9acf38f3239727a4540ae96fd01109b.1728558223.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/intel-xway.c | 253 +++++++++++++++++++++++++++++++++-- 1 file changed, 244 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index fad411b93c15..62ab1fbef16c 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -151,6 +151,13 @@ #define XWAY_MMD_LED3H 0x01E8 #define XWAY_MMD_LED3L 0x01E9 +#define XWAY_GPHY_MAX_LEDS 3 +#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx)) +#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx)) +#define XWAY_GPHY_LED_DA(idx) BIT(idx) +#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx)) +#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx)) + #define PHY_ID_PHY11G_1_3 0x030260D1 #define PHY_ID_PHY22F_1_3 0x030260E1 #define PHY_ID_PHY11G_1_4 0xD565A400 @@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct phy_device *phydev) XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); } -static int xway_gphy_config_init(struct phy_device *phydev) +static int xway_gphy_init_leds(struct phy_device *phydev) { int err; u32 ledxh; u32 ledxl; - /* Mask all interrupts */ - err = phy_write(phydev, XWAY_MDIO_IMASK, 0); - if (err) - return err; - - /* Clear all pending interrupts */ - phy_read(phydev, XWAY_MDIO_ISTAT); - /* Ensure that integrated led function is enabled for all leds */ err = phy_write(phydev, XWAY_MDIO_LED, XWAY_MDIO_LED_LED0_EN | @@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct phy_device *phydev) phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); + return 0; +} + +static int xway_gphy_config_init(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + int err; + + /* Mask all interrupts */ + err = phy_write(phydev, XWAY_MDIO_IMASK, 0); + if (err) + return err; + + /* Use default LED configuration if 'leds' node isn't defined */ + if (!of_get_child_by_name(np, "leds")) + xway_gphy_init_leds(phydev); + + /* Clear all pending interrupts */ + phy_read(phydev, XWAY_MDIO_ISTAT); + err = xway_gphy_rgmii_init(phydev); if (err) return err; @@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int xway_gphy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int ret; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + /* clear EN and set manual LED state */ + ret = phy_modify(phydev, XWAY_MDIO_LED, + ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) | + XWAY_GPHY_LED_DA(index), + (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index)); + if (ret) + return ret; + + /* clear HW LED setup */ + if (value == LED_OFF) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0); + } else { + return 0; + } +} + +static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX)); + +static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + /* activity triggers are not possible without combination with a link + * trigger. + */ + if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) && + !(rules & (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000)))) + return -EOPNOTSUPP; + + /* All other combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} + +static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int lval, hval; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index)); + if (hval < 0) + return hval; + + lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index)); + if (lval < 0) + return lval; + + if (hval & XWAY_MMD_LEDxH_CON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (hval & XWAY_MMD_LEDxH_CON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (hval & XWAY_MMD_LEDxH_CON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if ((hval & XWAY_MMD_LEDxH_CON_LINK10) && + (hval & XWAY_MMD_LEDxH_CON_LINK100) && + (hval & XWAY_MMD_LEDxH_CON_LINK1000)) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (lval & XWAY_MMD_LEDxL_PULSE_TXACT) + *rules |= BIT(TRIGGER_NETDEV_TX); + + if (lval & XWAY_MMD_LEDxL_PULSE_RXACT) + *rules |= BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 hval = 0, lval = 0; + int ret; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_10)) + hval |= XWAY_MMD_LEDxH_CON_LINK10; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_100)) + hval |= XWAY_MMD_LEDxH_CON_LINK100; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_1000)) + hval |= XWAY_MMD_LEDxH_CON_LINK1000; + + if (rules & BIT(TRIGGER_NETDEV_TX)) + lval |= XWAY_MMD_LEDxL_PULSE_TXACT; + + if (rules & BIT(TRIGGER_NETDEV_RX)) + lval |= XWAY_MMD_LEDxL_PULSE_RXACT; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval); + if (ret) + return ret; + + return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index)); +} + +static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool force_active_low = false, force_active_high = false; + u32 mode; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; + break; + default: + return -EINVAL; + } + } + + if (force_active_low) + return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); + + if (force_active_high) + return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); + + unreachable(); +} + static struct phy_driver xway_gphy[] = { { .phy_id = PHY_ID_PHY11G_1_3, @@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_3, .phy_id_mask = 0xffffffff, @@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_1_4, .phy_id_mask = 0xffffffff, @@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_4, .phy_id_mask = 0xffffffff, @@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_1_5, .phy_id_mask = 0xffffffff, @@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_5, .phy_id_mask = 0xffffffff, @@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_VR9_1_1, .phy_id_mask = 0xffffffff, @@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_VR9_1_1, .phy_id_mask = 0xffffffff, @@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_VR9_1_2, .phy_id_mask = 0xffffffff, @@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_VR9_1_2, .phy_id_mask = 0xffffffff, @@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, }; module_phy_driver(xway_gphy); -- 2.51.0 From 1bb33829d7d380fe3083f49d28968e268c6faf00 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 Aug 2025 06:57:23 +0200 Subject: [PATCH 093/517] net: mediatek: wed: Introduce MT7992 WED support to MT7988 SoC Introduce the second WDMA RX ring in WED driver for MT7988 SoC since the Mediatek MT7992 WiFi chipset supports two separated WDMA rings. Add missing MT7988 configurations to properly support WED for MT7992 in MT76 driver. Co-developed-by: Rex Lu Signed-off-by: Rex Lu Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250812-mt7992-wed-support-v3-1-9ada78a819a4@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mediatek/mtk_wed.c | 33 ++++++++++++++++++++----- drivers/net/ethernet/mediatek/mtk_wed.h | 2 +- include/linux/soc/mediatek/mtk_wed.h | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 499ca7000125..e7021d0622b0 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -59,7 +59,9 @@ struct mtk_wed_flow_block_priv { static const struct mtk_wed_soc_data mt7622_data = { .regmap = { .tx_bm_tkid = 0x088, - .wpdma_rx_ring0 = 0x770, + .wpdma_rx_ring = { + 0x770, + }, .reset_idx_tx_mask = GENMASK(3, 0), .reset_idx_rx_mask = GENMASK(17, 16), }, @@ -70,7 +72,9 @@ static const struct mtk_wed_soc_data mt7622_data = { static const struct mtk_wed_soc_data mt7986_data = { .regmap = { .tx_bm_tkid = 0x0c8, - .wpdma_rx_ring0 = 0x770, + .wpdma_rx_ring = { + 0x770, + }, .reset_idx_tx_mask = GENMASK(1, 0), .reset_idx_rx_mask = GENMASK(7, 6), }, @@ -81,7 +85,10 @@ static const struct mtk_wed_soc_data mt7986_data = { static const struct mtk_wed_soc_data mt7988_data = { .regmap = { .tx_bm_tkid = 0x0c8, - .wpdma_rx_ring0 = 0x7d0, + .wpdma_rx_ring = { + 0x7d0, + 0x7d8, + }, .reset_idx_tx_mask = GENMASK(1, 0), .reset_idx_rx_mask = GENMASK(7, 6), }, @@ -621,8 +628,8 @@ mtk_wed_amsdu_init(struct mtk_wed_device *dev) return ret; } - /* eagle E1 PCIE1 tx ring 22 flow control issue */ - if (dev->wlan.id == 0x7991) + /* Kite and Eagle E1 PCIE1 tx ring 22 flow control issue */ + if (dev->wlan.id == 0x7991 || dev->wlan.id == 0x7992) wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING); wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN); @@ -1239,7 +1246,11 @@ mtk_wed_set_wpdma(struct mtk_wed_device *dev) return; wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo); - wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx); + wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[0], + dev->wlan.wpdma_rx[0]); + if (mtk_wed_is_v3_or_greater(dev->hw)) + wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring[1], + dev->wlan.wpdma_rx[1]); if (!dev->wlan.hw_rro) return; @@ -2335,6 +2346,16 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) if (!dev->rx_wdma[i].desc) mtk_wed_wdma_rx_ring_setup(dev, i, 16, false); + if (dev->wlan.hw_rro) { + for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) { + u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) + + MTK_WED_RING_OFS_COUNT; + + if (!wed_r32(dev, addr)) + wed_w32(dev, addr, 1); + } + } + mtk_wed_hw_init(dev); mtk_wed_configure_irq(dev, irq_mask); diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h index c1f0479d7a71..b49aee9a8b65 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.h +++ b/drivers/net/ethernet/mediatek/mtk_wed.h @@ -17,7 +17,7 @@ struct mtk_wed_wo; struct mtk_wed_soc_data { struct { u32 tx_bm_tkid; - u32 wpdma_rx_ring0; + u32 wpdma_rx_ring[MTK_WED_RX_QUEUES]; u32 reset_idx_tx_mask; u32 reset_idx_rx_mask; } regmap; diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index a476648858a6..5ab3a93a7be9 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -147,7 +147,7 @@ struct mtk_wed_device { u32 wpdma_tx; u32 wpdma_txfree; u32 wpdma_rx_glo; - u32 wpdma_rx; + u32 wpdma_rx[MTK_WED_RX_QUEUES]; u32 wpdma_rx_rro[MTK_WED_RX_QUEUES]; u32 wpdma_rx_pg; -- 2.51.0 From 528e2e4d166e49dadcb780d5a37cda03bbe9e399 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Oct 2025 12:41:48 +0200 Subject: [PATCH 094/517] wifi: mt76: wed: use proper wed reference in mt76 wed driver callabacks MT7996 driver can use both wed and wed_hif2 devices to offload traffic from/to the wireless NIC. In the current codebase we assume to always use the primary wed device in wed callbacks resulting in the following crash if the hw runs wed_hif2 (e.g. 6GHz link). [ 297.455876] Unable to handle kernel read from unreadable memory at virtual address 000000000000080a [ 297.464928] Mem abort info: [ 297.467722] ESR = 0x0000000096000005 [ 297.471461] EC = 0x25: DABT (current EL), IL = 32 bits [ 297.476766] SET = 0, FnV = 0 [ 297.479809] EA = 0, S1PTW = 0 [ 297.482940] FSC = 0x05: level 1 translation fault [ 297.487809] Data abort info: [ 297.490679] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000 [ 297.496156] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 [ 297.501196] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 [ 297.506500] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000107480000 [ 297.512927] [000000000000080a] pgd=08000001097fb003, p4d=08000001097fb003, pud=08000001097fb003, pmd=0000000000000000 [ 297.523532] Internal error: Oops: 0000000096000005 [#1] SMP [ 297.715393] CPU: 2 UID: 0 PID: 45 Comm: kworker/u16:2 Tainted: G O 6.12.50 #0 [ 297.723908] Tainted: [O]=OOT_MODULE [ 297.727384] Hardware name: Banana Pi BPI-R4 (2x SFP+) (DT) [ 297.732857] Workqueue: nf_ft_offload_del nf_flow_rule_route_ipv6 [nf_flow_table] [ 297.740254] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 297.747205] pc : mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.752688] lr : mtk_wed_flow_remove+0x58/0x80 [ 297.757126] sp : ffffffc080fe3ae0 [ 297.760430] x29: ffffffc080fe3ae0 x28: ffffffc080fe3be0 x27: 00000000deadbef7 [ 297.767557] x26: ffffff80c5ebca00 x25: 0000000000000001 x24: ffffff80c85f4c00 [ 297.774683] x23: ffffff80c1875b78 x22: ffffffc080d42cd0 x21: ffffffc080660018 [ 297.781809] x20: ffffff80c6a076d0 x19: ffffff80c6a043c8 x18: 0000000000000000 [ 297.788935] x17: 0000000000000000 x16: 0000000000000001 x15: 0000000000000000 [ 297.796060] x14: 0000000000000019 x13: ffffff80c0ad8ec0 x12: 00000000fa83b2da [ 297.803185] x11: ffffff80c02700c0 x10: ffffff80c0ad8ec0 x9 : ffffff81fef96200 [ 297.810311] x8 : ffffff80c02700c0 x7 : ffffff80c02700d0 x6 : 0000000000000002 [ 297.817435] x5 : 0000000000000400 x4 : 0000000000000000 x3 : 0000000000000000 [ 297.824561] x2 : 0000000000000001 x1 : 0000000000000800 x0 : ffffff80c6a063c8 [ 297.831686] Call trace: [ 297.834123] mt76_wed_offload_disable+0x64/0xa0 [mt76] [ 297.839254] mtk_wed_flow_remove+0x58/0x80 [ 297.843342] mtk_flow_offload_cmd+0x434/0x574 [ 297.847689] mtk_wed_setup_tc_block_cb+0x30/0x40 [ 297.852295] nf_flow_offload_ipv6_hook+0x7f4/0x964 [nf_flow_table] [ 297.858466] nf_flow_rule_route_ipv6+0x438/0x4a4 [nf_flow_table] [ 297.864463] process_one_work+0x174/0x300 [ 297.868465] worker_thread+0x278/0x430 [ 297.872204] kthread+0xd8/0xdc [ 297.875251] ret_from_fork+0x10/0x20 [ 297.878820] Code: 928b5ae0 8b000273 91400a60 f943fa61 (79401421) [ 297.884901] ---[ end trace 0000000000000000 ]--- Fix the issue detecting the proper wed reference to use running wed callabacks. -- Partial backport for data structure change only (rest is in the mt76 package) Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") Tested-by: Daniel Pawlik Tested-by: Matteo Croce Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20251008-wed-fixes-v1-1-8f7678583385@kernel.org Signed-off-by: Felix Fietkau --- include/linux/soc/mediatek/mtk_wed.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h index 5ab3a93a7be9..5c3358e033df 100644 --- a/include/linux/soc/mediatek/mtk_wed.h +++ b/include/linux/soc/mediatek/mtk_wed.h @@ -154,6 +154,7 @@ struct mtk_wed_device { bool wcid_512; bool hw_rro; bool msi; + bool hif2; u16 token_start; unsigned int nbuf; -- 2.51.0 From 91f5d4afc87aa13b8a58ce06713b4166ec5aeae0 Mon Sep 17 00:00:00 2001 From: Rex Lu Date: Thu, 9 Oct 2025 08:29:34 +0200 Subject: [PATCH 095/517] net: mtk: wed: add dma mask limitation and GFP_DMA32 for device with more than 4GB DRAM Limit tx/rx buffer address to 32-bit address space for board with more than 4GB DRAM. Fixes: 804775dfc2885 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") Fixes: 6757d345dd7db ("net: ethernet: mtk_wed: introduce hw_rro support for MT7988") Tested-by: Daniel Pawlik Tested-by: Matteo Croce Signed-off-by: Rex Lu Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_wed.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index e7021d0622b0..1e369a059edd 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -677,7 +677,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) void *buf; int s; - page = __dev_alloc_page(GFP_KERNEL); + page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); if (!page) return -ENOMEM; @@ -800,7 +800,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev) struct page *page; int s; - page = __dev_alloc_page(GFP_KERNEL); + page = __dev_alloc_page(GFP_KERNEL | GFP_DMA32); if (!page) return -ENOMEM; @@ -2438,6 +2438,10 @@ mtk_wed_attach(struct mtk_wed_device *dev) dev->version = hw->version; dev->hw->pcie_base = mtk_wed_get_pcie_base(dev); + ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32)); + if (ret) + goto out; + if (hw->eth->dma_dev == hw->eth->dev && of_dma_is_coherent(hw->eth->dev->of_node)) mtk_eth_set_dma_device(hw->eth, hw->dev); -- 2.51.0 From 41f6a1b75d6742130804539509cff2ef9294196b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 13 Oct 2023 00:08:35 +0200 Subject: [PATCH 096/517] net: dsa: mv88e6xxx: Support LED control This adds control over the hardware LEDs in the Marvell MV88E6xxx DSA switch and enables it for MV88E6352. This fixes an imminent problem on the Inteno XG6846 which has a WAN LED that simply do not work with hardware defaults: driver amendment is necessary. The patch is modeled after Christian Marangis LED support code for the QCA8k DSA switch, I got help with the register definitions from Tim Harvey. After this patch it is possible to activate hardware link indication like this (or with a similar script): cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/ echo netdev > trigger echo 1 > link This makes the green link indicator come up on any link speed. It is also possible to be more elaborate, like this: cd /sys/class/leds/Marvell\ 88E6352:05:00:green:wan/ echo netdev > trigger echo 1 > link_1000 cd /sys/class/leds/Marvell\ 88E6352:05:01:amber:wan/ echo netdev > trigger echo 1 > link_100 Making the green LED come on for a gigabit link and the amber LED come on for a 100 mbit link. Each port has 2 LED slots (the hardware may use just one or none) and the hardware triggers are specified in four bits per LED, and some of the hardware triggers are only available on the SFP (fiber) uplink. The restrictions are described in the port.h header file where the registers are described. For example, selector 1 set for LED 1 on port 5 or 6 will indicate Fiber 1000 (gigabit) and activity with a blinking LED, but ONLY for an SFP connection. If port 5/6 is used with something not SFP, this selector is a noop: something else need to be selected. After the previous series rewriting the MV88E6xxx DT bindings to use YAML a "leds" subnode is already valid for each port, in my scratch device tree it looks like this: leds { #address-cells = <1>; #size-cells = <0>; led@0 { reg = <0>; color = ; function = LED_FUNCTION_LAN; default-state = "off"; linux,default-trigger = "netdev"; }; led@1 { reg = <1>; color = ; function = LED_FUNCTION_LAN; default-state = "off"; }; }; This DT config is not yet configuring everything: when the netdev default trigger is assigned the hw acceleration callbacks are not called, and there is no way to set the netdev sub-trigger type (such as link_1000) from the device tree, such as if you want a gigabit link indicator. This has to be done from userspace at this point. We add LED operations to all switches in the 6352 family: 6172, 6176, 6240 and 6352. Signed-off-by: Linus Walleij --- drivers/net/dsa/mv88e6xxx/Kconfig | 10 + drivers/net/dsa/mv88e6xxx/Makefile | 1 + drivers/net/dsa/mv88e6xxx/chip.c | 38 +- drivers/net/dsa/mv88e6xxx/chip.h | 11 + drivers/net/dsa/mv88e6xxx/leds.c | 839 +++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/port.c | 1 + drivers/net/dsa/mv88e6xxx/port.h | 133 +++++ 7 files changed, 1031 insertions(+), 2 deletions(-) create mode 100644 drivers/net/dsa/mv88e6xxx/leds.c diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig index e3181d5471df..64ae3882d17c 100644 --- a/drivers/net/dsa/mv88e6xxx/Kconfig +++ b/drivers/net/dsa/mv88e6xxx/Kconfig @@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP help Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch chips that support it. + +config NET_DSA_MV88E6XXX_LEDS + bool "LED support for Marvell 88E6xxx" + default y + depends on NET_DSA_MV88E6XXX + depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX + depends on LEDS_TRIGGERS + help + This enabled support for controlling the LEDs attached to the + Marvell 88E6xxx switch chips. diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index a9a9651187db..dd961081d631 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o mv88e6xxx-objs += global2_avb.o mv88e6xxx-objs += global2_scratch.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o mv88e6xxx-objs += pcs-6185.o mv88e6xxx-objs += pcs-6352.o mv88e6xxx-objs += pcs-639x.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 211c219dd52d..43e0482fe1fd 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -3412,14 +3413,43 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct device_node *phy_handle = NULL; + struct fwnode_handle *ports_fwnode; + struct fwnode_handle *port_fwnode; struct dsa_switch *ds = chip->ds; + struct mv88e6xxx_port *p; struct dsa_port *dp; int tx_amp; int err; u16 reg; + u32 val; + + p = &chip->ports[port]; + p->chip = chip; + p->port = port; + + /* Look up corresponding fwnode if any */ + ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports"); + if (!ports_fwnode) + ports_fwnode = device_get_named_child_node(chip->dev, "ports"); + if (ports_fwnode) { + fwnode_for_each_child_node(ports_fwnode, port_fwnode) { + if (fwnode_property_read_u32(port_fwnode, "reg", &val)) + continue; + if (val == port) { + p->fwnode = port_fwnode; + p->fiber = fwnode_property_present(port_fwnode, "sfp"); + break; + } + } + } else { + dev_dbg(chip->dev, "no ethernet ports node defined for the device\n"); + } - chip->ports[port].chip = chip; - chip->ports[port].port = port; + if (chip->info->ops->port_setup_leds) { + err = chip->info->ops->port_setup_leds(chip, port); + if (err && err != -EOPNOTSUPP) + return err; + } err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, SPEED_UNFORCED, DUPLEX_UNFORCED, @@ -4653,6 +4683,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -4755,6 +4786,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -5030,6 +5062,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -5460,6 +5493,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index a54682240839..71a8fd9ff374 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -276,6 +278,7 @@ struct mv88e6xxx_vlan { struct mv88e6xxx_port { struct mv88e6xxx_chip *chip; int port; + struct fwnode_handle *fwnode; struct mv88e6xxx_vlan bridge_pvid; u64 serdes_stats[2]; u64 atu_member_violation; @@ -290,6 +293,11 @@ struct mv88e6xxx_port { struct devlink_region *region; void *pcs_private; + /* LED related information */ + bool fiber; + struct led_classdev led0; + struct led_classdev led1; + /* MacAuth Bypass control flag */ bool mab; }; @@ -574,6 +582,9 @@ struct mv88e6xxx_ops { phy_interface_t mode); int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode); + /* LED control */ + int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port); + /* Some devices have a per port register indicating what is * the upstream port this port should forward to. */ diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c new file mode 100644 index 000000000000..1c88bfaea46b --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/leds.c @@ -0,0 +1,839 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include + +#include "chip.h" +#include "global2.h" +#include "port.h" + +/* Offset 0x16: LED control */ + +static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg) +{ + reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE; + + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg); +} + +static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port, + u16 ptr, u16 *val) +{ + int err; + + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr); + if (err) + return err; + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val); + *val &= 0x3ff; + + return err; +} + +static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led, + int brightness) +{ + u16 reg; + int err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + if (brightness) { + /* Selector 0x0f == Force LED ON */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF; + } else { + /* Selector 0x0e == Force LED OFF */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; + } + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev, + enum led_brightness brightness) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_brightness_set(p, 0, brightness); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev, + enum led_brightness brightness) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_brightness_set(p, 1, brightness); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +struct mv88e6xxx_led_hwconfig { + int led; + u8 portmask; + unsigned long rules; + bool fiber; + bool blink_activity; + u16 selector; +}; + +/* The following is a lookup table to check what rules we can support on a + * certain LED given restrictions such as that some rules only work with fiber + * (SFP) connections and some blink on activity by default. + */ +#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3)) +#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5)) +#define MV88E6XXX_PORT_4 BIT(4) +#define MV88E6XXX_PORT_5 BIT(5) + +/* Entries are listed in selector order. + * + * These configurations vary across different switch families, list + * different tables per-family here. + */ +static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = { + { + .led = 0, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB, + }, +}; + +/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector + * @p: port state container + * @led: LED number, 0 or 1 + * @blink_activity: blink the LED (usually blink on indicated activity) + * @fiber: the link is connected to fiber such as SFP + * @rules: LED status flags from the LED classdev core + * @selector: fill in the selector in this parameter with an OR operation + */ +static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity, + bool fiber, unsigned long rules, u16 *selector) +{ + const struct mv88e6xxx_led_hwconfig *conf; + int i; + + /* No rules means we turn the LED off */ + if (!rules) { + if (led == 1) + *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; + else + *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; + return 0; + } + + /* TODO: these rules are for MV88E6352, when adding other families, + * think about making sure you select the table that match the + * specific switch family. + */ + for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { + conf = &mv88e6352_led_hwconfigs[i]; + + if (conf->led != led) + continue; + + if (!(conf->portmask & BIT(p->port))) + continue; + + if (conf->blink_activity != blink_activity) + continue; + + if (conf->fiber != fiber) + continue; + + if (conf->rules == rules) { + dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n", + p->port, led, conf->selector, rules); + *selector |= conf->selector; + return 0; + } + } + + return -EOPNOTSUPP; +} + +/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value + * @p: port state container + * @selector: the selector value from the LED actity register + * @led: LED number, 0 or 1 + * @rules: Linux netdev activity rules found from selector + */ +static int +mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules) +{ + const struct mv88e6xxx_led_hwconfig *conf; + int i; + + /* Find the selector in the table, we just look for the right selector + * and ignore if the activity has special properties such as blinking + * or is fiber-only. + */ + for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { + conf = &mv88e6352_led_hwconfigs[i]; + + if (conf->led != led) + continue; + + if (!(conf->portmask & BIT(p->port))) + continue; + + if (conf->selector == selector) { + dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n", + p->port, led, selector, conf->rules); + *rules = conf->rules; + return 0; + } + } + + return -EINVAL; +} + +/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector + * @p: port state container + * @led: LED number, 0 or 1 + * @fiber: the link is connected to fiber such as SFP + * @rules: LED status flags from the LED classdev core + * @selector: fill in the selector in this parameter with an OR operation + */ +static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led, + bool fiber, unsigned long rules, u16 *selector) +{ + int err; + + /* What happens here is that we first try to locate a trigger with solid + * indicator (such as LED is on for a 1000 link) else we try a second + * sweep to find something suitable with a trigger that will blink on + * activity. + */ + err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector); + if (err) + return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector); + + return 0; +} + +/* Sets up the hardware blinking period */ +static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led, + unsigned long delay_on, unsigned long delay_off) +{ + unsigned long period; + u16 reg; + + period = delay_on + delay_off; + + reg = 0; + + switch (period) { + case 21: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS; + break; + case 42: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS; + break; + case 84: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS; + break; + case 168: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS; + break; + case 336: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS; + break; + case 672: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS; + break; + default: + /* Fall back to software blinking */ + return -EINVAL; + } + + /* This is essentially PWM duty cycle: how long time of the period + * will the LED be on. Zero isn't great in most cases. + */ + switch (delay_on) { + case 0: + /* This is usually pretty useless and will make the LED look OFF */ + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE; + break; + case 21: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; + break; + case 42: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS; + break; + case 84: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS; + break; + case 168: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS; + break; + default: + /* Just use something non-zero */ + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; + break; + } + + /* Set up blink rate */ + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led, + unsigned long *delay_on, unsigned long *delay_off) +{ + u16 reg; + int err; + + /* Choose a sensible default 336 ms (~3 Hz) */ + if ((*delay_on == 0) && (*delay_off == 0)) { + *delay_on = 168; + *delay_off = 168; + } + + /* No off delay is just on */ + if (*delay_off == 0) + return mv88e6xxx_led_brightness_set(p, led, 1); + + err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off); + if (err) + return err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + /* This will select the forced blinking status */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD; + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + u16 selector = 0; + + return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector); +} + +static int +mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + u16 selector = 0; + + return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector); +} + +static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p, + int led, unsigned long rules) +{ + u16 reg; + int err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®); + if (err) + return err; + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + if (led == 0) + dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n", + p->port, + (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK)); + else + dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n", + p->port, + (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4); + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int +mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules) +{ + u16 val; + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val); + mv88e6xxx_reg_unlock(p->chip); + if (err) + return err; + + /* Mask out the selector bits for this port */ + if (led == 1) { + val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + /* It's forced blinking/OFF/ON */ + if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD || + val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE || + val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) { + *rules = 0; + return 0; + } + } else { + val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + /* It's forced blinking/OFF/ON */ + if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD || + val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE || + val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) { + *rules = 0; + return 0; + } + } + + err = mv88e6xxx_led_match_rule(p, val, led, rules); + if (!err) + return 0; + + dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val); + *rules = 0; + return 0; +} + +static int +mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_hw_control_set(p, 0, rules); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_hw_control_set(p, 1, rules); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + + return mv88e6xxx_led_hw_control_get(p, 0, rules); +} + +static int +mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + + return mv88e6xxx_led_hw_control_get(p, 1, rules); +} + +static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p) +{ + struct dsa_port *dp; + + dp = dsa_to_port(p->chip->ds, p->port); + if (!dp) + return NULL; + if (dp->user) + return &dp->user->dev; + return NULL; +} + +static struct device * +mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + + return mv88e6xxx_led_hw_control_get_device(p); +} + +static struct device * +mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + + return mv88e6xxx_led_hw_control_get_device(p); +} + +int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port) +{ + struct fwnode_handle *led = NULL, *leds = NULL; + struct led_init_data init_data = { }; + enum led_default_state state; + struct mv88e6xxx_port *p; + struct led_classdev *l; + struct device *dev; + u32 led_num; + int ret; + + /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */ + if (port > 5) + return -EOPNOTSUPP; + + p = &chip->ports[port]; + if (!p->fwnode) + return 0; + + dev = chip->dev; + + leds = fwnode_get_named_child_node(p->fwnode, "leds"); + if (!leds) { + dev_dbg(dev, "No Leds node specified in device tree for port %d!\n", + port); + return 0; + } + + fwnode_for_each_child_node(leds, led) { + /* Reg represent the led number of the port, max 2 + * LEDs can be connected to each port, in some designs + * only one LED is connected. + */ + if (fwnode_property_read_u32(led, "reg", &led_num)) + continue; + if (led_num > 1) { + dev_err(dev, "invalid LED specified port %d\n", port); + return -EINVAL; + } + + if (led_num == 0) + l = &p->led0; + else + l = &p->led1; + + state = led_init_default_state_get(led); + switch (state) { + case LEDS_DEFSTATE_ON: + l->brightness = 1; + mv88e6xxx_led_brightness_set(p, led_num, 1); + break; + case LEDS_DEFSTATE_KEEP: + break; + default: + l->brightness = 0; + mv88e6xxx_led_brightness_set(p, led_num, 0); + } + + l->max_brightness = 1; + if (led_num == 0) { + l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking; + l->blink_set = mv88e6xxx_led0_blink_set; + l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported; + l->hw_control_set = mv88e6xxx_led0_hw_control_set; + l->hw_control_get = mv88e6xxx_led0_hw_control_get; + l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device; + } else { + l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking; + l->blink_set = mv88e6xxx_led1_blink_set; + l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported; + l->hw_control_set = mv88e6xxx_led1_hw_control_set; + l->hw_control_get = mv88e6xxx_led1_hw_control_get; + l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device; + } + l->hw_control_trigger = "netdev"; + + init_data.default_label = ":port"; + init_data.fwnode = led; + init_data.devname_mandatory = true; + init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name, + port, led_num); + if (!init_data.devicename) + return -ENOMEM; + + ret = devm_led_classdev_register_ext(dev, l, &init_data); + kfree(init_data.devicename); + + if (ret) { + dev_err(dev, "Failed to init LED %d for port %d", led_num, port); + return ret; + } + } + + return 0; +} diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 04053fdc6489..dc777ddce1f3 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "chip.h" #include "global2.h" diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index ddadeb9bfdae..c1d2f99efb1c 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -309,6 +309,130 @@ /* Offset 0x13: OutFiltered Counter */ #define MV88E6XXX_PORT_OUT_FILTERED 0x13 +/* Offset 0x16: LED Control */ +#define MV88E6XXX_PORT_LED_CONTROL 0x16 +#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15) +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12) +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */ +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */ +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */ +#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0) +/* Selection masks valid for either port 1,2,3,4 or 5 */ +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4) +/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0 + * Bits Function + * 0..3 LED 0 control selector on ports 1-5 + * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6 + * + * Sel Port LED Function for the 6352 family: + * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 1-4 1 Port 2's Special LED + * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity) + * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity) + * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity) + * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity) + * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) + * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity) + * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) + * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity) + * 1-4 1 1000 Link (off=no link, on=1000 link) + * 5-6 0 Port 0's Special LED + * 5-6 1 Fiber Link (off=no link, on=link) + * 4 1-4 0 Port 0's Special LED + * 1-4 1 Port 1's Special LED + * 5-6 0 Port 1's Special LED + * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity) + * 5 1-4 0 Reserved + * 1-4 1 Reserved + * 5-6 0 Port 2's Special LED + * 5-6 1 Port 6 Link (off=no link, on=link) + * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision) + * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) + * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) + * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) + * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) + * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link) + * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 8 1-4 0 Link (off=no link, on=link) + * 1-4 1 Activity (off=no link, blink on=activity) + * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity) + * 5-6 1 Port 0's Special LED + * 9 1-4 0 10 Link (off=no link, on=10 link) + * 1-4 1 100 Link (off=no link, on=100 link) + * 5-6 0 Reserved + * 5-6 1 Port 1's Special LED + * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity) + * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity) + * 5-6 0 Reserved + * 5-6 1 Port 2's Special LED + * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link) + * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity) + * 5-6 0 Reserved + * 5-6 1 Reserved + * c * * PTP Act (blink on=PTP activity) + * d * * Force Blink + * e * * Force Off + * f * * Force On + */ +/* Select LED0 output */ +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4) +/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */ +/* Pulse Stretch Selection for all LED's on this port */ +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4) +/* Blink Rate Selection for all LEDs on this port */ +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5 + /* Control for Special LED (Index 0x7 of LED Control on Port0) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */ +/* Control for Special LED (Index 0x7 of LED Control on Port 1) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */ +/* Control for Special LED (Index 0x7 of LED Control on Port 2) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */ + /* Offset 0x18: IEEE Priority Mapping Table */ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 @@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); +#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS +int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port); +#else +static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, + int port) +{ + return 0; +} +#endif int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port, bool drop_untagged); int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map); -- 2.51.0 From 75caf17387cec21649e7981585617b6f1bd850ea Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Oct 2024 07:48:05 +0200 Subject: [PATCH 097/517] r8169: remove original workaround for RTL8125 broken rx issue Now that we have b9c7ac4fe22c ("r8169: disable ALDPS per default for RTL8125"), the first attempt to fix the issue shouldn't be needed any longer. So let's effectively revert 621735f59064 ("r8169: fix rare issue with broken rx after link-down on RTL8125") and see whether anybody complains. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/382d8c88-cbce-400f-ad62-fda0181c7e38@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 80b5262d0d57..4ef3a23f9f95 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4813,11 +4813,7 @@ static void r8169_phylink_handler(struct net_device *ndev) if (netif_carrier_ok(ndev)) { rtl_link_chg_patch(tp); pm_request_resume(d); - netif_wake_queue(tp->dev); } else { - /* In few cases rx is broken after link-down otherwise */ - if (rtl_is_8125(tp)) - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); pm_runtime_idle(d); } -- 2.51.0 From 876e8c0219f3c916926131747aded27d275a1cfd Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 10 Oct 2024 12:58:02 +0200 Subject: [PATCH 098/517] r8169: enable SG/TSO on selected chip versions per default Due to problem reports in the past SG and TSO/TSO6 are disabled per default. It's not fully clear which chip versions are affected, so we may impact also users of unaffected chip versions, unless they know how to use ethtool for enabling SG/TSO/TSO6. Vendor drivers r8168/r8125 enable SG/TSO/TSO6 for selected chip versions per default, I'd interpret this as confirmation that these chip versions are unaffected. So let's do the same here. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 4ef3a23f9f95..9a01b5a9facd 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5527,11 +5527,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features |= dev->hw_features; - /* There has been a number of reports that using SG/TSO results in - * tx timeouts. However for a lot of people SG/TSO works fine. - * Therefore disable both features by default, but allow users to - * enable them. Use at own risk! - */ if (rtl_chip_supports_csum_v2(tp)) { dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); @@ -5542,6 +5537,17 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); } + /* There has been a number of reports that using SG/TSO results in + * tx timeouts. However for a lot of people SG/TSO works fine. + * It's not fully clear which chip versions are affected. Vendor + * drivers enable SG/TSO for certain chip versions per default, + * let's mimic this here. On other chip versions users can + * use ethtool to enable SG/TSO, use at own risk! + */ + if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && + tp->mac_version != RTL_GIGA_MAC_VER_61) + dev->features |= dev->hw_features; + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; -- 2.51.0 From cc333d732be713e617a9e2673d01e660ca905e2e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 13 Oct 2024 11:17:39 +0200 Subject: [PATCH 099/517] r8169: implement additional ethtool stats ops This adds support for ethtool standard statistics, and makes use of the extended hardware statistics being available from RTl8125. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/58e0da73-a7dd-4be3-82ae-d5b3f9069bde@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 82 +++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 9a01b5a9facd..27633b4802f8 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2160,6 +2160,19 @@ static void rtl8169_get_ringparam(struct net_device *dev, data->tx_pending = NUM_TX_DESC; } +static void rtl8169_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on); + pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on); +} + static void rtl8169_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *data) { @@ -2186,6 +2199,69 @@ static int rtl8169_set_pauseparam(struct net_device *dev, return 0; } +static void rtl8169_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8169_update_counters(tp); + + mac_stats->FramesTransmittedOK = + le64_to_cpu(tp->counters->tx_packets); + mac_stats->SingleCollisionFrames = + le32_to_cpu(tp->counters->tx_one_collision); + mac_stats->MultipleCollisionFrames = + le32_to_cpu(tp->counters->tx_multi_collision); + mac_stats->FramesReceivedOK = + le64_to_cpu(tp->counters->rx_packets); + mac_stats->AlignmentErrors = + le16_to_cpu(tp->counters->align_errors); + mac_stats->FramesLostDueToIntMACXmitError = + le64_to_cpu(tp->counters->tx_errors); + mac_stats->BroadcastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_broadcast); + mac_stats->MulticastFramesReceivedOK = + le32_to_cpu(tp->counters->rx_multicast); + + if (!rtl_is_8125(tp)) + return; + + mac_stats->AlignmentErrors = + le32_to_cpu(tp->counters->align_errors32); + mac_stats->OctetsTransmittedOK = + le64_to_cpu(tp->counters->tx_octets); + mac_stats->LateCollisions = + le32_to_cpu(tp->counters->tx_late_collision); + mac_stats->FramesAbortedDueToXSColls = + le32_to_cpu(tp->counters->tx_aborted32); + mac_stats->OctetsReceivedOK = + le64_to_cpu(tp->counters->rx_octets); + mac_stats->FramesLostDueToIntMACRcvError = + le32_to_cpu(tp->counters->rx_mac_error); + mac_stats->MulticastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_multicast64); + mac_stats->BroadcastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_broadcast64); + mac_stats->MulticastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_multicast64); + mac_stats->FrameTooLongErrors = + le32_to_cpu(tp->counters->rx_frame_too_long); +} + +static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + + ctrl_stats->UnsupportedOpcodesReceived = + le32_to_cpu(tp->counters->rx_unknown_opcode); +} + static const struct ethtool_ops rtl8169_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -2207,8 +2283,11 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_ringparam = rtl8169_get_ringparam, + .get_pause_stats = rtl8169_get_pause_stats, .get_pauseparam = rtl8169_get_pauseparam, .set_pauseparam = rtl8169_set_pauseparam, + .get_eth_mac_stats = rtl8169_get_eth_mac_stats, + .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, }; static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) @@ -3929,6 +4008,9 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) break; } + /* enable extended tally counter */ + r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0)); + rtl_hw_config(tp); } -- 2.51.0 From 346f3face3f8c7e50c37eb4c9afa0fedc0231401 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Oct 2024 22:05:57 +0200 Subject: [PATCH 100/517] r8169: don't take RTNL lock in rtl_task() There's not really a benefit here in taking the RTNL lock. The task handler does exception handling only, so we're in trouble anyway when we come here, and there's no need to protect against e.g. a parallel ethtool call. A benefit of removing the RTNL lock here is that we now can synchronously cancel the workqueue from a context holding the RTNL mutex. Signed-off-by: Heiner Kallweit Signed-off-by: Andrew Lunn --- drivers/net/ethernet/realtek/r8169_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 27633b4802f8..793c3740b623 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4836,10 +4836,8 @@ static void rtl_task(struct work_struct *work) container_of(work, struct rtl8169_private, wk.work); int ret; - rtnl_lock(); - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - goto out_unlock; + return; if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { /* if chip isn't accessible, reset bus to revive it */ @@ -4848,7 +4846,7 @@ static void rtl_task(struct work_struct *work) if (ret < 0) { netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n"); netif_device_detach(tp->dev); - goto out_unlock; + return; } } @@ -4867,8 +4865,6 @@ static void rtl_task(struct work_struct *work) } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { rtl_reset_work(tp); } -out_unlock: - rtnl_unlock(); } static int rtl8169_poll(struct napi_struct *napi, int budget) -- 2.51.0 From 946357f990b9bdbdfcea45e565acafab66b877f8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Oct 2024 22:06:53 +0200 Subject: [PATCH 101/517] r8169: replace custom flag with disable_work() et al So far we use a custom flag to define when a task can be scheduled and when not. Let's use the standard mechanism with disable_work() et al instead. Note that in rtl8169_close() we can remove the call to cancel_work() because we now call disable_work_sync() in rtl8169_down() already. Signed-off-by: Heiner Kallweit Signed-off-by: Andrew Lunn --- drivers/net/ethernet/realtek/r8169_main.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 793c3740b623..a4d659612c0b 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -619,7 +619,6 @@ struct rtl8169_tc_offsets { }; enum rtl_flag { - RTL_FLAG_TASK_ENABLED = 0, RTL_FLAG_TASK_RESET_PENDING, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, RTL_FLAG_TASK_TX_TIMEOUT, @@ -2505,11 +2504,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) { - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - return; - set_bit(flag, tp->wk.flags); - schedule_work(&tp->wk.work); + if (!schedule_work(&tp->wk.work)) + clear_bit(flag, tp->wk.flags); } static void rtl8169_init_phy(struct rtl8169_private *tp) @@ -4836,9 +4833,6 @@ static void rtl_task(struct work_struct *work) container_of(work, struct rtl8169_private, wk.work); int ret; - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - return; - if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { /* if chip isn't accessible, reset bus to revive it */ if (RTL_R32(tp, TxConfig) == ~0) { @@ -4922,6 +4916,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp) static void rtl8169_down(struct rtl8169_private *tp) { + disable_work_sync(&tp->wk.work); /* Clear all task flags */ bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); @@ -4950,7 +4945,7 @@ static void rtl8169_up(struct rtl8169_private *tp) phy_resume(tp->phydev); rtl8169_init_phy(tp); napi_enable(&tp->napi); - set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + enable_work(&tp->wk.work); rtl_reset_work(tp); phy_start(tp->phydev); @@ -4967,8 +4962,6 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(tp); rtl8169_rx_clear(tp); - cancel_work(&tp->wk.work); - free_irq(tp->irq, tp); phy_disconnect(tp->phydev); @@ -5202,7 +5195,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); - cancel_work_sync(&tp->wk.work); + disable_work_sync(&tp->wk.work); if (IS_ENABLED(CONFIG_R8169_LEDS)) r8169_remove_leds(tp->leds); @@ -5580,6 +5573,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->irq = pci_irq_vector(pdev, 0); INIT_WORK(&tp->wk.work, rtl_task); + disable_work(&tp->wk.work); rtl_init_mac_address(tp); -- 2.51.0 From a96d084288956bdc353e2d978982680e65c30f55 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Oct 2024 22:29:39 +0200 Subject: [PATCH 102/517] r8169: avoid duplicated messages if loading firmware fails and switch to warn level In case of a problem with firmware loading we inform at the driver level, in addition the firmware load code itself issues warnings. Therefore switch to firmware_request_nowarn() to avoid duplicated error messages. In addition switch to warn level because the firmware is optional and typically just fixes compatibility issues. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Message-ID: Signed-off-by: Andrew Lunn --- drivers/net/ethernet/realtek/r8169_firmware.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index ed6e721b1555..bf055078a855 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) { int rc; - rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); if (rc < 0) goto out; @@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) return 0; out: - dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", - rtl_fw->fw_name, rc); + dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n", + rtl_fw->fw_name, rc); return rc; } -- 2.51.0 From 56661855d12fe1c72a1028936f9d3e5fb9c82478 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Oct 2024 22:31:10 +0200 Subject: [PATCH 103/517] r8169: remove rtl_dash_loop_wait_high/low Remove rtl_dash_loop_wait_high/low to simplify the code. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Message-ID: Signed-off-by: Andrew Lunn --- drivers/net/ethernet/realtek/r8169_main.c | 35 ++++++----------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index a4d659612c0b..d9682329f6e7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1348,40 +1348,19 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01); } -static void rtl_dash_loop_wait(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long usecs, int n, bool high) -{ - if (!tp->dash_enabled) - return; - rtl_loop_wait(tp, c, usecs, n, high); -} - -static void rtl_dash_loop_wait_high(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long d, int n) -{ - rtl_dash_loop_wait(tp, c, d, n, true); -} - -static void rtl_dash_loop_wait_low(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long d, int n) -{ - rtl_dash_loop_wait(tp, c, d, n, false); -} - static void rtl8168dp_driver_start(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); - rtl_dash_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_start(struct rtl8169_private *tp) { r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); } static void rtl8168_driver_start(struct rtl8169_private *tp) @@ -1395,7 +1374,8 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168dp_driver_stop(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); - rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_stop(struct rtl8169_private *tp) @@ -1403,7 +1383,8 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) rtl8168ep_stop_cmac(tp); r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); } static void rtl8168_driver_stop(struct rtl8169_private *tp) -- 2.51.0 From 7f019b21702006b9e9dd50ad8c9e2107face00db Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 17 Oct 2024 22:27:44 +0200 Subject: [PATCH 104/517] r8169: enable EEE at 2.5G per default on RTL8125B Register a6d/12 is shadowing register MDIO_AN_EEE_ADV2. So this line disables advertisement of EEE at 2.5G. Latest vendor driver r8125 doesn't do this (any longer?), so this mode seems to be safe. EEE saves quite some energy, therefore enable this mode per default. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Message-ID: <95dd5a0c-09ea-4847-94d9-b7aa3063e8ff@gmail.com> Signed-off-by: Andrew Lunn --- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index d09b2a41cd06..8739f4b42aaf 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -99,7 +99,6 @@ static void rtl8125a_config_eee_phy(struct phy_device *phydev) static void rtl8125b_config_eee_phy(struct phy_device *phydev) { - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); -- 2.51.0 From 28b4af371b12a73bf9a0fef04753076b4d5446e1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 24 Oct 2024 22:48:59 +0200 Subject: [PATCH 105/517] r8169: fix inconsistent indenting in rtl8169_get_eth_mac_stats This fixes an inconsistent indenting introduced with e3fc5139bd8f ("r8169: implement additional ethtool stats ops"). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202410220413.1gAxIJ4t-lkp@intel.com/ Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/20fd6f39-3c1b-4af0-9adc-7d1f49728fad@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index d9682329f6e7..0091f1460036 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2224,7 +2224,7 @@ static void rtl8169_get_eth_mac_stats(struct net_device *dev, le64_to_cpu(tp->counters->tx_broadcast64); mac_stats->MulticastFramesReceivedOK = le64_to_cpu(tp->counters->rx_multicast64); - mac_stats->FrameTooLongErrors = + mac_stats->FrameTooLongErrors = le32_to_cpu(tp->counters->rx_frame_too_long); } -- 2.51.0 From c325ddc8e8248f828deef9638176039f3f83eae5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 31 Oct 2024 22:42:52 +0100 Subject: [PATCH 106/517] r8169: align RTL8125 EEE config with vendor driver Align the EEE config for RTL8125A/RTL8125B with vendor driver r8125. This should help to avoid compatibility issues. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/044c925e-8669-4b98-87df-95b4056f4f5f@gmail.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/realtek/r8169_phy_config.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 8739f4b42aaf..a0ecfa9c60ae 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -89,19 +89,25 @@ static void rtl8168h_config_eee_phy(struct phy_device *phydev) phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080); } -static void rtl8125a_config_eee_phy(struct phy_device *phydev) +static void rtl8125_common_config_eee_phy(struct phy_device *phydev) { - rtl8168h_config_eee_phy(phydev); + phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); +} +static void rtl8125a_config_eee_phy(struct phy_device *phydev) +{ + rtl8168g_config_eee_phy(phydev); + /* disable EEE at 2.5Gbps */ phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); - phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + rtl8125_common_config_eee_phy(phydev); } static void rtl8125b_config_eee_phy(struct phy_device *phydev) { - phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); - phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); - phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); + rtl8168g_config_eee_phy(phydev); + rtl8125_common_config_eee_phy(phydev); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp, -- 2.51.0 From 0ec8e3bb0f649ceb7c034d76957b3e74999f95dd Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 31 Oct 2024 22:43:45 +0100 Subject: [PATCH 107/517] r8169: align RTL8125/RTL8126 PHY config with vendor driver This aligns some parameters with vendor driver r8125/r8126 to avoid compatibility issues. Note that for RTL8125B there's no functional change, just the open-coded version of the function is replaced. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/a8a9d896-fbe6-41f2-bf87-666567d3cdb3@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_phy_config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index a0ecfa9c60ae..54b254b9bf6c 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1073,8 +1073,8 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); - phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800); phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); @@ -1113,6 +1113,7 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); rtl8125_legacy_force_mode(phydev); rtl8168g_disable_aldps(phydev); rtl8125b_config_eee_phy(phydev); @@ -1122,6 +1123,9 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); } void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, -- 2.51.0 From 390ace441dd012d005dddb5aed3bfb7e022f4c2a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 31 Oct 2024 22:44:36 +0100 Subject: [PATCH 108/517] r8169: align RTL8126 EEE config with vendor driver Align the EEE config for RTL8126A with vendor driver r8126 to avoid compatibility issues. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/71e4859e-4cd0-4b6b-b7fa-621d7721992f@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 54b254b9bf6c..1d5b33f6c4b5 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1126,6 +1126,7 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, rtl8168g_enable_gphy_10m(phydev); rtl8125_legacy_force_mode(phydev); rtl8168g_disable_aldps(phydev); + rtl8125_common_config_eee_phy(phydev); } void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, -- 2.51.0 From b40777ebd76e985658185127b635c20e00c38199 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 2 Nov 2024 14:49:01 +0100 Subject: [PATCH 109/517] r8169: improve initialization of RSS registers on RTL8125/RTL8126 Replace the register addresses with the names used in r8125/r8126 vendor driver, and consider that RSS_CTRL_8125 is a 32 bit register. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/3bf2f340-b369-4174-97bf-fd38d4217492@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 0091f1460036..ab8300984a2b 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -346,6 +346,8 @@ enum rtl8125_registers { TxPoll_8125 = 0x90, LEDSEL3 = 0x96, MAC0_BKP = 0x19e0, + RSS_CTRL_8125 = 0x4500, + Q_NUM_CTRL_8125 = 0x4800, EEE_TXIDLE_TIMER_8125 = 0x6048, }; @@ -3791,8 +3793,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) rtl_pcie_state_l2l3_disable(tp); RTL_W16(tp, 0x382, 0x221b); - RTL_W8(tp, 0x4500, 0); - RTL_W16(tp, 0x4800, 0); + RTL_W32(tp, RSS_CTRL_8125, 0); + RTL_W16(tp, Q_NUM_CTRL_8125, 0); /* disable UPS */ r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); -- 2.51.0 From aa67f9dc507adfc19a82b9392692926658de1590 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 4 Nov 2024 23:16:20 +0100 Subject: [PATCH 110/517] r8169: remove leftover locks after reverted change After e31a9fedc7d8 ("Revert "r8169: disable ASPM during NAPI poll"") these locks aren't needed any longer. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/680f2606-ac7d-4ced-8694-e5033855da9b@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 29 ++--------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index ab8300984a2b..5d708053c37c 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -661,13 +661,9 @@ struct rtl8169_private { struct work_struct work; } wk; - raw_spinlock_t config25_lock; raw_spinlock_t mac_ocp_lock; struct mutex led_lock; /* serialize LED ctrl RMW access */ - raw_spinlock_t cfg9346_usage_lock; - int cfg9346_usage_count; - unsigned supports_gmii:1; unsigned aspm_manageable:1; unsigned dash_enabled:1; @@ -721,22 +717,12 @@ static inline struct device *tp_to_dev(struct rtl8169_private *tp) static void rtl_lock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!--tp->cfg9346_usage_count) - RTL_W8(tp, Cfg9346, Cfg9346_Lock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Lock); } static void rtl_unlock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!tp->cfg9346_usage_count++) - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } static void rtl_pci_commit(struct rtl8169_private *tp) @@ -747,24 +733,18 @@ static void rtl_pci_commit(struct rtl8169_private *tp) static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config2); RTL_W8(tp, Config2, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config5); RTL_W8(tp, Config5, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static bool rtl_is_8125(struct rtl8169_private *tp) @@ -1570,7 +1550,6 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { WAKE_MAGIC, Config3, MagicPacket } }; unsigned int i, tmp = ARRAY_SIZE(cfg); - unsigned long flags; u8 options; rtl_unlock_config_regs(tp); @@ -1589,14 +1568,12 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); } - raw_spin_lock_irqsave(&tp->config25_lock, flags); for (i = 0; i < tmp; i++) { options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; if (wolopts & cfg[i].opt) options |= cfg[i].mask; RTL_W8(tp, cfg[i].reg, options); } - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: @@ -5480,8 +5457,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; tp->ocp_base = OCP_STD_PHY_BASE; - raw_spin_lock_init(&tp->cfg9346_usage_lock); - raw_spin_lock_init(&tp->config25_lock); raw_spin_lock_init(&tp->mac_ocp_lock); mutex_init(&tp->led_lock); -- 2.51.0 From 70713cb39f81777f2e78d556869f76dbc9ec6879 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 6 Nov 2024 17:55:45 +0100 Subject: [PATCH 111/517] r8169: improve __rtl8169_set_wol Add helper r8169_mod_reg8_cond() what allows to significantly simplify __rtl8169_set_wol(). Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/697b197a-8eac-40c6-8847-27093cacec36@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 55 ++++++++++------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 5d708053c37c..bb5784654cec 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -747,6 +747,20 @@ static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) RTL_W8(tp, Config5, (val & ~clear) | set); } +static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg, + u8 bits, bool cond) +{ + u8 val, old_val; + + old_val = RTL_R8(tp, reg); + if (cond) + val = old_val | bits; + else + val = old_val & ~bits; + if (val != old_val) + RTL_W8(tp, reg, val); +} + static bool rtl_is_8125(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_61; @@ -1537,58 +1551,37 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { - static const struct { - u32 opt; - u16 reg; - u8 mask; - } cfg[] = { - { WAKE_PHY, Config3, LinkUp }, - { WAKE_UCAST, Config5, UWF }, - { WAKE_BCAST, Config5, BWF }, - { WAKE_MCAST, Config5, MWF }, - { WAKE_ANY, Config5, LanWake }, - { WAKE_MAGIC, Config3, MagicPacket } - }; - unsigned int i, tmp = ARRAY_SIZE(cfg); - u8 options; - rtl_unlock_config_regs(tp); if (rtl_is_8168evl_up(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); else rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); } else if (rtl_is_8125(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); else r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); + } else { + r8169_mod_reg8_cond(tp, Config3, MagicPacket, + wolopts & WAKE_MAGIC); } - for (i = 0; i < tmp; i++) { - options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; - if (wolopts & cfg[i].opt) - options |= cfg[i].mask; - RTL_W8(tp, cfg[i].reg, options); - } + r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); + r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); + r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); + r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); + r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: - options = RTL_R8(tp, Config1) & ~PMEnable; - if (wolopts) - options |= PMEnable; - RTL_W8(tp, Config1, options); + r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts); break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: - if (wolopts) - rtl_mod_config2(tp, 0, PME_SIGNAL); - else - rtl_mod_config2(tp, PME_SIGNAL, 0); + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); break; default: break; -- 2.51.0 From d3852405b70dcc37cc63b0f66bf77a7fbf825e8f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 6 Nov 2024 17:56:28 +0100 Subject: [PATCH 112/517] r8169: improve rtl_set_d3_pll_down Make use of new helper r8169_mod_reg8_cond() and move from a switch() to an if() clause. Benefit is that we don't have to touch this piece of code each time support for a new chip version is added. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/e1ccdb85-a4ed-4800-89c2-89770ff06452@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index bb5784654cec..e963e4f9fff7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1430,19 +1430,11 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) { - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: - case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: - case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: - if (enable) - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); - else - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN); - break; - default: - break; - } + if (tp->mac_version >= RTL_GIGA_MAC_VER_25 && + tp->mac_version != RTL_GIGA_MAC_VER_28 && + tp->mac_version != RTL_GIGA_MAC_VER_31 && + tp->mac_version != RTL_GIGA_MAC_VER_38) + r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable); } static void rtl_reset_packet_filter(struct rtl8169_private *tp) -- 2.51.0 From 45dd32ce075f308916c99e45bb6b5e140e299dbd Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 6 Nov 2024 17:57:08 +0100 Subject: [PATCH 113/517] r8169: align WAKE_PHY handling with r8125/r8126 vendor drivers Vendor drivers r8125/r8126 apply this additional magic setting when enabling WAKE_PHY, so do the same here. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/51130715-45be-4db5-abb7-05d87e1f5df9@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index e963e4f9fff7..bd42f548fbda 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1561,6 +1561,9 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) } r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); + if (rtl_is_8125(tp)) + r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f, + wolopts & WAKE_PHY ? 0x13 : 0); r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); -- 2.51.0 From 5d248ce8f3584802bfc97c437bff82778b2517a3 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2024 23:12:12 +0100 Subject: [PATCH 114/517] r8169: use helper r8169_mod_reg8_cond to simplify rtl_jumbo_config Use recently added helper r8169_mod_reg8_cond() to simplify jumbo mode configuration. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/3df1d484-a02e-46e7-8f75-db5b428e422e@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 77 ++++------------------- 1 file changed, 11 insertions(+), 66 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index bd42f548fbda..aafe113d3bed 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2542,86 +2542,31 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; } -static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); -} - -static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); -} - -static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); -} - -static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); -} - -static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x24); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); -} - -static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x3f); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); -} - -static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); -} - -static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); -} - static void rtl_jumbo_config(struct rtl8169_private *tp) { bool jumbo = tp->dev->mtu > ETH_DATA_LEN; int readrq = 4096; + if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 && + tp->mac_version <= RTL_GIGA_MAC_VER_26) + readrq = 512; + rtl_unlock_config_regs(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_17: - if (jumbo) { - readrq = 512; - r8168b_1_hw_jumbo_enable(tp); - } else { - r8168b_1_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: - if (jumbo) { - readrq = 512; - r8168c_hw_jumbo_enable(tp); - } else { - r8168c_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo); break; case RTL_GIGA_MAC_VER_28: - if (jumbo) - r8168dp_hw_jumbo_enable(tp); - else - r8168dp_hw_jumbo_disable(tp); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); break; case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: - if (jumbo) - r8168e_hw_jumbo_enable(tp); - else - r8168e_hw_jumbo_disable(tp); + RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; default: break; -- 2.51.0 From 5c600144ed1b77cb7771b5d1e43098850d6d01fe Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 8 Nov 2024 08:08:24 +0100 Subject: [PATCH 115/517] r8169: copy vendor driver 2.5G/5G EEE advertisement constraints Vendor driver r8125 doesn't advertise 2.5G EEE on RTL8125A, and r8126 doesn't advertise 5G EEE. Likely there are compatibility issues, therefore do the same in r8169. With this change we don't have to disable 2.5G EEE advertisement in rtl8125a_config_eee_phy() any longer. We use new phylib accessor phy_set_eee_broken() to mark the respective EEE modes as broken. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/ce185e10-8a2f-4cf8-a49b-fd8fb3c3c8a1@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 5 +++++ drivers/net/ethernet/realtek/r8169_phy_config.c | 16 ++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index aafe113d3bed..1f519eecc1f7 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5256,6 +5256,11 @@ static int r8169_mdio_register(struct rtl8169_private *tp) phy_support_eee(tp->phydev); phy_support_asym_pause(tp->phydev); + /* mimic behavior of r8125/r8126 vendor drivers */ + if (tp->mac_version == RTL_GIGA_MAC_VER_61) + tp->phydev->eee_broken_modes |= MDIO_EEE_2_5GT; + tp->phydev->eee_broken_modes |= MDIO_EEE_5GT; + /* PHY will be woken up in rtl_open() */ phy_suspend(tp->phydev); diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 1d5b33f6c4b5..5307c6ff4e25 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -96,15 +96,7 @@ static void rtl8125_common_config_eee_phy(struct phy_device *phydev) phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); } -static void rtl8125a_config_eee_phy(struct phy_device *phydev) -{ - rtl8168g_config_eee_phy(phydev); - /* disable EEE at 2.5Gbps */ - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); - rtl8125_common_config_eee_phy(phydev); -} - -static void rtl8125b_config_eee_phy(struct phy_device *phydev) +static void rtl8125_config_eee_phy(struct phy_device *phydev) { rtl8168g_config_eee_phy(phydev); rtl8125_common_config_eee_phy(phydev); @@ -1066,7 +1058,7 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, rtl8168g_enable_gphy_10m(phydev); rtl8168g_disable_aldps(phydev); - rtl8125a_config_eee_phy(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, @@ -1106,7 +1098,7 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, rtl8125_legacy_force_mode(phydev); rtl8168g_disable_aldps(phydev); - rtl8125b_config_eee_phy(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, @@ -1116,7 +1108,7 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, rtl8168g_enable_gphy_10m(phydev); rtl8125_legacy_force_mode(phydev); rtl8168g_disable_aldps(phydev); - rtl8125b_config_eee_phy(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, -- 2.51.0 From a924fb5a747c493e99bae0ce528f55ae30a93a8e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 2 Dec 2024 21:14:35 +0100 Subject: [PATCH 116/517] r8169: remove unused flag RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE After 854d71c555dfc3 ("r8169: remove original workaround for RTL8125 broken rx issue") this flag isn't used any longer. So remove it. Signed-off-by: Heiner Kallweit Reviewed-by: Michal Swiatkowski Link: https://patch.msgid.link/d9dd214b-3027-4f60-b0e8-6f34a0c76582@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 1f519eecc1f7..4ec51251615b 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -622,7 +622,6 @@ struct rtl8169_tc_offsets { enum rtl_flag { RTL_FLAG_TASK_RESET_PENDING, - RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, RTL_FLAG_TASK_TX_TIMEOUT, RTL_FLAG_MAX }; @@ -4749,8 +4748,6 @@ static void rtl_task(struct work_struct *work) reset: rtl_reset_work(tp); netif_wake_queue(tp->dev); - } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { - rtl_reset_work(tp); } } -- 2.51.0 From 31e5c12785164a84028c96e7cc39f3cb6e81c27e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 2 Dec 2024 21:20:02 +0100 Subject: [PATCH 117/517] r8169: remove support for chip version 11 This is a follow-up to 982300c115d2 ("r8169: remove detection of chip version 11 (early RTL8168b)"). Nobody complained yet, so remove support for this chip version. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/b689ab6d-20b5-4b64-bd7e-531a0a972ba3@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 2 +- drivers/net/ethernet/realtek/r8169_main.c | 14 +------------- drivers/net/ethernet/realtek/r8169_phy_config.c | 10 ---------- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index be4c9622618d..8904aae41aca 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -23,7 +23,7 @@ enum mac_version { RTL_GIGA_MAC_VER_08, RTL_GIGA_MAC_VER_09, RTL_GIGA_MAC_VER_10, - RTL_GIGA_MAC_VER_11, + /* support for RTL_GIGA_MAC_VER_11 has been removed */ /* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */ /* RTL_GIGA_MAC_VER_13 was merged with VER_10 */ RTL_GIGA_MAC_VER_14, diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 4ec51251615b..e435f17fa722 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -103,7 +103,6 @@ static const struct { [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, - [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" }, [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, @@ -2334,7 +2333,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) /* 8168B family. */ { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, - /* This one is very old and rare, let's see if anybody complains. + /* This one is very old and rare, support has been removed. * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, */ @@ -3829,7 +3828,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401, [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, @@ -4705,12 +4703,6 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) if (status & LinkChg) phy_mac_interrupt(tp->phydev); - if (unlikely(status & RxFIFOOver && - tp->mac_version == RTL_GIGA_MAC_VER_11)) { - netif_stop_queue(tp->dev); - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); - } - rtl_irq_disable(tp); napi_schedule(&tp->napi); out: @@ -5127,9 +5119,6 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp) if (tp->mac_version <= RTL_GIGA_MAC_VER_06) tp->irq_mask |= SYSErr | RxFIFOOver; - else if (tp->mac_version == RTL_GIGA_MAC_VER_11) - /* special workaround needed */ - tp->irq_mask |= RxFIFOOver; } static int rtl_alloc_irq(struct rtl8169_private *tp) @@ -5324,7 +5313,6 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: return JUMBO_7K; /* RTL8168b */ - case RTL_GIGA_MAC_VER_11: case RTL_GIGA_MAC_VER_17: return JUMBO_4K; /* RTL8168c */ diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 5307c6ff4e25..b28b30390e84 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -276,15 +276,6 @@ static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp, rtl_writephy_batch(phydev, phy_reg_init); } -static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp, - struct phy_device *phydev) -{ - phy_write(phydev, 0x1f, 0x0001); - phy_set_bits(phydev, 0x16, BIT(0)); - phy_write(phydev, 0x10, 0xf41b); - phy_write(phydev, 0x1f, 0x0000); -} - static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { @@ -1136,7 +1127,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_08] = rtl8102e_hw_phy_config, [RTL_GIGA_MAC_VER_09] = rtl8102e_hw_phy_config, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl8168bb_hw_phy_config, [RTL_GIGA_MAC_VER_14] = rtl8401_hw_phy_config, [RTL_GIGA_MAC_VER_17] = rtl8168bef_hw_phy_config, [RTL_GIGA_MAC_VER_18] = rtl8168cp_1_hw_phy_config, -- 2.51.0 From 29bfd059af1164901861876a59ff00abe5571d04 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 13 Dec 2024 20:01:41 +0100 Subject: [PATCH 118/517] r8169: adjust version numbering for RTL8126 Adjust version numbering for RTL8126, so that it doesn't overlap with new RTL8125 versions. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/6a354364-20e9-48ad-a198-468264288757@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 4 +- drivers/net/ethernet/realtek/r8169_main.c | 62 +++++++++---------- .../net/ethernet/realtek/r8169_phy_config.c | 4 +- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 8904aae41aca..00d74e76c6f2 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -69,8 +69,8 @@ enum mac_version { RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, RTL_GIGA_MAC_VER_64, - RTL_GIGA_MAC_VER_65, - RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, RTL_GIGA_MAC_NONE }; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index e435f17fa722..f0d6261f92bb 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -139,8 +139,8 @@ static const struct { /* reserve 62 for CFG_METHOD_4 in the vendor driver */ [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, - [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, - [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, }; static const struct pci_device_id rtl8169_pci_tbl[] = { @@ -1227,7 +1227,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) case RTL_GIGA_MAC_VER_31: r8168dp_2_mdio_write(tp, location, val); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168g_mdio_write(tp, location, val); break; default: @@ -1242,7 +1242,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return r8168dp_2_mdio_read(tp, location); - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: return r8168g_mdio_read(tp, location); default: return r8169_mdio_read(tp, location); @@ -1573,7 +1573,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); break; default: @@ -2046,7 +2046,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) tp->tx_lpi_timer = timer_val; r8168_mac_ocp_write(tp, 0xe048, timer_val); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: tp->tx_lpi_timer = timer_val; RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); break; @@ -2254,8 +2254,8 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) enum mac_version ver; } mac_info[] = { /* 8126A family. */ - { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 }, - { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, /* 8125D family. */ { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, @@ -2525,7 +2525,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | RX_PAUSE_SLOT_ON); break; @@ -2657,7 +2657,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); break; - case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); @@ -2926,7 +2926,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: rtl_eri_set_bits(tp, 0xd4, 0x0c00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); break; default: @@ -2940,7 +2940,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: rtl_eri_clear_bits(tp, 0xd4, 0x1f00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); break; default: @@ -2966,8 +2966,8 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) rtl_mod_config5(tp, 0, ASPM_en); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_65: - case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -2978,7 +2978,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: /* reset ephy tx/rx disable timer */ r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); /* chip can trigger L1.2 */ @@ -2990,7 +2990,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } else { switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); break; default: @@ -2998,8 +2998,8 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_65: - case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -3719,12 +3719,12 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_65 || - tp->mac_version == RTL_GIGA_MAC_VER_66) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); - if (tp->mac_version == RTL_GIGA_MAC_VER_65 || - tp->mac_version == RTL_GIGA_MAC_VER_66) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); @@ -3742,8 +3742,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); - if (tp->mac_version == RTL_GIGA_MAC_VER_65 || - tp->mac_version == RTL_GIGA_MAC_VER_66) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); else r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); @@ -3863,8 +3863,8 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, - [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, - [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, }; if (hw_configs[tp->mac_version]) @@ -3885,8 +3885,8 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) RTL_W32(tp, i, 0); break; case RTL_GIGA_MAC_VER_63: - case RTL_GIGA_MAC_VER_65: - case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: for (i = 0xa00; i < 0xa80; i += 4) RTL_W32(tp, i, 0); RTL_W16(tp, INT_CFG1_8125, 0x0000); @@ -4118,7 +4118,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: rtl_enable_rxdvgate(tp); fsleep(2000); break; @@ -4275,7 +4275,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: padto = max_t(unsigned int, padto, ETH_ZLEN); break; default: @@ -5294,7 +5294,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: rtl_hw_init_8168g(tp); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: rtl_hw_init_8125(tp); break; default: diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index b28b30390e84..bc498ea78034 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1162,8 +1162,8 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, - [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, - [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, }; if (phy_configs[ver]) -- 2.51.0 From df24521b323b138471e6ea933e24af5f77c30f33 Mon Sep 17 00:00:00 2001 From: ChunHao Lin Date: Fri, 13 Dec 2024 20:02:58 +0100 Subject: [PATCH 119/517] r8169: add support for RTL8125D rev.b Add support for RTL8125D rev.b. Its XID is 0x689. It is basically based on the one with XID 0x688, but with different firmware file. Signed-off-by: ChunHao Lin [hkallweit1@gmail.com: rebased after adjusted version numbering] Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/75e5e9ec-d01f-43ac-b0f4-e7456baf18d1@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 1 + drivers/net/ethernet/realtek/r8169_main.c | 6 ++++++ drivers/net/ethernet/realtek/r8169_phy_config.c | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 00d74e76c6f2..e0817f2a311a 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -69,6 +69,7 @@ enum mac_version { RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_65, RTL_GIGA_MAC_VER_70, RTL_GIGA_MAC_VER_71, RTL_GIGA_MAC_NONE diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index f0d6261f92bb..16c1e74554b2 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -56,6 +56,7 @@ #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" +#define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" @@ -139,6 +140,7 @@ static const struct { /* reserve 62 for CFG_METHOD_4 in the vendor driver */ [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, + [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, }; @@ -705,6 +707,7 @@ MODULE_FIRMWARE(FIRMWARE_8107E_2); MODULE_FIRMWARE(FIRMWARE_8125A_3); MODULE_FIRMWARE(FIRMWARE_8125B_2); MODULE_FIRMWARE(FIRMWARE_8125D_1); +MODULE_FIRMWARE(FIRMWARE_8125D_2); MODULE_FIRMWARE(FIRMWARE_8126A_2); MODULE_FIRMWARE(FIRMWARE_8126A_3); @@ -2258,6 +2261,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, /* 8125D family. */ + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, /* 8125B family. */ @@ -3863,6 +3867,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, }; @@ -3881,6 +3886,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_64: + case RTL_GIGA_MAC_VER_65: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); break; diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index bc498ea78034..968c8a2185a4 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1162,6 +1162,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, }; -- 2.51.0 From acdb177b82422fdb3c015b9cc048720f11cc944e Mon Sep 17 00:00:00 2001 From: ChunHao Lin Date: Tue, 7 Jan 2025 14:43:55 +0800 Subject: [PATCH 120/517] r8169: add support for RTL8125BP rev.b Add support for RTL8125BP rev.b. Its XID is 0x689. This chip supports DASH and its dash type is "RTL_DASH_25_BP". Signed-off-by: ChunHao Lin Reviewed-by: Heiner Kallweit Link: https://patch.msgid.link/20250107064355.104711-1-hau@realtek.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/realtek/r8169.h | 1 + drivers/net/ethernet/realtek/r8169_main.c | 30 +++++++++++++++++++ .../net/ethernet/realtek/r8169_phy_config.c | 23 ++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index e0817f2a311a..7a194a8ab989 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -70,6 +70,7 @@ enum mac_version { RTL_GIGA_MAC_VER_63, RTL_GIGA_MAC_VER_64, RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, RTL_GIGA_MAC_VER_71, RTL_GIGA_MAC_NONE diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 16c1e74554b2..b99ddcbec526 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -57,6 +57,7 @@ #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" #define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" #define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" +#define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" @@ -141,6 +142,7 @@ static const struct { [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, + [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, }; @@ -631,6 +633,7 @@ enum rtl_dash_type { RTL_DASH_NONE, RTL_DASH_DP, RTL_DASH_EP, + RTL_DASH_25_BP, }; struct rtl8169_private { @@ -708,6 +711,7 @@ MODULE_FIRMWARE(FIRMWARE_8125A_3); MODULE_FIRMWARE(FIRMWARE_8125B_2); MODULE_FIRMWARE(FIRMWARE_8125D_1); MODULE_FIRMWARE(FIRMWARE_8125D_2); +MODULE_FIRMWARE(FIRMWARE_8125BP_2); MODULE_FIRMWARE(FIRMWARE_8126A_2); MODULE_FIRMWARE(FIRMWARE_8126A_3); @@ -1360,10 +1364,19 @@ static void rtl8168ep_driver_start(struct rtl8169_private *tp) rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); } +static void rtl8125bp_driver_start(struct rtl8169_private *tp) +{ + r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_START); + r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); + r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); +} + static void rtl8168_driver_start(struct rtl8169_private *tp) { if (tp->dash_type == RTL_DASH_DP) rtl8168dp_driver_start(tp); + else if (tp->dash_type == RTL_DASH_25_BP) + rtl8125bp_driver_start(tp); else rtl8168ep_driver_start(tp); } @@ -1384,10 +1397,19 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); } +static void rtl8125bp_driver_stop(struct rtl8169_private *tp) +{ + r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_STOP); + r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); + r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); +} + static void rtl8168_driver_stop(struct rtl8169_private *tp) { if (tp->dash_type == RTL_DASH_DP) rtl8168dp_driver_stop(tp); + else if (tp->dash_type == RTL_DASH_25_BP) + rtl8125bp_driver_stop(tp); else rtl8168ep_driver_stop(tp); } @@ -1410,6 +1432,7 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp) case RTL_DASH_DP: return r8168dp_check_dash(tp); case RTL_DASH_EP: + case RTL_DASH_25_BP: return r8168ep_check_dash(tp); default: return false; @@ -1424,6 +1447,8 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) return RTL_DASH_DP; case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: return RTL_DASH_EP; + case RTL_GIGA_MAC_VER_66: + return RTL_DASH_25_BP; default: return RTL_DASH_NONE; } @@ -2260,6 +2285,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + /* 8125BP family. */ + { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, + /* 8125D family. */ { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, @@ -3868,6 +3896,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, }; @@ -3887,6 +3916,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_64: case RTL_GIGA_MAC_VER_65: + case RTL_GIGA_MAC_VER_66: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); break; diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 968c8a2185a4..cf95e579c65d 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1102,6 +1102,28 @@ static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, rtl8125_config_eee_phy(phydev); } +static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + + r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); + + phy_write(phydev, 0x1f, 0x0b87); + phy_write(phydev, 0x16, 0x8088); + phy_modify(phydev, 0x17, 0xff00, 0x9000); + phy_write(phydev, 0x16, 0x808f); + phy_modify(phydev, 0x17, 0xff00, 0x9000); + phy_write(phydev, 0x1f, 0x0000); + + r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); +} + static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { @@ -1163,6 +1185,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, }; -- 2.51.0 From 3ff41a19c5246bfa3fbe37fe5d4b091393dd949a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 3 Feb 2025 21:35:24 +0100 Subject: [PATCH 121/517] r8169: make Kconfig option for LED support user-visible Make config option R8169_LEDS user-visible, so that users can remove support if not needed. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/d29f0cdb-32bf-435f-b59d-dc96bca1e3ab@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index 8a8ea51c639e..fe136f61586f 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -114,7 +114,8 @@ config R8169 will be called r8169. This is recommended. config R8169_LEDS - def_bool R8169 && LEDS_TRIGGER_NETDEV + bool "Support for controlling the NIC LEDs" + depends on R8169 && LEDS_TRIGGER_NETDEV depends on !(R8169=y && LEDS_CLASS=m) help Optional support for controlling the NIC LED's with the netdev -- 2.51.0 From f0f1c081b8621b6572e2e1fb59c598b8ebca85d5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 12 Feb 2025 08:03:56 +0100 Subject: [PATCH 122/517] r8169: add support for Intel Killer E5000 This adds support for the Intel Killer E5000 which seems to be a rebranded RTL8126. Copied from r8126 vendor driver. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/9db73e9b-e2e8-45de-97a5-041c5f71d774@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index b99ddcbec526..c6acf6709524 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -169,6 +169,7 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { PCI_VDEVICE(REALTEK, 0x8125) }, { PCI_VDEVICE(REALTEK, 0x8126) }, { PCI_VDEVICE(REALTEK, 0x3000) }, + { PCI_VDEVICE(REALTEK, 0x5000) }, {} }; -- 2.51.0 From 6c0325b41afeb91bf75bf5e75b0062834b033190 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 13 Feb 2025 20:15:42 +0100 Subject: [PATCH 123/517] r8169: add PHY c45 ops for MDIO_MMD_VENDOR2 registers The integrated PHYs on chip versions from RTL8168g allow to address MDIO_MMD_VEND2 registers. All c22 standard registers are mapped to MDIO_MMD_VEND2 registers. So far the paging mechanism is used to address PHY registers. Add support for c45 ops to address MDIO_MMD_VEND2 registers directly, w/o the paging. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/d6f97eaa-0f13-468f-89cb-75a41087bc4a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index c6acf6709524..d974461db6b0 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5228,6 +5228,33 @@ static int r8169_mdio_write_reg(struct mii_bus *mii_bus, int phyaddr, return 0; } +static int r8169_mdio_read_reg_c45(struct mii_bus *mii_bus, int addr, + int devnum, int regnum) +{ + struct rtl8169_private *tp = mii_bus->priv; + + if (addr > 0) + return -ENODEV; + + if (devnum == MDIO_MMD_VEND2 && regnum > MDIO_STAT2) + return r8168_phy_ocp_read(tp, regnum); + + return 0; +} + +static int r8169_mdio_write_reg_c45(struct mii_bus *mii_bus, int addr, + int devnum, int regnum, u16 val) +{ + struct rtl8169_private *tp = mii_bus->priv; + + if (addr > 0 || devnum != MDIO_MMD_VEND2 || regnum <= MDIO_STAT2) + return -ENODEV; + + r8168_phy_ocp_write(tp, regnum, val); + + return 0; +} + static int r8169_mdio_register(struct rtl8169_private *tp) { struct pci_dev *pdev = tp->pci_dev; @@ -5258,6 +5285,11 @@ static int r8169_mdio_register(struct rtl8169_private *tp) new_bus->read = r8169_mdio_read_reg; new_bus->write = r8169_mdio_write_reg; + if (tp->mac_version >= RTL_GIGA_MAC_VER_40) { + new_bus->read_c45 = r8169_mdio_read_reg_c45; + new_bus->write_c45 = r8169_mdio_write_reg_c45; + } + ret = devm_mdiobus_register(&pdev->dev, new_bus); if (ret) return ret; -- 2.51.0 From 8589e361c146c0a256bfa01874126364a1a6c540 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 7 Mar 2025 08:29:47 +0100 Subject: [PATCH 124/517] r8169: increase max jumbo packet size on RTL8125/RTL8126 Realtek confirmed that all RTL8125/RTL8126 chip versions support up to 16K jumbo packets. Reflect this in the driver. Tested by Rui on RTL8125B with 12K jumbo packets. Suggested-by: Rui Salvaterra Tested-by: Rui Salvaterra Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/396762ad-cc65-4e60-b01e-8847db89e98b@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index d974461db6b0..90585f44ed77 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -89,6 +89,7 @@ #define JUMBO_6K (6 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) #define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) +#define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN) static const struct { const char *name; @@ -5387,6 +5388,9 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) /* RTL8168c */ case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: return JUMBO_6K; + /* RTL8125/8126 */ + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + return JUMBO_16K; default: return JUMBO_9K; } -- 2.51.0 From 685a636e3096ae8ba35b8f928ba1bc4ec10462ba Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 12 Mar 2025 20:21:42 +0100 Subject: [PATCH 125/517] r8169: switch away from deprecated pcim_iomap_table Avoid using deprecated pcim_iomap_table by switching to pcim_iomap_region. Signed-off-by: Heiner Kallweit Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Link: https://patch.msgid.link/a36b4cf3-c792-40fa-8164-5dc9d5f14dd0@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/realtek/r8169_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 90585f44ed77..37e1cbf87e2d 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5474,11 +5474,10 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (region < 0) return dev_err_probe(&pdev->dev, -ENODEV, "no MMIO resource found\n"); - rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME); - if (rc < 0) - return dev_err_probe(&pdev->dev, rc, "cannot remap MMIO, aborting\n"); - - tp->mmio_addr = pcim_iomap_table(pdev)[region]; + tp->mmio_addr = pcim_iomap_region(pdev, region, KBUILD_MODNAME); + if (IS_ERR(tp->mmio_addr)) + return dev_err_probe(&pdev->dev, PTR_ERR(tp->mmio_addr), + "cannot remap MMIO, aborting\n"); txconfig = RTL_R32(tp, TxConfig); if (txconfig == ~0U) -- 2.51.0 From ae7d0b24a7b500d0d2b5f87dc2311464714542d9 Mon Sep 17 00:00:00 2001 From: ChunHao Lin Date: Tue, 18 Mar 2025 16:37:20 +0800 Subject: [PATCH 126/517] r8169: enable RTL8168H/RTL8168EP/RTL8168FP ASPM support This patch will enable RTL8168H/RTL8168EP/RTL8168FP ASPM support on the platforms that have tested with ASPM enabled. Signed-off-by: ChunHao Lin Reviewed-by: Heiner Kallweit Link: https://patch.msgid.link/20250318083721.4127-2-hau@realtek.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 37e1cbf87e2d..f5150c9a0f66 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5425,7 +5425,7 @@ static void rtl_init_mac_address(struct rtl8169_private *tp) /* register is set if system vendor successfully tested ASPM 1.2 */ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) { - if (tp->mac_version >= RTL_GIGA_MAC_VER_61 && + if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && r8168_mac_ocp_read(tp, 0xc0b2) & 0xf) return true; -- 2.51.0 From c20f71142b7d50326a236e242a375831f453193a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Apr 2025 21:05:37 +0200 Subject: [PATCH 127/517] r8169: add helper rtl_csi_mod for accessing extended config space Add a helper for the Realtek-specific mechanism for accessing extended config space if native access isn't possible. This avoids code duplication. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/b368fd91-57d7-4cb5-9342-98b4d8fe9aea@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index f5150c9a0f66..efdfa95ff693 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2852,10 +2852,23 @@ static u32 rtl_csi_read(struct rtl8169_private *tp, int addr) RTL_R32(tp, CSIDR) : ~0; } +static void rtl_csi_mod(struct rtl8169_private *tp, int addr, + u32 mask, u32 set) +{ + u32 val; + + WARN(addr % 4, "Invalid CSI address %#x\n", addr); + + netdev_notice_once(tp->dev, + "No native access to PCI extended config space, falling back to CSI\n"); + + val = rtl_csi_read(tp, addr); + rtl_csi_write(tp, addr, (val & ~mask) | set); +} + static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp) { struct pci_dev *pdev = tp->pci_dev; - u32 csi; int rc; u8 val; @@ -2872,16 +2885,12 @@ static void rtl_disable_zrxdc_timeout(struct rtl8169_private *tp) } } - netdev_notice_once(tp->dev, - "No native access to PCI extended config space, falling back to CSI\n"); - csi = rtl_csi_read(tp, RTL_GEN3_RELATED_OFF); - rtl_csi_write(tp, RTL_GEN3_RELATED_OFF, csi & ~RTL_GEN3_ZRXDC_NONCOMPL); + rtl_csi_mod(tp, RTL_GEN3_RELATED_OFF, RTL_GEN3_ZRXDC_NONCOMPL, 0); } static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val) { struct pci_dev *pdev = tp->pci_dev; - u32 csi; /* According to Realtek the value at config space address 0x070f * controls the L0s/L1 entrance latency. We try standard ECAM access @@ -2893,10 +2902,7 @@ static void rtl_set_aspm_entry_latency(struct rtl8169_private *tp, u8 val) pci_write_config_byte(pdev, 0x070f, val) == PCIBIOS_SUCCESSFUL) return; - netdev_notice_once(tp->dev, - "No native access to PCI extended config space, falling back to CSI\n"); - csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff; - rtl_csi_write(tp, 0x070c, csi | val << 24); + rtl_csi_mod(tp, 0x070c, 0xff000000, val << 24); } static void rtl_set_def_aspm_entry_latency(struct rtl8169_private *tp) -- 2.51.0 From aaf2eb9eaec5f513d9a4870701574ca85343f144 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Apr 2025 21:14:47 +0200 Subject: [PATCH 128/517] r8169: add helper rtl8125_phy_param The integrated PHY's of RTL8125/8126 have an own mechanism to access PHY parameters, similar to what r8168g_phy_param does on earlier PHY versions. Add helper rtl8125_phy_param to simplify the code. Signed-off-by: Heiner Kallweit Link: https://patch.msgid.link/847b7356-12d6-441b-ade9-4b6e1539b84a@gmail.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/realtek/r8169_phy_config.c | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index cf95e579c65d..748ca8b212ba 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -50,6 +50,15 @@ static void r8168g_phy_param(struct phy_device *phydev, u16 parm, phy_restore_page(phydev, oldpage, 0); } +static void rtl8125_phy_param(struct phy_device *phydev, u16 parm, + u16 mask, u16 val) +{ + phy_lock_mdio_bus(phydev); + __phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xb87c, parm); + __phy_modify_mmd(phydev, MDIO_MMD_VEND2, 0xb87e, mask, val); + phy_unlock_mdio_bus(phydev); +} + struct phy_reg { u16 reg; u16 val; @@ -1004,12 +1013,8 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, phy_write_paged(phydev, 0xac5, 0x16, 0x01ff); phy_modify_paged(phydev, 0xac8, 0x15, 0x00f0, 0x0030); - phy_write(phydev, 0x1f, 0x0b87); - phy_write(phydev, 0x16, 0x80a2); - phy_write(phydev, 0x17, 0x0153); - phy_write(phydev, 0x16, 0x809c); - phy_write(phydev, 0x17, 0x0153); - phy_write(phydev, 0x1f, 0x0000); + rtl8125_phy_param(phydev, 0x80a2, 0xffff, 0x0153); + rtl8125_phy_param(phydev, 0x809c, 0xffff, 0x0153); phy_write(phydev, 0x1f, 0x0a43); phy_write(phydev, 0x13, 0x81B3); @@ -1061,14 +1066,9 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); - phy_write(phydev, 0x1f, 0x0b87); - phy_write(phydev, 0x16, 0x80f5); - phy_write(phydev, 0x17, 0x760e); - phy_write(phydev, 0x16, 0x8107); - phy_write(phydev, 0x17, 0x360e); - phy_write(phydev, 0x16, 0x8551); - phy_modify(phydev, 0x17, 0xff00, 0x0800); - phy_write(phydev, 0x1f, 0x0000); + rtl8125_phy_param(phydev, 0x80f5, 0xffff, 0x760e); + rtl8125_phy_param(phydev, 0x8107, 0xffff, 0x360e); + rtl8125_phy_param(phydev, 0x8551, 0xff00, 0x0800); phy_modify_paged(phydev, 0xbf0, 0x10, 0xe000, 0xa000); phy_modify_paged(phydev, 0xbf4, 0x13, 0x0f00, 0x0300); @@ -1110,12 +1110,8 @@ static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); - phy_write(phydev, 0x1f, 0x0b87); - phy_write(phydev, 0x16, 0x8088); - phy_modify(phydev, 0x17, 0xff00, 0x9000); - phy_write(phydev, 0x16, 0x808f); - phy_modify(phydev, 0x17, 0xff00, 0x9000); - phy_write(phydev, 0x1f, 0x0000); + rtl8125_phy_param(phydev, 0x8088, 0xff00, 0x9000); + rtl8125_phy_param(phydev, 0x808f, 0xff00, 0x9000); r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); -- 2.51.0 From 09aaa64852d52817e4cd8421cc789e862de34eae Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 15 Apr 2025 21:29:34 +0200 Subject: [PATCH 129/517] r8169: refactor chip version detection Refactor chip version detection and merge both configuration tables. Apart from reducing the code by a third, this paves the way for merging chip version handling if only difference is the firmware. Signed-off-by: Heiner Kallweit Reviewed-by: Michal Swiatkowski Link: https://patch.msgid.link/1fea533a-dd5a-4198-a9e2-895e11083947@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 325 +++++++++------------- 1 file changed, 128 insertions(+), 197 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index efdfa95ff693..140577e626bd 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -91,61 +91,114 @@ #define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN) #define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN) -static const struct { +static const struct rtl_chip_info { + u16 mask; + u16 val; + enum mac_version mac_version; const char *name; const char *fw_name; } rtl_chip_infos[] = { - /* PCI devices. */ - [RTL_GIGA_MAC_VER_02] = {"RTL8169s" }, - [RTL_GIGA_MAC_VER_03] = {"RTL8110s" }, - [RTL_GIGA_MAC_VER_04] = {"RTL8169sb/8110sb" }, - [RTL_GIGA_MAC_VER_05] = {"RTL8169sc/8110sc" }, - [RTL_GIGA_MAC_VER_06] = {"RTL8169sc/8110sc" }, - /* PCI-E devices. */ - [RTL_GIGA_MAC_VER_07] = {"RTL8102e" }, - [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, - [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, - [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, - [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, - [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, - [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, - [RTL_GIGA_MAC_VER_19] = {"RTL8168c/8111c" }, - [RTL_GIGA_MAC_VER_20] = {"RTL8168c/8111c" }, - [RTL_GIGA_MAC_VER_21] = {"RTL8168c/8111c" }, - [RTL_GIGA_MAC_VER_22] = {"RTL8168c/8111c" }, - [RTL_GIGA_MAC_VER_23] = {"RTL8168cp/8111cp" }, - [RTL_GIGA_MAC_VER_24] = {"RTL8168cp/8111cp" }, - [RTL_GIGA_MAC_VER_25] = {"RTL8168d/8111d", FIRMWARE_8168D_1}, - [RTL_GIGA_MAC_VER_26] = {"RTL8168d/8111d", FIRMWARE_8168D_2}, - [RTL_GIGA_MAC_VER_28] = {"RTL8168dp/8111dp" }, - [RTL_GIGA_MAC_VER_29] = {"RTL8105e", FIRMWARE_8105E_1}, - [RTL_GIGA_MAC_VER_30] = {"RTL8105e", FIRMWARE_8105E_1}, - [RTL_GIGA_MAC_VER_31] = {"RTL8168dp/8111dp" }, - [RTL_GIGA_MAC_VER_32] = {"RTL8168e/8111e", FIRMWARE_8168E_1}, - [RTL_GIGA_MAC_VER_33] = {"RTL8168e/8111e", FIRMWARE_8168E_2}, - [RTL_GIGA_MAC_VER_34] = {"RTL8168evl/8111evl", FIRMWARE_8168E_3}, - [RTL_GIGA_MAC_VER_35] = {"RTL8168f/8111f", FIRMWARE_8168F_1}, - [RTL_GIGA_MAC_VER_36] = {"RTL8168f/8111f", FIRMWARE_8168F_2}, - [RTL_GIGA_MAC_VER_37] = {"RTL8402", FIRMWARE_8402_1 }, - [RTL_GIGA_MAC_VER_38] = {"RTL8411", FIRMWARE_8411_1 }, - [RTL_GIGA_MAC_VER_39] = {"RTL8106e", FIRMWARE_8106E_1}, - [RTL_GIGA_MAC_VER_40] = {"RTL8168g/8111g", FIRMWARE_8168G_2}, - [RTL_GIGA_MAC_VER_42] = {"RTL8168gu/8111gu", FIRMWARE_8168G_3}, - [RTL_GIGA_MAC_VER_43] = {"RTL8106eus", FIRMWARE_8106E_2}, - [RTL_GIGA_MAC_VER_44] = {"RTL8411b", FIRMWARE_8411_2 }, - [RTL_GIGA_MAC_VER_46] = {"RTL8168h/8111h", FIRMWARE_8168H_2}, - [RTL_GIGA_MAC_VER_48] = {"RTL8107e", FIRMWARE_8107E_2}, - [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" }, - [RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117", FIRMWARE_8168FP_3}, - [RTL_GIGA_MAC_VER_53] = {"RTL8168fp/RTL8117", }, - [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, - /* reserve 62 for CFG_METHOD_4 in the vendor driver */ - [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, - [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, - [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, - [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, - [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, - [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, + /* 8126A family. */ + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, + + /* 8125BP family. */ + { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 }, + + /* 8125D family. */ + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 }, + + /* 8125B family. */ + { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63, "RTL8125B", FIRMWARE_8125B_2 }, + + /* 8125A family. */ + { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 }, + + /* RTL8117 */ + { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" }, + { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117", + FIRMWARE_8168FP_3 }, + + /* 8168EP family. */ + { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51, "RTL8168ep/8111ep" }, + + /* 8168H family. */ + { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46, "RTL8168h/8111h", + FIRMWARE_8168H_2 }, + /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ + { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46, "RTL8168M", FIRMWARE_8168H_2 }, + + /* 8168G family. */ + { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44, "RTL8411b", FIRMWARE_8411_2 }, + { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42, "RTL8168gu/8111gu", + FIRMWARE_8168G_3 }, + { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40, "RTL8168g/8111g", + FIRMWARE_8168G_2 }, + + /* 8168F family. */ + { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38, "RTL8411", FIRMWARE_8411_1 }, + { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36, "RTL8168f/8111f", + FIRMWARE_8168F_2 }, + { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35, "RTL8168f/8111f", + FIRMWARE_8168F_1 }, + + /* 8168E family. */ + { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34, "RTL8168evl/8111evl", + FIRMWARE_8168E_3 }, + { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32, "RTL8168e/8111e", + FIRMWARE_8168E_1 }, + { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33, "RTL8168e/8111e", + FIRMWARE_8168E_2 }, + + /* 8168D family. */ + { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25, "RTL8168d/8111d", + FIRMWARE_8168D_1 }, + { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26, "RTL8168d/8111d", + FIRMWARE_8168D_2 }, + + /* 8168DP family. */ + { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28, "RTL8168dp/8111dp" }, + { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31, "RTL8168dp/8111dp" }, + + /* 8168C family. */ + { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23, "RTL8168cp/8111cp" }, + { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18, "RTL8168cp/8111cp" }, + { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24, "RTL8168cp/8111cp" }, + { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19, "RTL8168c/8111c" }, + { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20, "RTL8168c/8111c" }, + { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21, "RTL8168c/8111c" }, + { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22, "RTL8168c/8111c" }, + + /* 8168B family. */ + { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17, "RTL8168b/8111b" }, + /* This one is very old and rare, support has been removed. + * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11, "RTL8168b/8111b" }, + */ + + /* 8101 family. */ + { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39, "RTL8106e", FIRMWARE_8106E_1 }, + { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37, "RTL8402", FIRMWARE_8402_1 }, + { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29, "RTL8105e", FIRMWARE_8105E_1 }, + { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30, "RTL8105e", FIRMWARE_8105E_1 }, + { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08, "RTL8102e" }, + { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08, "RTL8102e" }, + { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07, "RTL8102e" }, + { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07, "RTL8102e" }, + { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14, "RTL8401" }, + { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" }, + { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09, "RTL8102e/RTL8103e" }, + { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10, "RTL8101e/RTL8100e" }, + + /* 8110 family. */ + { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06, "RTL8169sc/8110sc" }, + { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05, "RTL8169sc/8110sc" }, + { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04, "RTL8169sb/8110sb" }, + { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03, "RTL8110s" }, + { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02, "RTL8169s" }, + + /* Catch-all */ + { 0x000, 0x000, RTL_GIGA_MAC_NONE } }; static const struct pci_device_id rtl8169_pci_tbl[] = { @@ -2265,151 +2318,30 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, }; -static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) +static const struct rtl_chip_info *rtl8169_get_chip_version(u16 xid, bool gmii) { - /* - * The driver currently handles the 8168Bf and the 8168Be identically - * but they can be identified more specifically through the test below - * if needed: - * - * (RTL_R32(tp, TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be - * - * Same thing for the 8101Eb and the 8101Ec: - * - * (RTL_R32(tp, TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec - */ - static const struct rtl_mac_info { - u16 mask; - u16 val; - enum mac_version ver; - } mac_info[] = { - /* 8126A family. */ - { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, - { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, - - /* 8125BP family. */ - { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, - - /* 8125D family. */ - { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, - { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, - - /* 8125B family. */ - { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, - - /* 8125A family. */ - { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61 }, - /* It seems only XID 609 made it to the mass market. - * { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 }, - * { 0x7c8, 0x608, RTL_GIGA_MAC_VER_61 }, - */ - - /* RTL8117 */ - { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53 }, - { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52 }, - - /* 8168EP family. */ - { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51 }, - /* It seems this chip version never made it to - * the wild. Let's disable detection. - * { 0x7cf, 0x501, RTL_GIGA_MAC_VER_50 }, - * { 0x7cf, 0x500, RTL_GIGA_MAC_VER_49 }, - */ - - /* 8168H family. */ - { 0x7cf, 0x541, RTL_GIGA_MAC_VER_46 }, - /* It seems this chip version never made it to - * the wild. Let's disable detection. - * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 }, - */ - /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ - { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 }, - - /* 8168G family. */ - { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 }, - { 0x7cf, 0x509, RTL_GIGA_MAC_VER_42 }, - /* It seems this chip version never made it to - * the wild. Let's disable detection. - * { 0x7cf, 0x4c1, RTL_GIGA_MAC_VER_41 }, - */ - { 0x7cf, 0x4c0, RTL_GIGA_MAC_VER_40 }, - - /* 8168F family. */ - { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 }, - { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 }, - { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 }, - - /* 8168E family. */ - { 0x7c8, 0x2c8, RTL_GIGA_MAC_VER_34 }, - { 0x7cf, 0x2c1, RTL_GIGA_MAC_VER_32 }, - { 0x7c8, 0x2c0, RTL_GIGA_MAC_VER_33 }, - - /* 8168D family. */ - { 0x7cf, 0x281, RTL_GIGA_MAC_VER_25 }, - { 0x7c8, 0x280, RTL_GIGA_MAC_VER_26 }, - - /* 8168DP family. */ - /* It seems this early RTL8168dp version never made it to - * the wild. Support has been removed. - * { 0x7cf, 0x288, RTL_GIGA_MAC_VER_27 }, - */ - { 0x7cf, 0x28a, RTL_GIGA_MAC_VER_28 }, - { 0x7cf, 0x28b, RTL_GIGA_MAC_VER_31 }, - - /* 8168C family. */ - { 0x7cf, 0x3c9, RTL_GIGA_MAC_VER_23 }, - { 0x7cf, 0x3c8, RTL_GIGA_MAC_VER_18 }, - { 0x7c8, 0x3c8, RTL_GIGA_MAC_VER_24 }, - { 0x7cf, 0x3c0, RTL_GIGA_MAC_VER_19 }, - { 0x7cf, 0x3c2, RTL_GIGA_MAC_VER_20 }, - { 0x7cf, 0x3c3, RTL_GIGA_MAC_VER_21 }, - { 0x7c8, 0x3c0, RTL_GIGA_MAC_VER_22 }, - - /* 8168B family. */ - { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, - /* This one is very old and rare, support has been removed. - * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, - */ - - /* 8101 family. */ - { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 }, - { 0x7c8, 0x440, RTL_GIGA_MAC_VER_37 }, - { 0x7cf, 0x409, RTL_GIGA_MAC_VER_29 }, - { 0x7c8, 0x408, RTL_GIGA_MAC_VER_30 }, - { 0x7cf, 0x349, RTL_GIGA_MAC_VER_08 }, - { 0x7cf, 0x249, RTL_GIGA_MAC_VER_08 }, - { 0x7cf, 0x348, RTL_GIGA_MAC_VER_07 }, - { 0x7cf, 0x248, RTL_GIGA_MAC_VER_07 }, - { 0x7cf, 0x240, RTL_GIGA_MAC_VER_14 }, - { 0x7c8, 0x348, RTL_GIGA_MAC_VER_09 }, - { 0x7c8, 0x248, RTL_GIGA_MAC_VER_09 }, - { 0x7c8, 0x340, RTL_GIGA_MAC_VER_10 }, - - /* 8110 family. */ - { 0xfc8, 0x980, RTL_GIGA_MAC_VER_06 }, - { 0xfc8, 0x180, RTL_GIGA_MAC_VER_05 }, - { 0xfc8, 0x100, RTL_GIGA_MAC_VER_04 }, - { 0xfc8, 0x040, RTL_GIGA_MAC_VER_03 }, - { 0xfc8, 0x008, RTL_GIGA_MAC_VER_02 }, - - /* Catch-all */ - { 0x000, 0x000, RTL_GIGA_MAC_NONE } + /* Chips combining a 1Gbps MAC with a 100Mbps PHY */ + static const struct rtl_chip_info rtl8106eus_info = { + .mac_version = RTL_GIGA_MAC_VER_43, + .name = "RTL8106eus", + .fw_name = FIRMWARE_8106E_2, + }; + static const struct rtl_chip_info rtl8107e_info = { + .mac_version = RTL_GIGA_MAC_VER_48, + .name = "RTL8107e", + .fw_name = FIRMWARE_8107E_2, }; - const struct rtl_mac_info *p = mac_info; - enum mac_version ver; + const struct rtl_chip_info *p = rtl_chip_infos; while ((xid & p->mask) != p->val) p++; - ver = p->ver; - if (ver != RTL_GIGA_MAC_NONE && !gmii) { - if (ver == RTL_GIGA_MAC_VER_42) - ver = RTL_GIGA_MAC_VER_43; - else if (ver == RTL_GIGA_MAC_VER_46) - ver = RTL_GIGA_MAC_VER_48; - } + if (p->mac_version == RTL_GIGA_MAC_VER_42 && !gmii) + return &rtl8106eus_info; + if (p->mac_version == RTL_GIGA_MAC_VER_46 && !gmii) + return &rtl8107e_info; - return ver; + return p; } static void rtl_release_firmware(struct rtl8169_private *tp) @@ -5440,9 +5372,9 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { + const struct rtl_chip_info *chip; struct rtl8169_private *tp; int jumbo_max, region, rc; - enum mac_version chipset; struct net_device *dev; u32 txconfig; u16 xid; @@ -5492,12 +5424,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) xid = (txconfig >> 20) & 0xfcf; /* Identify chip attached to board */ - chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); - if (chipset == RTL_GIGA_MAC_NONE) + chip = rtl8169_get_chip_version(xid, tp->supports_gmii); + if (chip->mac_version == RTL_GIGA_MAC_NONE) return dev_err_probe(&pdev->dev, -ENODEV, "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n", xid); - tp->mac_version = chipset; + tp->mac_version = chip->mac_version; + tp->fw_name = chip->fw_name; /* Disable ASPM L1 as that cause random device stop working * problems as well as full system hangs for some PCIe devices users. @@ -5602,8 +5535,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_set_irq_mask(tp); - tp->fw_name = rtl_chip_infos[chipset].fw_name; - tp->counters = dmam_alloc_coherent (&pdev->dev, sizeof(*tp->counters), &tp->counters_phys_addr, GFP_KERNEL); @@ -5628,7 +5559,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", - rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); + chip->name, dev->dev_addr, xid, tp->irq); if (jumbo_max) netdev_info(dev, "jumbo features [frames: %d bytes, tx checksumming: %s]\n", -- 2.51.0 From 6d1a8e18dcd206964f87e9b4cf3b0296eb2aea68 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 15 Apr 2025 21:39:23 +0200 Subject: [PATCH 130/517] r8169: add RTL_GIGA_MAC_VER_LAST to facilitate adding support for new chip versions Add a new mac_version enum value RTL_GIGA_MAC_VER_LAST. Benefit is that when adding support for a new chip version we have to touch less code, except something changes fundamentally. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/06991f47-2aec-4aa2-8918-2c6e79332303@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 3 ++- drivers/net/ethernet/realtek/r8169_main.c | 28 +++++++++++------------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 7a194a8ab989..9f784840ea0d 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -73,7 +73,8 @@ enum mac_version { RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, RTL_GIGA_MAC_VER_71, - RTL_GIGA_MAC_NONE + RTL_GIGA_MAC_NONE, + RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 }; struct rtl8169_private; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 140577e626bd..55fd902da0a0 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1289,7 +1289,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) case RTL_GIGA_MAC_VER_31: r8168dp_2_mdio_write(tp, location, val); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: r8168g_mdio_write(tp, location, val); break; default: @@ -1304,7 +1304,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return r8168dp_2_mdio_read(tp, location); - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: return r8168g_mdio_read(tp, location); default: return r8169_mdio_read(tp, location); @@ -1656,7 +1656,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_LAST: r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); break; default: @@ -2129,7 +2129,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) tp->tx_lpi_timer = timer_val; r8168_mac_ocp_write(tp, 0xe048, timer_val); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: tp->tx_lpi_timer = timer_val; RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); break; @@ -2491,7 +2491,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | RX_PAUSE_SLOT_ON); break; @@ -2623,7 +2623,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); break; - case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST: RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); @@ -2898,7 +2898,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: rtl_eri_set_bits(tp, 0xd4, 0x0c00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); break; default: @@ -2912,7 +2912,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: rtl_eri_clear_bits(tp, 0xd4, 0x1f00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); break; default: @@ -2950,7 +2950,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: /* reset ephy tx/rx disable timer */ r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); /* chip can trigger L1.2 */ @@ -2962,7 +2962,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } else { switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); break; default: @@ -4094,7 +4094,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST: rtl_enable_rxdvgate(tp); fsleep(2000); break; @@ -4251,7 +4251,7 @@ static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: padto = max_t(unsigned int, padto, ETH_ZLEN); break; default: @@ -5302,7 +5302,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: rtl_hw_init_8168g(tp); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: rtl_hw_init_8125(tp); break; default: @@ -5327,7 +5327,7 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_24: return JUMBO_6K; /* RTL8125/8126 */ - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST: return JUMBO_16K; default: return JUMBO_9K; -- 2.51.0 From 4e4662eb811cb1f8b8d71110751c9e3a8ba11a94 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 21 Apr 2025 11:25:18 +0200 Subject: [PATCH 131/517] r8169: use pci_prepare_to_sleep in rtl_shutdown Use pci_prepare_to_sleep() like PCI core does in pci_pm_suspend_noirq. This aligns setting a low-power mode during shutdown with the handling of the transition to system suspend. Also the transition to runtime suspend uses pci_target_state() instead of setting D3hot unconditionally. Note: pci_prepare_to_sleep() uses device_may_wakeup() to check whether device may generate wakeup events. So we don't lose anything by not passing tp->saved_wolopts any longer. Signed-off-by: Heiner Kallweit Reviewed-by: Jacob Keller Link: https://patch.msgid.link/f573fdbd-ba6d-41c1-b68f-311d3c88db2c@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 55fd902da0a0..6e353efd342f 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5040,10 +5040,8 @@ static void rtl_shutdown(struct pci_dev *pdev) /* Restore original MAC address */ rtl_rar_set(tp, tp->dev->perm_addr); - if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) { - pci_wake_from_d3(pdev, tp->saved_wolopts); - pci_set_power_state(pdev, PCI_D3hot); - } + if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) + pci_prepare_to_sleep(pdev); } static void rtl_remove_one(struct pci_dev *pdev) -- 2.51.0 From 871a69f8e15d5804a59dca57da8ede9740f16d3f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 18 Apr 2025 11:23:45 +0200 Subject: [PATCH 132/517] r8169: merge chip versions 70 and 71 (RTL8126A) Handling of both chip versions is the same, only difference is the firmware. So we can merge handling of both chip versions. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/97d7ae79-d021-4b6b-b424-89e5e305b029@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 1 - drivers/net/ethernet/realtek/r8169_main.c | 15 ++++----------- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 9f784840ea0d..3f7182dc8c9e 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -72,7 +72,6 @@ enum mac_version { RTL_GIGA_MAC_VER_65, RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, - RTL_GIGA_MAC_VER_71, RTL_GIGA_MAC_NONE, RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 }; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 6e353efd342f..b7ff554ca611 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -99,7 +99,7 @@ static const struct rtl_chip_info { const char *fw_name; } rtl_chip_infos[] = { /* 8126A family. */ - { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71, "RTL8126A", FIRMWARE_8126A_3 }, + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 }, { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, /* 8125BP family. */ @@ -2939,7 +2939,6 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) rtl_mod_config5(tp, 0, ASPM_en); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: - case RTL_GIGA_MAC_VER_71: val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -2971,7 +2970,6 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: - case RTL_GIGA_MAC_VER_71: val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -3691,12 +3689,10 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_70 || - tp->mac_version == RTL_GIGA_MAC_VER_71) + if (tp->mac_version == RTL_GIGA_MAC_VER_70) RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); - if (tp->mac_version == RTL_GIGA_MAC_VER_70 || - tp->mac_version == RTL_GIGA_MAC_VER_71) + if (tp->mac_version == RTL_GIGA_MAC_VER_70) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); @@ -3714,8 +3710,7 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); - if (tp->mac_version == RTL_GIGA_MAC_VER_70 || - tp->mac_version == RTL_GIGA_MAC_VER_71) + if (tp->mac_version == RTL_GIGA_MAC_VER_70) r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); else r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); @@ -3838,7 +3833,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, - [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, }; if (hw_configs[tp->mac_version]) @@ -3862,7 +3856,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) break; case RTL_GIGA_MAC_VER_63: case RTL_GIGA_MAC_VER_70: - case RTL_GIGA_MAC_VER_71: for (i = 0xa00; i < 0xa80; i += 4) RTL_W32(tp, i, 0); RTL_W16(tp, INT_CFG1_8125, 0x0000); diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 748ca8b212ba..7f513086ba96 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1183,7 +1183,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, - [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, }; if (phy_configs[ver]) -- 2.51.0 From 26be2181b358372db7fb62af9e69d9f4fb70d0b0 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 18 Apr 2025 11:24:30 +0200 Subject: [PATCH 133/517] r8169: merge chip versions 64 and 65 (RTL8125D) Handling of both chip versions is the same, only difference is the firmware. So we can merge handling of both chip versions. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/0baad123-c679-4154-923f-fdc12783e900@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 1 - drivers/net/ethernet/realtek/r8169_main.c | 4 +--- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 3f7182dc8c9e..1878c44ece91 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -69,7 +69,6 @@ enum mac_version { RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, RTL_GIGA_MAC_VER_64, - RTL_GIGA_MAC_VER_65, RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, RTL_GIGA_MAC_NONE, diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index b7ff554ca611..0c5afbc8f5fe 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -106,7 +106,7 @@ static const struct rtl_chip_info { { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66, "RTL8125BP", FIRMWARE_8125BP_2 }, /* 8125D family. */ - { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65, "RTL8125D", FIRMWARE_8125D_2 }, + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_2 }, { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64, "RTL8125D", FIRMWARE_8125D_1 }, /* 8125B family. */ @@ -3830,7 +3830,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, - [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, }; @@ -3849,7 +3848,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_64: - case RTL_GIGA_MAC_VER_65: case RTL_GIGA_MAC_VER_66: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 7f513086ba96..e3adfafa2b1b 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1180,7 +1180,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, - [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, }; -- 2.51.0 From 6d604938ecae971d603aeae185c08c65492c24e4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 18 Apr 2025 11:25:17 +0200 Subject: [PATCH 134/517] r8169: merge chip versions 52 and 53 (RTL8117) Handling of both chip versions is the same, only difference is the firmware. So we can merge handling of both chip versions. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/ae866b71-c904-434e-befb-848c831e33ff@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 1 - drivers/net/ethernet/realtek/r8169_main.c | 17 +++++++---------- drivers/net/ethernet/realtek/r8169_phy_config.c | 1 - 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 1878c44ece91..f05231030925 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -64,7 +64,6 @@ enum mac_version { /* support for RTL_GIGA_MAC_VER_50 has been removed */ RTL_GIGA_MAC_VER_51, RTL_GIGA_MAC_VER_52, - RTL_GIGA_MAC_VER_53, /* support for RTL_GIGA_MAC_VER_60 has been removed */ RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 0c5afbc8f5fe..1af644a62968 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -116,7 +116,7 @@ static const struct rtl_chip_info { { 0x7cf, 0x609, RTL_GIGA_MAC_VER_61, "RTL8125A", FIRMWARE_8125A_3 }, /* RTL8117 */ - { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_53, "RTL8168fp/RTL8117" }, + { 0x7cf, 0x54b, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117" }, { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52, "RTL8168fp/RTL8117", FIRMWARE_8168FP_3 }, @@ -830,7 +830,7 @@ static bool rtl_is_8168evl_up(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_34 && tp->mac_version != RTL_GIGA_MAC_VER_39 && - tp->mac_version <= RTL_GIGA_MAC_VER_53; + tp->mac_version <= RTL_GIGA_MAC_VER_52; } static bool rtl_supports_eee(struct rtl8169_private *tp) @@ -998,9 +998,7 @@ void r8169_get_led_name(struct rtl8169_private *tp, int idx, static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type) { /* based on RTL8168FP_OOBMAC_BASE in vendor driver */ - if (type == ERIAR_OOB && - (tp->mac_version == RTL_GIGA_MAC_VER_52 || - tp->mac_version == RTL_GIGA_MAC_VER_53)) + if (type == ERIAR_OOB && tp->mac_version == RTL_GIGA_MAC_VER_52) *cmd |= 0xf70 << 18; } @@ -1500,7 +1498,7 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return RTL_DASH_DP; - case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: + case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52: return RTL_DASH_EP; case RTL_GIGA_MAC_VER_66: return RTL_DASH_25_BP; @@ -2485,7 +2483,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_38: RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); break; case RTL_GIGA_MAC_VER_61: @@ -2616,7 +2614,7 @@ DECLARE_RTL_COND(rtl_rxtx_empty_cond_2) static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) { switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); break; @@ -3826,7 +3824,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_48] = rtl_hw_start_8168h_1, [RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3, [RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117, - [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, @@ -5285,7 +5282,7 @@ static void rtl_hw_init_8125(struct rtl8169_private *tp) static void rtl_hw_initialize(struct rtl8169_private *tp) { switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: + case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_52: rtl8168ep_stop_cmac(tp); fallthrough; case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index e3adfafa2b1b..5403f8202c79 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1176,7 +1176,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_48] = rtl8168h_2_hw_phy_config, [RTL_GIGA_MAC_VER_51] = rtl8168ep_2_hw_phy_config, [RTL_GIGA_MAC_VER_52] = rtl8117_hw_phy_config, - [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, -- 2.51.0 From c3fdac7c0b9944f77753c0293f813b86ea29a0e4 Mon Sep 17 00:00:00 2001 From: ChunHao Lin Date: Thu, 15 May 2025 17:53:03 +0800 Subject: [PATCH 135/517] r8169: add support for RTL8127A This adds support for 10Gbs chip RTL8127A. Signed-off-by: ChunHao Lin Reviewed-by: Heiner Kallweit Link: https://patch.msgid.link/20250515095303.3138-1-hau@realtek.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169.h | 1 + drivers/net/ethernet/realtek/r8169_main.c | 29 ++- .../net/ethernet/realtek/r8169_phy_config.c | 166 ++++++++++++++++++ 3 files changed, 193 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index f05231030925..2c1a0c21af8d 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -70,6 +70,7 @@ enum mac_version { RTL_GIGA_MAC_VER_64, RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_80, RTL_GIGA_MAC_NONE, RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 }; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 1af644a62968..c16741eec0bd 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -60,6 +60,7 @@ #define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" +#define FIRMWARE_8127A_1 "rtl_nic/rtl8127a-1.fw" #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -98,6 +99,9 @@ static const struct rtl_chip_info { const char *name; const char *fw_name; } rtl_chip_infos[] = { + /* 8127A family. */ + { 0x7cf, 0x6c9, RTL_GIGA_MAC_VER_80, "RTL8127A", FIRMWARE_8127A_1 }, + /* 8126A family. */ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 }, { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, @@ -222,8 +226,10 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, { PCI_VDEVICE(REALTEK, 0x8125) }, { PCI_VDEVICE(REALTEK, 0x8126) }, + { PCI_VDEVICE(REALTEK, 0x8127) }, { PCI_VDEVICE(REALTEK, 0x3000) }, { PCI_VDEVICE(REALTEK, 0x5000) }, + { PCI_VDEVICE(REALTEK, 0x0e10) }, {} }; @@ -769,6 +775,7 @@ MODULE_FIRMWARE(FIRMWARE_8125D_2); MODULE_FIRMWARE(FIRMWARE_8125BP_2); MODULE_FIRMWARE(FIRMWARE_8126A_2); MODULE_FIRMWARE(FIRMWARE_8126A_3); +MODULE_FIRMWARE(FIRMWARE_8127A_1); static inline struct device *tp_to_dev(struct rtl8169_private *tp) { @@ -2937,6 +2944,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) rtl_mod_config5(tp, 0, ASPM_en); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_80: val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -2968,6 +2976,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_80: val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -3687,10 +3696,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_80) RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_80) + r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00); + else if (tp->mac_version == RTL_GIGA_MAC_VER_70) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); @@ -3708,7 +3720,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_80) r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); else r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); @@ -3786,6 +3799,12 @@ static void rtl_hw_start_8126a(struct rtl8169_private *tp) rtl_hw_start_8125_common(tp); } +static void rtl_hw_start_8127a(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + static void rtl_hw_config(struct rtl8169_private *tp) { static const rtl_generic_fct hw_configs[] = { @@ -3829,6 +3848,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_80] = rtl_hw_start_8127a, }; if (hw_configs[tp->mac_version]) @@ -3846,8 +3866,11 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_64: case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_80: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); + if (tp->mac_version == RTL_GIGA_MAC_VER_80) + RTL_W16(tp, INT_CFG1_8125, 0x0000); break; case RTL_GIGA_MAC_VER_63: case RTL_GIGA_MAC_VER_70: diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 5403f8202c79..032d9d2cfa2a 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1130,6 +1130,171 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, rtl8125_common_config_eee_phy(phydev); } +static void rtl8127a_1_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + + r8168g_phy_param(phydev, 0x8415, 0xff00, 0x9300); + r8168g_phy_param(phydev, 0x81a3, 0xff00, 0x0f00); + r8168g_phy_param(phydev, 0x81ae, 0xff00, 0x0f00); + r8168g_phy_param(phydev, 0x81b9, 0xff00, 0xb900); + rtl8125_phy_param(phydev, 0x83b0, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83C5, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83da, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83ef, 0x0e00, 0x0000); + phy_modify_paged(phydev, 0x0bf3, 0x14, 0x01f0, 0x0160); + phy_modify_paged(phydev, 0x0bf3, 0x15, 0x001f, 0x0014); + phy_modify_paged(phydev, 0x0bf2, 0x14, 0x6000, 0x0000); + phy_modify_paged(phydev, 0x0bf2, 0x16, 0xc000, 0x0000); + phy_modify_paged(phydev, 0x0bf2, 0x14, 0x1fff, 0x0187); + phy_modify_paged(phydev, 0x0bf2, 0x15, 0x003f, 0x0003); + + r8168g_phy_param(phydev, 0x8173, 0xffff, 0x8620); + r8168g_phy_param(phydev, 0x8175, 0xffff, 0x8671); + r8168g_phy_param(phydev, 0x817c, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x8187, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x8192, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x819d, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x81a8, 0x2000, 0x0000); + r8168g_phy_param(phydev, 0x81b3, 0x2000, 0x0000); + r8168g_phy_param(phydev, 0x81be, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x817d, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x8188, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x8193, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x819e, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x81a9, 0xff00, 0x1400); + r8168g_phy_param(phydev, 0x81b4, 0xff00, 0x1400); + r8168g_phy_param(phydev, 0x81bf, 0xff00, 0xa600); + + phy_modify_paged(phydev, 0x0aea, 0x15, 0x0028, 0x0000); + + rtl8125_phy_param(phydev, 0x84f0, 0xffff, 0x201c); + rtl8125_phy_param(phydev, 0x84f2, 0xffff, 0x3117); + + phy_write_paged(phydev, 0x0aec, 0x13, 0x0000); + phy_write_paged(phydev, 0x0ae2, 0x10, 0xffff); + phy_write_paged(phydev, 0x0aec, 0x17, 0xffff); + phy_write_paged(phydev, 0x0aed, 0x11, 0xffff); + phy_write_paged(phydev, 0x0aec, 0x14, 0x0000); + phy_modify_paged(phydev, 0x0aed, 0x10, 0x0001, 0x0000); + phy_write_paged(phydev, 0x0adb, 0x14, 0x0150); + rtl8125_phy_param(phydev, 0x8197, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x8231, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x82cb, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x82cd, 0xff00, 0x5700); + rtl8125_phy_param(phydev, 0x8233, 0xff00, 0x5700); + rtl8125_phy_param(phydev, 0x8199, 0xff00, 0x5700); + + rtl8125_phy_param(phydev, 0x815a, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x81f4, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x828e, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x81b1, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x824b, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x82e5, 0xffff, 0x0000); + + rtl8125_phy_param(phydev, 0x84f7, 0xff00, 0x2800); + phy_modify_paged(phydev, 0x0aec, 0x11, 0x0000, 0x1000); + rtl8125_phy_param(phydev, 0x81b3, 0xff00, 0xad00); + rtl8125_phy_param(phydev, 0x824d, 0xff00, 0xad00); + rtl8125_phy_param(phydev, 0x82e7, 0xff00, 0xad00); + phy_modify_paged(phydev, 0x0ae4, 0x17, 0x000f, 0x0001); + rtl8125_phy_param(phydev, 0x82ce, 0xf000, 0x4000); + + rtl8125_phy_param(phydev, 0x84ac, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x84ae, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x84b0, 0xffff, 0xf818); + rtl8125_phy_param(phydev, 0x84b2, 0xff00, 0x6000); + + rtl8125_phy_param(phydev, 0x8ffc, 0xffff, 0x6008); + rtl8125_phy_param(phydev, 0x8ffe, 0xffff, 0xf450); + + rtl8125_phy_param(phydev, 0x8015, 0x0000, 0x0200); + rtl8125_phy_param(phydev, 0x8016, 0x0800, 0x0000); + rtl8125_phy_param(phydev, 0x8fe6, 0xff00, 0x0800); + rtl8125_phy_param(phydev, 0x8fe4, 0xffff, 0x2114); + + rtl8125_phy_param(phydev, 0x8647, 0xffff, 0xa7b1); + rtl8125_phy_param(phydev, 0x8649, 0xffff, 0xbbca); + rtl8125_phy_param(phydev, 0x864b, 0xff00, 0xdc00); + + rtl8125_phy_param(phydev, 0x8154, 0xc000, 0x4000); + rtl8125_phy_param(phydev, 0x8158, 0xc000, 0x0000); + + rtl8125_phy_param(phydev, 0x826c, 0xffff, 0xffff); + rtl8125_phy_param(phydev, 0x826e, 0xffff, 0xffff); + + rtl8125_phy_param(phydev, 0x8872, 0xff00, 0x0e00); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x0800); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x4000); + phy_modify_paged(phydev, 0x0b57, 0x13, 0x0000, 0x0001); + r8168g_phy_param(phydev, 0x834a, 0xff00, 0x0700); + rtl8125_phy_param(phydev, 0x8217, 0x3f00, 0x2a00); + r8168g_phy_param(phydev, 0x81b1, 0xff00, 0x0b00); + rtl8125_phy_param(phydev, 0x8fed, 0xff00, 0x4e00); + + rtl8125_phy_param(phydev, 0x88ac, 0xff00, 0x2300); + phy_modify_paged(phydev, 0x0bf0, 0x16, 0x0000, 0x3800); + rtl8125_phy_param(phydev, 0x88de, 0xff00, 0x0000); + rtl8125_phy_param(phydev, 0x80b4, 0xffff, 0x5195); + + r8168g_phy_param(phydev, 0x8370, 0xffff, 0x8671); + r8168g_phy_param(phydev, 0x8372, 0xffff, 0x86c8); + + r8168g_phy_param(phydev, 0x8401, 0xffff, 0x86c8); + r8168g_phy_param(phydev, 0x8403, 0xffff, 0x86da); + r8168g_phy_param(phydev, 0x8406, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8408, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840a, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840c, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840e, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8410, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8412, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8414, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8416, 0x1800, 0x1000); + + r8168g_phy_param(phydev, 0x82bd, 0xffff, 0x1f40); + + phy_modify_paged(phydev, 0x0bfb, 0x12, 0x07ff, 0x0328); + phy_write_paged(phydev, 0x0bfb, 0x13, 0x3e14); + + r8168g_phy_param(phydev, 0x81c4, 0xffff, 0x003b); + r8168g_phy_param(phydev, 0x81c6, 0xffff, 0x0086); + r8168g_phy_param(phydev, 0x81c8, 0xffff, 0x00b7); + r8168g_phy_param(phydev, 0x81ca, 0xffff, 0x00db); + r8168g_phy_param(phydev, 0x81cc, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81ce, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d0, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d2, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d4, 0xffff, 0x00c3); + r8168g_phy_param(phydev, 0x81d6, 0xffff, 0x0078); + r8168g_phy_param(phydev, 0x81d8, 0xffff, 0x0047); + r8168g_phy_param(phydev, 0x81da, 0xffff, 0x0023); + + rtl8125_phy_param(phydev, 0x88d7, 0xffff, 0x01a0); + rtl8125_phy_param(phydev, 0x88d9, 0xffff, 0x01a0); + rtl8125_phy_param(phydev, 0x8ffa, 0xffff, 0x002a); + + rtl8125_phy_param(phydev, 0x8fee, 0xffff, 0xffdf); + rtl8125_phy_param(phydev, 0x8ff0, 0xffff, 0xffff); + rtl8125_phy_param(phydev, 0x8ff2, 0xffff, 0x0a4a); + rtl8125_phy_param(phydev, 0x8ff4, 0xffff, 0xaa5a); + rtl8125_phy_param(phydev, 0x8ff6, 0xffff, 0x0a4a); + + rtl8125_phy_param(phydev, 0x8ff8, 0xffff, 0xaa5a); + rtl8125_phy_param(phydev, 0x88d5, 0xff00, 0x0200); + + r8168g_phy_param(phydev, 0x84bb, 0xff00, 0x0a00); + r8168g_phy_param(phydev, 0x84c0, 0xff00, 0x1600); + + phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x0003); + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_common_config_eee_phy(phydev); +} + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, enum mac_version ver) { @@ -1181,6 +1346,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_80] = rtl8127a_1_hw_phy_config, }; if (phy_configs[ver]) -- 2.51.0 From 76bb2f3d8a700c0e1e0de6582d7c4469d51dbee6 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 14:07:16 +0100 Subject: [PATCH 136/517] net: phy: realtek: read duplex and gbit master from PHYSR register The PHYSR MMD register is present and defined equally for all RTL82xx Ethernet PHYs. Read duplex and Gbit master bits from rtlgen_decode_speed() and rename it to rtlgen_decode_physr(). Signed-off-by: Daniel Golle Link: https://patch.msgid.link/b9a76341da851a18c985bc4774fa295babec79bb.1728565530.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek.c | 41 +++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 8ce5705af69c..f620cd7b17c8 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -80,15 +80,18 @@ #define RTL822X_VND2_GANLPAR 0xa414 -#define RTL822X_VND2_PHYSR 0xa434 - #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) #define RTL9000A_GINMR 0x14 #define RTL9000A_GINMR_LINK_STATUS BIT(4) -#define RTLGEN_SPEED_MASK 0x0630 +#define RTL_VND2_PHYSR 0xa434 +#define RTL_VND2_PHYSR_DUPLEX BIT(3) +#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) +#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) +#define RTL_VND2_PHYSR_MASTER BIT(11) +#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) #define RTL_GENERIC_PHYID 0x001cc800 #define RTL_8211FVD_PHYID 0x001cc878 @@ -661,9 +664,18 @@ static int rtl8366rb_config_init(struct phy_device *phydev) } /* get actual speed to cover the downshift case */ -static void rtlgen_decode_speed(struct phy_device *phydev, int val) +static void rtlgen_decode_physr(struct phy_device *phydev, int val) { - switch (val & RTLGEN_SPEED_MASK) { + /* bit 3 + * 0: Half Duplex + * 1: Full Duplex + */ + if (val & RTL_VND2_PHYSR_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + switch (val & RTL_VND2_PHYSR_SPEED_MASK) { case 0x0000: phydev->speed = SPEED_10; break; @@ -685,6 +697,19 @@ static void rtlgen_decode_speed(struct phy_device *phydev, int val) default: break; } + + /* bit 11 + * 0: Slave Mode + * 1: Master Mode + */ + if (phydev->speed >= 1000) { + if (val & RTL_VND2_PHYSR_MASTER) + phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; + else + phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; + } else { + phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; + } } static int rtlgen_read_status(struct phy_device *phydev) @@ -702,7 +727,7 @@ static int rtlgen_read_status(struct phy_device *phydev) if (val < 0) return val; - rtlgen_decode_speed(phydev, val); + rtlgen_decode_physr(phydev, val); return 0; } @@ -1008,11 +1033,11 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) return 0; /* Read actual speed from vendor register. */ - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); if (val < 0) return val; - rtlgen_decode_speed(phydev, val); + rtlgen_decode_physr(phydev, val); return 0; } -- 2.51.0 From 8044888966fcc83cca44c0ed9d74bfbc9b342d31 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 14:07:26 +0100 Subject: [PATCH 137/517] net: phy: realtek: change order of calls in C22 read_status() Always call rtlgen_read_status() first, so genphy_read_status() which is called by it clears bits in case auto-negotiation has not completed. Also clear 10GBT link-partner advertisement bits in case auto-negotiation is disabled or has not completed. Suggested-by: Russell King (Oracle) Signed-off-by: Daniel Golle Link: https://patch.msgid.link/b15929a41621d215c6b2b57393368086589569ec.1728565530.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index f620cd7b17c8..c724ab0c4501 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -950,17 +950,25 @@ static void rtl822xb_update_interface(struct phy_device *phydev) static int rtl822x_read_status(struct phy_device *phydev) { - if (phydev->autoneg == AUTONEG_ENABLE) { - int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + int lpadv, ret; - if (lpadv < 0) - return lpadv; + ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; - mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, - lpadv); + if (phydev->autoneg == AUTONEG_DISABLE || + !phydev->autoneg_complete) { + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + return 0; } - return rtlgen_read_status(phydev); + lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + if (lpadv < 0) + return lpadv; + + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); + + return 0; } static int rtl822xb_read_status(struct phy_device *phydev) -- 2.51.0 From 12f9b03a9a0219fb6995129ff24d18858903e949 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 10 Oct 2024 14:07:39 +0100 Subject: [PATCH 138/517] net: phy: realtek: clear 1000Base-T link partner advertisement Clear 1000Base-T link partner advertisement bits in Clause-45 read_status() function in case auto-negotiation is disabled or has not been completed. Signed-off-by: Daniel Golle Link: https://patch.msgid.link/9dc9b47b2d675708afef3ad366bfd78eb584d958.1728565530.git.daniel@makrotopia.org Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index c724ab0c4501..f65d7f1f348e 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -1027,6 +1027,10 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) if (ret < 0) return ret; + if (phydev->autoneg == AUTONEG_DISABLE || + !genphy_c45_aneg_done(phydev)) + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + /* Vendor register as C45 has no standardized support for 1000BaseT */ if (phydev->autoneg == AUTONEG_ENABLE) { val = phy_read_mmd(phydev, MDIO_MMD_VEND2, -- 2.51.0 From af5aaa6a8e593cc32687a2d570336c20a446b23a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 11 Jan 2025 21:49:31 +0100 Subject: [PATCH 139/517] net: phy: realtek: add support for reading MDIO_MMD_VEND2 regs on RTL8125/RTL8126 RTL8125/RTL8126 don't support MMD access to the internal PHY, but provide a mechanism to access at least all MDIO_MMD_VEND2 registers. By exposing this mechanism standard MMD access functions can be used to access the MDIO_MMD_VEND2 registers. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/e821b302-5fe6-49ab-aabd-05da500581c0@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index f65d7f1f348e..af9874143f0c 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -736,7 +736,11 @@ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) { int ret; - if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { + if (devnum == MDIO_MMD_VEND2) { + rtl821x_write_page(phydev, regnum >> 4); + ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); + rtl821x_write_page(phydev, 0); + } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { rtl821x_write_page(phydev, 0xa5c); ret = __phy_read(phydev, 0x12); rtl821x_write_page(phydev, 0); @@ -760,7 +764,11 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, { int ret; - if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { + if (devnum == MDIO_MMD_VEND2) { + rtl821x_write_page(phydev, regnum >> 4); + ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); + rtl821x_write_page(phydev, 0); + } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { rtl821x_write_page(phydev, 0xa5d); ret = __phy_write(phydev, 0x10, val); rtl821x_write_page(phydev, 0); -- 2.51.0 From 99f16566ae0a8e2efe07c07dc3bdfa47c42563d0 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 15 Jan 2025 14:43:35 +0000 Subject: [PATCH 140/517] net: phy: realtek: clear 1000Base-T lpa if link is down Only read 1000Base-T link partner advertisement if autonegotiation has completed and otherwise 1000Base-T link partner advertisement bits. This fixes bogus 1000Base-T link partner advertisement after link goes down (eg. by disconnecting the wire). Fixes: 5cb409b3960e ("net: phy: realtek: clear 1000Base-T link partner advertisement") Signed-off-by: Daniel Golle Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index af9874143f0c..201c10f3718a 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -1031,23 +1031,20 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) { int ret, val; - ret = genphy_c45_read_status(phydev); - if (ret < 0) - return ret; - - if (phydev->autoneg == AUTONEG_DISABLE || - !genphy_c45_aneg_done(phydev)) - mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); - /* Vendor register as C45 has no standardized support for 1000BaseT */ - if (phydev->autoneg == AUTONEG_ENABLE) { + if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GANLPAR); if (val < 0) return val; - - mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); + } else { + val = 0; } + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); + + ret = genphy_c45_read_status(phydev); + if (ret < 0) + return ret; if (!phydev->link) return 0; -- 2.51.0 From 2020fe683da044996ed029f65c578d58f01b6a34 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 15 Jan 2025 14:43:43 +0000 Subject: [PATCH 141/517] net: phy: realtek: clear master_slave_state if link is down rtlgen_decode_physr() which sets master_slave_state isn't called in case the link is down and other than rtlgen_read_status(), rtl822x_c45_read_status() doesn't implicitely clear master_slave_state. Avoid stale master_slave_state by always setting it to MASTER_SLAVE_STATE_UNKNOWN in rtl822x_c45_read_status() in case the link is down. Fixes: 081c9c0265c9 ("net: phy: realtek: read duplex and gbit master from PHYSR register") Signed-off-by: Daniel Golle Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 201c10f3718a..138e608c4043 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -1046,8 +1046,10 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) if (ret < 0) return ret; - if (!phydev->link) + if (!phydev->link) { + phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN; return 0; + } /* Read actual speed from vendor register. */ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); -- 2.51.0 From cb90466e609fa150db720a90f4a79a3b1c1899a2 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 15 Jan 2025 14:45:00 +0000 Subject: [PATCH 142/517] net: phy: realtek: always clear NBase-T lpa Clear NBase-T link partner advertisement before calling rtlgen_read_status() to avoid phy_resolve_aneg_linkmode() wrongly setting speed and duplex. This fixes bogus 2.5G/5G/10G link partner advertisement and thus speed and duplex being set by phy_resolve_aneg_linkmode() due to stale NBase-T lpa. Fixes: 68d5cd09e891 ("net: phy: realtek: change order of calls in C22 read_status()") Signed-off-by: Daniel Golle Reviewed-by: Michal Swiatkowski Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 138e608c4043..44c7bdb88d76 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -960,15 +960,15 @@ static int rtl822x_read_status(struct phy_device *phydev) { int lpadv, ret; + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + ret = rtlgen_read_status(phydev); if (ret < 0) return ret; if (phydev->autoneg == AUTONEG_DISABLE || - !phydev->autoneg_complete) { - mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + !phydev->autoneg_complete) return 0; - } lpadv = phy_read_paged(phydev, 0xa5d, 0x13); if (lpadv < 0) -- 2.51.0 From 4ea28dcb44149566275d2f6ef46787057043cdb2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 11 Jan 2025 21:50:19 +0100 Subject: [PATCH 143/517] net: phy: move realtek PHY driver to its own subdirectory In preparation of adding a source file with hwmon support, move the Realtek PHY driver to its own subdirectory and rename realtek.c to realtek_main.c. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/c566551b-c915-4e34-9b33-129a6ddd6e4c@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 5 +---- drivers/net/phy/Makefile | 2 +- drivers/net/phy/realtek/Kconfig | 5 +++++ drivers/net/phy/realtek/Makefile | 3 +++ drivers/net/phy/{realtek.c => realtek/realtek_main.c} | 0 5 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 drivers/net/phy/realtek/Kconfig create mode 100644 drivers/net/phy/realtek/Makefile rename drivers/net/phy/{realtek.c => realtek/realtek_main.c} (100%) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 4e78a4d8fd2a..f7e21a2761b8 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -343,10 +343,7 @@ config QSEMI_PHY help Currently supports the qs6612 -config REALTEK_PHY - tristate "Realtek PHYs" - help - Supports the Realtek 821x PHY. +source "drivers/net/phy/realtek/Kconfig" config RENESAS_PHY tristate "Renesas PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e6145153e837..a38b01f74db7 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -94,7 +94,7 @@ obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o -obj-$(CONFIG_REALTEK_PHY) += realtek.o +obj-$(CONFIG_REALTEK_PHY) += realtek/ obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o obj-$(CONFIG_SMSC_PHY) += smsc.o diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig new file mode 100644 index 000000000000..5b9e6e6db834 --- /dev/null +++ b/drivers/net/phy/realtek/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +config REALTEK_PHY + tristate "Realtek PHYs" + help + Currently supports RTL821x/RTL822x and fast ethernet PHYs diff --git a/drivers/net/phy/realtek/Makefile b/drivers/net/phy/realtek/Makefile new file mode 100644 index 000000000000..996a80642431 --- /dev/null +++ b/drivers/net/phy/realtek/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +realtek-y += realtek_main.o +obj-$(CONFIG_REALTEK_PHY) += realtek.o diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek/realtek_main.c similarity index 100% rename from drivers/net/phy/realtek.c rename to drivers/net/phy/realtek/realtek_main.c -- 2.51.0 From 4dd3c0207f8b32828710d42d82ba2fa24497dcf4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 11 Jan 2025 21:51:24 +0100 Subject: [PATCH 144/517] net: phy: realtek: add hwmon support for temp sensor on RTL822x This adds hwmon support for the temperature sensor on RTL822x. It's available on the standalone versions of the PHY's, and on the integrated PHY's in RTL8125B/RTL8125D/RTL8126. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/ad6bfe9f-6375-4a00-84b4-bfb38a21bd71@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/Kconfig | 6 ++ drivers/net/phy/realtek/Makefile | 1 + drivers/net/phy/realtek/realtek.h | 10 ++++ drivers/net/phy/realtek/realtek_hwmon.c | 79 +++++++++++++++++++++++++ drivers/net/phy/realtek/realtek_main.c | 12 ++++ 5 files changed, 108 insertions(+) create mode 100644 drivers/net/phy/realtek/realtek.h create mode 100644 drivers/net/phy/realtek/realtek_hwmon.c diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig index 5b9e6e6db834..31935f147d87 100644 --- a/drivers/net/phy/realtek/Kconfig +++ b/drivers/net/phy/realtek/Kconfig @@ -3,3 +3,9 @@ config REALTEK_PHY tristate "Realtek PHYs" help Currently supports RTL821x/RTL822x and fast ethernet PHYs + +config REALTEK_PHY_HWMON + def_bool REALTEK_PHY && HWMON + depends on !(REALTEK_PHY=y && HWMON=m) + help + Optional hwmon support for the temperature sensor diff --git a/drivers/net/phy/realtek/Makefile b/drivers/net/phy/realtek/Makefile index 996a80642431..dd21cf87f2f1 100644 --- a/drivers/net/phy/realtek/Makefile +++ b/drivers/net/phy/realtek/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 realtek-y += realtek_main.o +realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o obj-$(CONFIG_REALTEK_PHY) += realtek.o diff --git a/drivers/net/phy/realtek/realtek.h b/drivers/net/phy/realtek/realtek.h new file mode 100644 index 000000000000..a39b44fa18a0 --- /dev/null +++ b/drivers/net/phy/realtek/realtek.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef REALTEK_H +#define REALTEK_H + +#include + +int rtl822x_hwmon_init(struct phy_device *phydev); + +#endif /* REALTEK_H */ diff --git a/drivers/net/phy/realtek/realtek_hwmon.c b/drivers/net/phy/realtek/realtek_hwmon.c new file mode 100644 index 000000000000..1ecb410bb941 --- /dev/null +++ b/drivers/net/phy/realtek/realtek_hwmon.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HWMON support for Realtek PHY's + * + * Author: Heiner Kallweit + */ + +#include +#include + +#include "realtek.h" + +#define RTL822X_VND2_TSALRM 0xa662 +#define RTL822X_VND2_TSRR 0xbd84 +#define RTL822X_VND2_TSSR 0xb54c + +static int rtl822x_hwmon_get_temp(int raw) +{ + if (raw >= 512) + raw -= 1024; + + return 1000 * raw / 2; +} + +static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + int raw; + + switch (attr) { + case hwmon_temp_input: + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; + *val = rtl822x_hwmon_get_temp(raw); + break; + case hwmon_temp_max: + /* Chip reduces speed to 1G if threshold is exceeded */ + raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; + *val = rtl822x_hwmon_get_temp(raw); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct hwmon_ops rtl822x_hwmon_ops = { + .visible = 0444, + .read = rtl822x_hwmon_read, +}; + +static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), + NULL +}; + +static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { + .ops = &rtl822x_hwmon_ops, + .info = rtl822x_hwmon_info, +}; + +int rtl822x_hwmon_init(struct phy_device *phydev) +{ + struct device *hwdev, *dev = &phydev->mdio.dev; + const char *name; + + /* Ensure over-temp alarm is reset. */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); + + name = devm_hwmon_sanitize_name(dev, dev_name(dev)); + if (IS_ERR(name)) + return PTR_ERR(name); + + hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, + &rtl822x_hwmon_chip_info, + NULL); + return PTR_ERR_OR_ZERO(hwdev); +} diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 44c7bdb88d76..1eaa66a613a1 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -14,6 +14,8 @@ #include #include +#include "realtek.h" + #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX BIT(13) #define RTL821x_PHYSR_SPEED GENMASK(15, 14) @@ -820,6 +822,15 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, return ret; } +static int rtl822x_probe(struct phy_device *phydev) +{ + if (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) && + phydev->phy_id != RTL_GENERIC_PHYID) + return rtl822x_hwmon_init(phydev); + + return 0; +} + static int rtl822xb_config_init(struct phy_device *phydev) { bool has_2500, has_sgmii; @@ -1518,6 +1529,7 @@ static struct phy_driver realtek_drvs[] = { .match_phy_device = rtl_internal_nbaset_match_phy_device, .name = "Realtek Internal NBASE-T PHY", .flags = PHY_IS_INTERNAL, + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -- 2.51.0 From 9d206755298602fa6e1ac888d793a898b6e3c27c Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Fri, 17 Jan 2025 23:24:21 +0100 Subject: [PATCH 145/517] net: phy: realtek: HWMON support for standalone versions of RTL8221B and RTL8251 HWMON support has been added for the RTL8221/8251 PHYs integrated together with the MAC inside the RTL8125/8126 chips. This patch extends temperature reading support for standalone variants of the mentioned PHYs. I don't know whether the earlier revisions of the RTL8226 also have a built-in temperature sensor, so they have been skipped for now. Tested on RTL8221B-VB-CG. Signed-off-by: Aleksander Jan Bajkowski Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/realtek/realtek_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 1eaa66a613a1..572a933636b0 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1474,6 +1474,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, @@ -1486,6 +1487,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, .get_features = rtl822x_c45_get_features, @@ -1496,6 +1498,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, @@ -1508,6 +1511,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", + .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, .get_features = rtl822x_c45_get_features, @@ -1518,6 +1522,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8251b_c45_match_phy_device, .name = "RTL8251B 5Gbps PHY", + .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, -- 2.51.0 From df5a2f57e71d7ecb6eb08c4f26f7fbc216d44c73 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 3 Feb 2025 21:33:39 +0100 Subject: [PATCH 146/517] net: phy: realtek: make HWMON support a user-visible Kconfig symbol Make config symbol REALTEK_PHY_HWMON user-visible, so that users can remove support if not needed. Suggested-by: Geert Uytterhoeven Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://patch.msgid.link/3466ee92-166a-4b0f-9ae7-42b9e046f333@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek/Kconfig b/drivers/net/phy/realtek/Kconfig index 31935f147d87..b05c2a1e9024 100644 --- a/drivers/net/phy/realtek/Kconfig +++ b/drivers/net/phy/realtek/Kconfig @@ -4,8 +4,12 @@ config REALTEK_PHY help Currently supports RTL821x/RTL822x and fast ethernet PHYs +if REALTEK_PHY + config REALTEK_PHY_HWMON - def_bool REALTEK_PHY && HWMON - depends on !(REALTEK_PHY=y && HWMON=m) + bool "HWMON support for Realtek PHYs" + depends on HWMON && !(REALTEK_PHY=y && HWMON=m) help Optional hwmon support for the temperature sensor + +endif # REALTEK_PHY -- 2.51.0 From 24028387bf45cc84b5c1eeb792b2466b8edf4564 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 3 Feb 2025 21:41:36 +0100 Subject: [PATCH 147/517] net: phy: realtek: use string choices helpers Use string choices helpers to simplify the code. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202501190707.qQS8PGHW-lkp@intel.com/ Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/phy/realtek/realtek_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 572a933636b0..210fefac44d4 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "realtek.h" @@ -422,11 +423,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) } else if (ret) { dev_dbg(dev, "%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n", - val_txdly ? "Enabling" : "Disabling"); + str_enable_disable(val_txdly)); } else { dev_dbg(dev, "2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n", - val_txdly ? "enabled" : "disabled"); + str_enabled_disabled(val_txdly)); } ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, @@ -437,11 +438,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) } else if (ret) { dev_dbg(dev, "%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n", - val_rxdly ? "Enabling" : "Disabling"); + str_enable_disable(val_rxdly)); } else { dev_dbg(dev, "2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n", - val_rxdly ? "enabled" : "disabled"); + str_enabled_disabled(val_rxdly)); } if (priv->has_phycr2) { -- 2.51.0 From c7696aeb0135b79aa1648db6b358c5ab33ffd849 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 13 Feb 2025 20:18:17 +0100 Subject: [PATCH 148/517] net: phy: realtek: improve mmd register access for internal PHY's r8169 provides the MDIO bus for the internal PHY's. It has been extended with c45 access functions for addressing MDIO_MMD_VEND2 registers. So we can switch from paged access to directly addressing the MDIO_MMD_VEND2 registers. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/a5f2333c-dda9-48ad-9801-77049766e632@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 79 +++++++++++--------------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 210fefac44d4..2e2c5353c5af 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -735,29 +735,31 @@ static int rtlgen_read_status(struct phy_device *phydev) return 0; } +static int rtlgen_read_vend2(struct phy_device *phydev, int regnum) +{ + return __mdiobus_c45_read(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum); +} + +static int rtlgen_write_vend2(struct phy_device *phydev, int regnum, u16 val) +{ + return __mdiobus_c45_write(phydev->mdio.bus, 0, MDIO_MMD_VEND2, regnum, + val); +} + static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) { int ret; - if (devnum == MDIO_MMD_VEND2) { - rtl821x_write_page(phydev, regnum >> 4); - ret = __phy_read(phydev, 0x10 + ((regnum & 0xf) >> 1)); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) { - rtl821x_write_page(phydev, 0xa5c); - ret = __phy_read(phydev, 0x12); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { - rtl821x_write_page(phydev, 0xa5d); - ret = __phy_read(phydev, 0x10); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) { - rtl821x_write_page(phydev, 0xa5d); - ret = __phy_read(phydev, 0x11); - rtl821x_write_page(phydev, 0); - } else { + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_read_vend2(phydev, regnum); + else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) + ret = rtlgen_read_vend2(phydev, 0xa5c4); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) + ret = rtlgen_read_vend2(phydev, 0xa5d0); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) + ret = rtlgen_read_vend2(phydev, 0xa5d2); + else ret = -EOPNOTSUPP; - } return ret; } @@ -767,17 +769,12 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, { int ret; - if (devnum == MDIO_MMD_VEND2) { - rtl821x_write_page(phydev, regnum >> 4); - ret = __phy_write(phydev, 0x10 + ((regnum & 0xf) >> 1), val); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) { - rtl821x_write_page(phydev, 0xa5d); - ret = __phy_write(phydev, 0x10, val); - rtl821x_write_page(phydev, 0); - } else { + if (devnum == MDIO_MMD_VEND2) + ret = rtlgen_write_vend2(phydev, regnum, val); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) + ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); + else ret = -EOPNOTSUPP; - } return ret; } @@ -789,19 +786,12 @@ static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) if (ret != -EOPNOTSUPP) return ret; - if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) { - rtl821x_write_page(phydev, 0xa6e); - ret = __phy_read(phydev, 0x16); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { - rtl821x_write_page(phydev, 0xa6d); - ret = __phy_read(phydev, 0x12); - rtl821x_write_page(phydev, 0); - } else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) { - rtl821x_write_page(phydev, 0xa6d); - ret = __phy_read(phydev, 0x10); - rtl821x_write_page(phydev, 0); - } + if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) + ret = rtlgen_read_vend2(phydev, 0xa6ec); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) + ret = rtlgen_read_vend2(phydev, 0xa6d4); + else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) + ret = rtlgen_read_vend2(phydev, 0xa6d0); return ret; } @@ -814,11 +804,8 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, if (ret != -EOPNOTSUPP) return ret; - if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) { - rtl821x_write_page(phydev, 0xa6d); - ret = __phy_write(phydev, 0x12, val); - rtl821x_write_page(phydev, 0); - } + if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) + ret = rtlgen_write_vend2(phydev, 0xa6d4, val); return ret; } -- 2.51.0 From 0a937df4d8245909b4d8777209ee0dfb07340350 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 13 Feb 2025 20:19:14 +0100 Subject: [PATCH 149/517] net: phy: realtek: switch from paged to MMD ops in rtl822x functions The MDIO bus provided by r8169 for the internal PHY's now supports c45 ops for the MDIO_MMD_VEND2 device. So we can switch to standard MMD ops here. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/81416f95-0fac-4225-87b4-828e3738b8ed@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 2e2c5353c5af..34be1d752ef8 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -901,7 +901,7 @@ static int rtl822x_get_features(struct phy_device *phydev) { int val; - val = phy_read_paged(phydev, 0xa61, 0x13); + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); if (val < 0) return val; @@ -922,10 +922,9 @@ static int rtl822x_config_aneg(struct phy_device *phydev) if (phydev->autoneg == AUTONEG_ENABLE) { u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); - ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, - MDIO_AN_10GBT_CTRL_ADV2_5G | - MDIO_AN_10GBT_CTRL_ADV5G, - adv); + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, + MDIO_AN_10GBT_CTRL_ADV2_5G | + MDIO_AN_10GBT_CTRL_ADV5G, adv); if (ret < 0) return ret; } @@ -969,7 +968,7 @@ static int rtl822x_read_status(struct phy_device *phydev) !phydev->autoneg_complete) return 0; - lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); if (lpadv < 0) return lpadv; -- 2.51.0 From a30ba9540ea58da2d711e0ec47a05fdabcdf04fe Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 14 Feb 2025 21:31:14 +0100 Subject: [PATCH 150/517] net: phy: realtek: add helper RTL822X_VND2_C22_REG C22 register space is mapped to 0xa400 in MMD VEND2 register space. Add a helper to access mapped C22 registers. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/6344277b-c5c7-449b-ac89-d5425306ca76@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 34be1d752ef8..b877057348d5 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -79,9 +79,7 @@ /* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45 * is set, they cannot be accessed by C45-over-C22. */ -#define RTL822X_VND2_GBCR 0xa412 - -#define RTL822X_VND2_GANLPAR 0xa414 +#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) @@ -1015,7 +1013,8 @@ static int rtl822x_c45_config_aneg(struct phy_device *phydev) val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); /* Vendor register as C45 has no standardized support for 1000BaseT */ - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR, + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, + RTL822X_VND2_C22_REG(MII_CTRL1000), ADVERTISE_1000FULL, val); if (ret < 0) return ret; @@ -1032,7 +1031,7 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) /* Vendor register as C45 has no standardized support for 1000BaseT */ if (phydev->autoneg == AUTONEG_ENABLE && genphy_c45_aneg_done(phydev)) { val = phy_read_mmd(phydev, MDIO_MMD_VEND2, - RTL822X_VND2_GANLPAR); + RTL822X_VND2_C22_REG(MII_STAT1000)); if (val < 0) return val; } else { -- 2.51.0 From 10dc716faf022f4c1e733b7cc7730effb0387309 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 15 Feb 2025 14:29:15 +0100 Subject: [PATCH 151/517] net: phy: realtek: add defines for shadowed c45 standard registers Realtek shadows standard c45 registers in VEND2 device register space. Add defines for these VEND2 registers, based on the names of the standard c45 registers. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/c90bdf76-f8b8-4d06-9656-7a52d5658ee6@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 33 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index b877057348d5..7a0b19d66aca 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -94,6 +94,16 @@ #define RTL_VND2_PHYSR_MASTER BIT(11) #define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) +#define RTL_MDIO_PCS_EEE_ABLE 0xa5c4 +#define RTL_MDIO_AN_EEE_ADV 0xa5d0 +#define RTL_MDIO_AN_EEE_LPABLE 0xa5d2 +#define RTL_MDIO_AN_10GBT_CTRL 0xa5d4 +#define RTL_MDIO_AN_10GBT_STAT 0xa5d6 +#define RTL_MDIO_PMA_SPEED 0xa616 +#define RTL_MDIO_AN_EEE_LPABLE2 0xa6d0 +#define RTL_MDIO_AN_EEE_ADV2 0xa6d4 +#define RTL_MDIO_PCS_EEE_ABLE2 0xa6ec + #define RTL_GENERIC_PHYID 0x001cc800 #define RTL_8211FVD_PHYID 0x001cc878 #define RTL_8221B 0x001cc840 @@ -751,11 +761,11 @@ static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) if (devnum == MDIO_MMD_VEND2) ret = rtlgen_read_vend2(phydev, regnum); else if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) - ret = rtlgen_read_vend2(phydev, 0xa5c4); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE); else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) - ret = rtlgen_read_vend2(phydev, 0xa5d0); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV); else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) - ret = rtlgen_read_vend2(phydev, 0xa5d2); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE); else ret = -EOPNOTSUPP; @@ -770,7 +780,7 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, if (devnum == MDIO_MMD_VEND2) ret = rtlgen_write_vend2(phydev, regnum, val); else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) - ret = rtlgen_write_vend2(phydev, regnum, 0xa5d0); + ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV); else ret = -EOPNOTSUPP; @@ -785,11 +795,11 @@ static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) return ret; if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) - ret = rtlgen_read_vend2(phydev, 0xa6ec); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_PCS_EEE_ABLE2); else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) - ret = rtlgen_read_vend2(phydev, 0xa6d4); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_ADV2); else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) - ret = rtlgen_read_vend2(phydev, 0xa6d0); + ret = rtlgen_read_vend2(phydev, RTL_MDIO_AN_EEE_LPABLE2); return ret; } @@ -803,7 +813,7 @@ static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, return ret; if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) - ret = rtlgen_write_vend2(phydev, 0xa6d4, val); + ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV2, val); return ret; } @@ -899,7 +909,7 @@ static int rtl822x_get_features(struct phy_device *phydev) { int val; - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa616); + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_PMA_SPEED); if (val < 0) return val; @@ -920,7 +930,8 @@ static int rtl822x_config_aneg(struct phy_device *phydev) if (phydev->autoneg == AUTONEG_ENABLE) { u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising); - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, 0xa5d4, + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, + RTL_MDIO_AN_10GBT_CTRL, MDIO_AN_10GBT_CTRL_ADV2_5G | MDIO_AN_10GBT_CTRL_ADV5G, adv); if (ret < 0) @@ -966,7 +977,7 @@ static int rtl822x_read_status(struct phy_device *phydev) !phydev->autoneg_complete) return 0; - lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa5d6); + lpadv = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_STAT); if (lpadv < 0) return lpadv; -- 2.51.0 From 0f352608b9659c2a38aaae383a9dfb7198c92550 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sun, 16 Mar 2025 12:39:54 +0000 Subject: [PATCH 152/517] net: phy: realtek: disable PHY-mode EEE Realtek RTL8211F has a "PHY-mode" EEE support which interferes with an IEEE 802.3 compliant implementation. This mode defaults to enabled, and results in the MAC receive path not seeing the link transition to LPI state. Fix this by disabling PHY-mode EEE. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/E1ttnHW-00785s-Uq@rmk-PC.armlinux.org.uk Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 7a0b19d66aca..893c82479671 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -33,6 +33,9 @@ #define RTL8211F_PHYCR1 0x18 #define RTL8211F_PHYCR2 0x19 +#define RTL8211F_CLKOUT_EN BIT(0) +#define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) + #define RTL8211F_INSR 0x1d #define RTL8211F_LEDCR 0x10 @@ -55,8 +58,6 @@ #define RTL8211E_TX_DELAY BIT(12) #define RTL8211E_RX_DELAY BIT(11) -#define RTL8211F_CLKOUT_EN BIT(0) - #define RTL8201F_ISR 0x1e #define RTL8201F_ISR_ANERR BIT(15) #define RTL8201F_ISR_DUPLEX BIT(13) @@ -453,6 +454,12 @@ static int rtl8211f_config_init(struct phy_device *phydev) str_enabled_disabled(val_rxdly)); } + /* Disable PHY-mode EEE so LPI is passed to the MAC */ + ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, + RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); + if (ret) + return ret; + if (priv->has_phycr2) { ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, priv->phycr2); -- 2.51.0 From 94a3d70ce477f33f92c9a49223563adc2382a80b Mon Sep 17 00:00:00 2001 From: Daniel Braunwarth Date: Tue, 29 Apr 2025 13:33:37 +0200 Subject: [PATCH 153/517] net: phy: realtek: Add support for WOL magic packet on RTL8211F The RTL8211F supports multiple WOL modes. This patch adds support for magic packets. The PHY notifies the system via the INTB/PMEB pin when a WOL event occurs. Signed-off-by: Daniel Braunwarth Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250429-realtek_wol-v2-1-8f84def1ef2c@kuka.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 893c82479671..05c4f4d394a5 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,24 @@ #define RTL8211F_INSR 0x1d +/* RTL8211F WOL interrupt configuration */ +#define RTL8211F_INTBCR_PAGE 0xd40 +#define RTL8211F_INTBCR 0x16 +#define RTL8211F_INTBCR_INTB_PMEB BIT(5) + +/* RTL8211F WOL settings */ +#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a +#define RTL8211F_WOL_SETTINGS_EVENTS 16 +#define RTL8211F_WOL_EVENT_MAGIC BIT(12) +#define RTL8211F_WOL_SETTINGS_STATUS 17 +#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) + +/* RTL8211F Unique phyiscal and multicast address (WOL) */ +#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c +#define RTL8211F_PHYSICAL_ADDR_WORD0 16 +#define RTL8211F_PHYSICAL_ADDR_WORD1 17 +#define RTL8211F_PHYSICAL_ADDR_WORD2 18 + #define RTL8211F_LEDCR 0x10 #define RTL8211F_LEDCR_MODE BIT(15) #define RTL8211F_LEDCR_ACT_TXRX BIT(4) @@ -123,6 +142,7 @@ struct rtl821x_priv { u16 phycr2; bool has_phycr2; struct clk *clk; + u32 saved_wolopts; }; static int rtl821x_read_page(struct phy_device *phydev) @@ -354,6 +374,53 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static void rtl8211f_get_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = WAKE_MAGIC; + if (phy_read_paged(dev, RTL8211F_WOL_SETTINGS_PAGE, RTL8211F_WOL_SETTINGS_EVENTS) + & RTL8211F_WOL_EVENT_MAGIC) + wol->wolopts = WAKE_MAGIC; +} + +static int rtl8211f_set_wol(struct phy_device *dev, struct ethtool_wolinfo *wol) +{ + const u8 *mac_addr = dev->attached_dev->dev_addr; + int oldpage; + + oldpage = phy_save_page(dev); + if (oldpage < 0) + goto err; + + if (wol->wolopts & WAKE_MAGIC) { + /* Store the device address for the magic packet */ + rtl821x_write_page(dev, RTL8211F_PHYSICAL_ADDR_PAGE); + __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD0, mac_addr[1] << 8 | (mac_addr[0])); + __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD1, mac_addr[3] << 8 | (mac_addr[2])); + __phy_write(dev, RTL8211F_PHYSICAL_ADDR_WORD2, mac_addr[5] << 8 | (mac_addr[4])); + + /* Enable magic packet matching and reset WOL status */ + rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); + __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, RTL8211F_WOL_EVENT_MAGIC); + __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); + + /* Enable the WOL interrupt */ + rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); + __phy_set_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); + } else { + /* Disable the WOL interrupt */ + rtl821x_write_page(dev, RTL8211F_INTBCR_PAGE); + __phy_clear_bits(dev, RTL8211F_INTBCR, RTL8211F_INTBCR_INTB_PMEB); + + /* Disable magic packet matching and reset WOL status */ + rtl821x_write_page(dev, RTL8211F_WOL_SETTINGS_PAGE); + __phy_write(dev, RTL8211F_WOL_SETTINGS_EVENTS, 0); + __phy_write(dev, RTL8211F_WOL_SETTINGS_STATUS, RTL8211F_WOL_STATUS_RESET); + } + +err: + return phy_restore_page(dev, oldpage, 0); +} + static int rtl8211_config_aneg(struct phy_device *phydev) { int ret; @@ -1400,6 +1467,8 @@ static struct phy_driver realtek_drvs[] = { .read_status = rtlgen_read_status, .config_intr = &rtl8211f_config_intr, .handle_interrupt = rtl8211f_handle_interrupt, + .set_wol = rtl8211f_set_wol, + .get_wol = rtl8211f_get_wol, .suspend = rtl821x_suspend, .resume = rtl821x_resume, .read_page = rtl821x_read_page, -- 2.51.0 From ddd234bd4736f05f5f0ed506bee9f1a9b26cbd07 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:11 +0200 Subject: [PATCH 154/517] net: phy: realtek: remove unsed RTL821x_PHYSR* macros These macros have there since the first revision but were never used, so let's just remove them. Signed-off-by: Michael Klein Link: https://patch.msgid.link/20250504172916.243185-2-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 05c4f4d394a5..a6d21dfb1073 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -18,10 +18,6 @@ #include "realtek.h" -#define RTL821x_PHYSR 0x11 -#define RTL821x_PHYSR_DUPLEX BIT(13) -#define RTL821x_PHYSR_SPEED GENMASK(15, 14) - #define RTL821x_INER 0x12 #define RTL8211B_INER_INIT 0x6400 #define RTL8211E_INER_LINK_STATUS BIT(10) -- 2.51.0 From 66803c7f8be64574b376190cc5b712c2f46c124d Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:12 +0200 Subject: [PATCH 155/517] net: phy: realtek: Clean up RTL821x ExtPage access Factor out RTL8211E extension page access code to rtl821x_modify_ext_page() and clean up rtl8211e_config_init() Signed-off-by: Michael Klein Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250504172916.243185-3-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 38 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index a6d21dfb1073..0f005a449719 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -26,7 +26,9 @@ #define RTL821x_INSR 0x13 #define RTL821x_EXT_PAGE_SELECT 0x1e + #define RTL821x_PAGE_SELECT 0x1f +#define RTL821x_SET_EXT_PAGE 0x07 #define RTL8211F_PHYCR1 0x18 #define RTL8211F_PHYCR2 0x19 @@ -69,9 +71,12 @@ #define RTL8211F_ALDPS_ENABLE BIT(2) #define RTL8211F_ALDPS_XTAL_OFF BIT(12) +#define RTL8211E_RGMII_EXT_PAGE 0xa4 +#define RTL8211E_RGMII_DELAY 0x1c #define RTL8211E_CTRL_DELAY BIT(13) #define RTL8211E_TX_DELAY BIT(12) #define RTL8211E_RX_DELAY BIT(11) +#define RTL8211E_DELAY_MASK GENMASK(13, 11) #define RTL8201F_ISR 0x1e #define RTL8201F_ISR_ANERR BIT(15) @@ -151,6 +156,21 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) return __phy_write(phydev, RTL821x_PAGE_SELECT, page); } +static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, + u32 regnum, u16 mask, u16 set) +{ + int oldpage, ret = 0; + + oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); + if (oldpage >= 0) { + ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page); + if (ret == 0) + ret = __phy_modify(phydev, regnum, mask, set); + } + + return phy_restore_page(phydev, oldpage, ret); +} + static int rtl821x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -670,7 +690,6 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, static int rtl8211e_config_init(struct phy_device *phydev) { - int ret = 0, oldpage; u16 val; /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ @@ -700,20 +719,9 @@ static int rtl8211e_config_init(struct phy_device *phydev) * 12 = RX Delay, 11 = TX Delay * 10:0 = Test && debug settings reserved by realtek */ - oldpage = phy_select_page(phydev, 0x7); - if (oldpage < 0) - goto err_restore_page; - - ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); - if (ret) - goto err_restore_page; - - ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY - | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, - val); - -err_restore_page: - return phy_restore_page(phydev, oldpage, ret); + return rtl821x_modify_ext_page(phydev, RTL8211E_RGMII_EXT_PAGE, + RTL8211E_RGMII_DELAY, + RTL8211E_DELAY_MASK, val); } static int rtl8211b_suspend(struct phy_device *phydev) -- 2.51.0 From 798b8b7ae7fd1757c5106f7bcd71938f31cb4296 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:13 +0200 Subject: [PATCH 156/517] net: phy: realtek: add RTL8211F register defines Add some more defines for RTL8211F page and register numbers. Signed-off-by: Michael Klein Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250504172916.243185-4-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 0f005a449719..ca6d2903b1c9 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -30,11 +30,14 @@ #define RTL821x_PAGE_SELECT 0x1f #define RTL821x_SET_EXT_PAGE 0x07 +/* RTL8211F PHY configuration */ +#define RTL8211F_PHYCR_PAGE 0xa43 #define RTL8211F_PHYCR1 0x18 #define RTL8211F_PHYCR2 0x19 #define RTL8211F_CLKOUT_EN BIT(0) #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) +#define RTL8211F_INSR_PAGE 0xa43 #define RTL8211F_INSR 0x1d /* RTL8211F WOL interrupt configuration */ @@ -55,6 +58,8 @@ #define RTL8211F_PHYSICAL_ADDR_WORD1 17 #define RTL8211F_PHYSICAL_ADDR_WORD2 18 +/* RTL8211F LED configuration */ +#define RTL8211F_LEDCR_PAGE 0xd04 #define RTL8211F_LEDCR 0x10 #define RTL8211F_LEDCR_MODE BIT(15) #define RTL8211F_LEDCR_ACT_TXRX BIT(4) @@ -64,7 +69,13 @@ #define RTL8211F_LEDCR_MASK GENMASK(4, 0) #define RTL8211F_LEDCR_SHIFT 5 +/* RTL8211F RGMII configuration */ +#define RTL8211F_RGMII_PAGE 0xd08 + +#define RTL8211F_TXCR 0x11 #define RTL8211F_TX_DELAY BIT(8) + +#define RTL8211F_RXCR 0x15 #define RTL8211F_RX_DELAY BIT(3) #define RTL8211F_ALDPS_PLL_OFF BIT(1) @@ -187,7 +198,7 @@ static int rtl821x_probe(struct phy_device *phydev) return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to get phy clock\n"); - ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); + ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1); if (ret < 0) return ret; @@ -197,7 +208,7 @@ static int rtl821x_probe(struct phy_device *phydev) priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID); if (priv->has_phycr2) { - ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2); + ret = phy_read_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2); if (ret < 0) return ret; @@ -233,7 +244,7 @@ static int rtl8211f_ack_interrupt(struct phy_device *phydev) { int err; - err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); + err = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); return (err < 0) ? err : 0; } @@ -376,7 +387,7 @@ static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev) { int irq_status; - irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR); + irq_status = phy_read_paged(phydev, RTL8211F_INSR_PAGE, RTL8211F_INSR); if (irq_status < 0) { phy_error(phydev); return IRQ_NONE; @@ -473,7 +484,7 @@ static int rtl8211f_config_init(struct phy_device *phydev) u16 val_txdly, val_rxdly; int ret; - ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1, + ret = phy_modify_paged_changed(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR1, RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF, priv->phycr1); if (ret < 0) { @@ -507,7 +518,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) return 0; } - ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, + ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, + RTL8211F_TXCR, RTL8211F_TX_DELAY, val_txdly); if (ret < 0) { dev_err(dev, "Failed to update the TX delay register\n"); @@ -522,7 +534,8 @@ static int rtl8211f_config_init(struct phy_device *phydev) str_enabled_disabled(val_txdly)); } - ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY, + ret = phy_modify_paged_changed(phydev, RTL8211F_RGMII_PAGE, + RTL8211F_RXCR, RTL8211F_RX_DELAY, val_rxdly); if (ret < 0) { dev_err(dev, "Failed to update the RX delay register\n"); @@ -538,14 +551,15 @@ static int rtl8211f_config_init(struct phy_device *phydev) } /* Disable PHY-mode EEE so LPI is passed to the MAC */ - ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, + ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, RTL8211F_PHYCR2, RTL8211F_PHYCR2_PHY_EEE_ENABLE, 0); if (ret) return ret; if (priv->has_phycr2) { - ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2, - RTL8211F_CLKOUT_EN, priv->phycr2); + ret = phy_modify_paged(phydev, RTL8211F_PHYCR_PAGE, + RTL8211F_PHYCR2, RTL8211F_CLKOUT_EN, + priv->phycr2); if (ret < 0) { dev_err(dev, "clkout configuration failed: %pe\n", ERR_PTR(ret)); -- 2.51.0 From 825c23aae9ae86718d9d0b15090994b8e2b99265 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:14 +0200 Subject: [PATCH 157/517] net: phy: realtek: Group RTL82* macro definitions Group macro definitions by PHY in lexicographic order. Within each PHY block, definitions are order by page number and then register number. Signed-off-by: Michael Klein Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250504172916.243185-5-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 72 +++++++++++++------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index ca6d2903b1c9..e01b13a9b5c3 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -18,6 +18,16 @@ #include "realtek.h" +#define RTL8201F_IER 0x13 + +#define RTL8201F_ISR 0x1e +#define RTL8201F_ISR_ANERR BIT(15) +#define RTL8201F_ISR_DUPLEX BIT(13) +#define RTL8201F_ISR_LINK BIT(11) +#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ + RTL8201F_ISR_DUPLEX | \ + RTL8201F_ISR_LINK) + #define RTL821x_INER 0x12 #define RTL8211B_INER_INIT 0x6400 #define RTL8211E_INER_LINK_STATUS BIT(10) @@ -30,9 +40,21 @@ #define RTL821x_PAGE_SELECT 0x1f #define RTL821x_SET_EXT_PAGE 0x07 +/* RTL8211E extension page 164/0xa4 */ +#define RTL8211E_RGMII_EXT_PAGE 0xa4 +#define RTL8211E_RGMII_DELAY 0x1c +#define RTL8211E_CTRL_DELAY BIT(13) +#define RTL8211E_TX_DELAY BIT(12) +#define RTL8211E_RX_DELAY BIT(11) +#define RTL8211E_DELAY_MASK GENMASK(13, 11) + /* RTL8211F PHY configuration */ #define RTL8211F_PHYCR_PAGE 0xa43 #define RTL8211F_PHYCR1 0x18 +#define RTL8211F_ALDPS_PLL_OFF BIT(1) +#define RTL8211F_ALDPS_ENABLE BIT(2) +#define RTL8211F_ALDPS_XTAL_OFF BIT(12) + #define RTL8211F_PHYCR2 0x19 #define RTL8211F_CLKOUT_EN BIT(0) #define RTL8211F_PHYCR2_PHY_EEE_ENABLE BIT(5) @@ -40,24 +62,6 @@ #define RTL8211F_INSR_PAGE 0xa43 #define RTL8211F_INSR 0x1d -/* RTL8211F WOL interrupt configuration */ -#define RTL8211F_INTBCR_PAGE 0xd40 -#define RTL8211F_INTBCR 0x16 -#define RTL8211F_INTBCR_INTB_PMEB BIT(5) - -/* RTL8211F WOL settings */ -#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a -#define RTL8211F_WOL_SETTINGS_EVENTS 16 -#define RTL8211F_WOL_EVENT_MAGIC BIT(12) -#define RTL8211F_WOL_SETTINGS_STATUS 17 -#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) - -/* RTL8211F Unique phyiscal and multicast address (WOL) */ -#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c -#define RTL8211F_PHYSICAL_ADDR_WORD0 16 -#define RTL8211F_PHYSICAL_ADDR_WORD1 17 -#define RTL8211F_PHYSICAL_ADDR_WORD2 18 - /* RTL8211F LED configuration */ #define RTL8211F_LEDCR_PAGE 0xd04 #define RTL8211F_LEDCR 0x10 @@ -78,25 +82,23 @@ #define RTL8211F_RXCR 0x15 #define RTL8211F_RX_DELAY BIT(3) -#define RTL8211F_ALDPS_PLL_OFF BIT(1) -#define RTL8211F_ALDPS_ENABLE BIT(2) -#define RTL8211F_ALDPS_XTAL_OFF BIT(12) +/* RTL8211F WOL interrupt configuration */ +#define RTL8211F_INTBCR_PAGE 0xd40 +#define RTL8211F_INTBCR 0x16 +#define RTL8211F_INTBCR_INTB_PMEB BIT(5) -#define RTL8211E_RGMII_EXT_PAGE 0xa4 -#define RTL8211E_RGMII_DELAY 0x1c -#define RTL8211E_CTRL_DELAY BIT(13) -#define RTL8211E_TX_DELAY BIT(12) -#define RTL8211E_RX_DELAY BIT(11) -#define RTL8211E_DELAY_MASK GENMASK(13, 11) +/* RTL8211F WOL settings */ +#define RTL8211F_WOL_SETTINGS_PAGE 0xd8a +#define RTL8211F_WOL_SETTINGS_EVENTS 16 +#define RTL8211F_WOL_EVENT_MAGIC BIT(12) +#define RTL8211F_WOL_SETTINGS_STATUS 17 +#define RTL8211F_WOL_STATUS_RESET (BIT(15) | 0x1fff) -#define RTL8201F_ISR 0x1e -#define RTL8201F_ISR_ANERR BIT(15) -#define RTL8201F_ISR_DUPLEX BIT(13) -#define RTL8201F_ISR_LINK BIT(11) -#define RTL8201F_ISR_MASK (RTL8201F_ISR_ANERR | \ - RTL8201F_ISR_DUPLEX | \ - RTL8201F_ISR_LINK) -#define RTL8201F_IER 0x13 +/* RTL8211F Unique phyiscal and multicast address (WOL) */ +#define RTL8211F_PHYSICAL_ADDR_PAGE 0xd8c +#define RTL8211F_PHYSICAL_ADDR_WORD0 16 +#define RTL8211F_PHYSICAL_ADDR_WORD1 17 +#define RTL8211F_PHYSICAL_ADDR_WORD2 18 #define RTL822X_VND1_SERDES_OPTION 0x697a #define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0) -- 2.51.0 From 6013af9a8dd65b8c5e941f33ec2dcf99f78c67d7 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:15 +0200 Subject: [PATCH 158/517] net: phy: realtek: use __set_bit() in rtl8211f_led_hw_control_get() rtl8211f_led_hw_control_get() does not need atomic bit operations, replace set_bit() by __set_bit(). Signed-off-by: Michael Klein Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250504172916.243185-6-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index e01b13a9b5c3..e26098a2ff27 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -659,17 +659,17 @@ static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, val &= RTL8211F_LEDCR_MASK; if (val & RTL8211F_LEDCR_LINK_10) - set_bit(TRIGGER_NETDEV_LINK_10, rules); + __set_bit(TRIGGER_NETDEV_LINK_10, rules); if (val & RTL8211F_LEDCR_LINK_100) - set_bit(TRIGGER_NETDEV_LINK_100, rules); + __set_bit(TRIGGER_NETDEV_LINK_100, rules); if (val & RTL8211F_LEDCR_LINK_1000) - set_bit(TRIGGER_NETDEV_LINK_1000, rules); + __set_bit(TRIGGER_NETDEV_LINK_1000, rules); if (val & RTL8211F_LEDCR_ACT_TXRX) { - set_bit(TRIGGER_NETDEV_RX, rules); - set_bit(TRIGGER_NETDEV_TX, rules); + __set_bit(TRIGGER_NETDEV_RX, rules); + __set_bit(TRIGGER_NETDEV_TX, rules); } return 0; -- 2.51.0 From af5ac7b353e93a7d31448c80a90f687b38805116 Mon Sep 17 00:00:00 2001 From: Michael Klein Date: Sun, 4 May 2025 19:29:16 +0200 Subject: [PATCH 159/517] net: phy: realtek: Add support for PHY LEDs on RTL8211E Like the RTL8211F, the RTL8211E PHY supports up to three LEDs. Add netdev trigger support for them, too. Signed-off-by: Michael Klein Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250504172916.243185-7-michael@fossekall.de Signed-off-by: Paolo Abeni --- drivers/net/phy/realtek/realtek_main.c | 125 +++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index e26098a2ff27..301fbe141b9b 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -40,6 +40,20 @@ #define RTL821x_PAGE_SELECT 0x1f #define RTL821x_SET_EXT_PAGE 0x07 +/* RTL8211E extension page 44/0x2c */ +#define RTL8211E_LEDCR_EXT_PAGE 0x2c +#define RTL8211E_LEDCR1 0x1a +#define RTL8211E_LEDCR1_ACT_TXRX BIT(4) +#define RTL8211E_LEDCR1_MASK BIT(4) +#define RTL8211E_LEDCR1_SHIFT 1 + +#define RTL8211E_LEDCR2 0x1c +#define RTL8211E_LEDCR2_LINK_1000 BIT(2) +#define RTL8211E_LEDCR2_LINK_100 BIT(1) +#define RTL8211E_LEDCR2_LINK_10 BIT(0) +#define RTL8211E_LEDCR2_MASK GENMASK(2, 0) +#define RTL8211E_LEDCR2_SHIFT 4 + /* RTL8211E extension page 164/0xa4 */ #define RTL8211E_RGMII_EXT_PAGE 0xa4 #define RTL8211E_RGMII_DELAY 0x1c @@ -145,7 +159,8 @@ #define RTL_8221B_VN_CG 0x001cc84a #define RTL_8251B 0x001cc862 -#define RTL8211F_LED_COUNT 3 +/* RTL8211E and RTL8211F support up to three LEDs */ +#define RTL8211x_LED_COUNT 3 MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); @@ -169,6 +184,21 @@ static int rtl821x_write_page(struct phy_device *phydev, int page) return __phy_write(phydev, RTL821x_PAGE_SELECT, page); } +static int rtl821x_read_ext_page(struct phy_device *phydev, u16 ext_page, + u32 regnum) +{ + int oldpage, ret = 0; + + oldpage = phy_select_page(phydev, RTL821x_SET_EXT_PAGE); + if (oldpage >= 0) { + ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, ext_page); + if (ret == 0) + ret = __phy_read(phydev, regnum); + } + + return phy_restore_page(phydev, oldpage, ret); +} + static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page, u32 regnum, u16 mask, u16 set) { @@ -608,7 +638,7 @@ static int rtl821x_resume(struct phy_device *phydev) return 0; } -static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, +static int rtl8211x_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules) { const unsigned long mask = BIT(TRIGGER_NETDEV_LINK_10) | @@ -627,9 +657,11 @@ static int rtl8211f_led_hw_is_supported(struct phy_device *phydev, u8 index, * rates and Active indication always at all three 10+100+1000 * link rates. * This code currently uses mode B only. + * + * RTL8211E PHY LED has one mode, which works like RTL8211F mode B. */ - if (index >= RTL8211F_LED_COUNT) + if (index >= RTL8211x_LED_COUNT) return -EINVAL; /* Filter out any other unsupported triggers. */ @@ -648,7 +680,7 @@ static int rtl8211f_led_hw_control_get(struct phy_device *phydev, u8 index, { int val; - if (index >= RTL8211F_LED_COUNT) + if (index >= RTL8211x_LED_COUNT) return -EINVAL; val = phy_read_paged(phydev, 0xd04, RTL8211F_LEDCR); @@ -681,7 +713,7 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, const u16 mask = RTL8211F_LEDCR_MASK << (RTL8211F_LEDCR_SHIFT * index); u16 reg = 0; - if (index >= RTL8211F_LED_COUNT) + if (index >= RTL8211x_LED_COUNT) return -EINVAL; if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) @@ -704,6 +736,84 @@ static int rtl8211f_led_hw_control_set(struct phy_device *phydev, u8 index, return phy_modify_paged(phydev, 0xd04, RTL8211F_LEDCR, mask, reg); } +static int rtl8211e_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int ret; + u16 cr1, cr2; + + if (index >= RTL8211x_LED_COUNT) + return -EINVAL; + + ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, + RTL8211E_LEDCR1); + if (ret < 0) + return ret; + + cr1 = ret >> RTL8211E_LEDCR1_SHIFT * index; + if (cr1 & RTL8211E_LEDCR1_ACT_TXRX) { + __set_bit(TRIGGER_NETDEV_RX, rules); + __set_bit(TRIGGER_NETDEV_TX, rules); + } + + ret = rtl821x_read_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, + RTL8211E_LEDCR2); + if (ret < 0) + return ret; + + cr2 = ret >> RTL8211E_LEDCR2_SHIFT * index; + if (cr2 & RTL8211E_LEDCR2_LINK_10) + __set_bit(TRIGGER_NETDEV_LINK_10, rules); + + if (cr2 & RTL8211E_LEDCR2_LINK_100) + __set_bit(TRIGGER_NETDEV_LINK_100, rules); + + if (cr2 & RTL8211E_LEDCR2_LINK_1000) + __set_bit(TRIGGER_NETDEV_LINK_1000, rules); + + return ret; +} + +static int rtl8211e_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + const u16 cr1mask = + RTL8211E_LEDCR1_MASK << (RTL8211E_LEDCR1_SHIFT * index); + const u16 cr2mask = + RTL8211E_LEDCR2_MASK << (RTL8211E_LEDCR2_SHIFT * index); + u16 cr1 = 0, cr2 = 0; + int ret; + + if (index >= RTL8211x_LED_COUNT) + return -EINVAL; + + if (test_bit(TRIGGER_NETDEV_RX, &rules) || + test_bit(TRIGGER_NETDEV_TX, &rules)) { + cr1 |= RTL8211E_LEDCR1_ACT_TXRX; + } + + cr1 <<= RTL8211E_LEDCR1_SHIFT * index; + ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, + RTL8211E_LEDCR1, cr1mask, cr1); + if (ret < 0) + return ret; + + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + cr2 |= RTL8211E_LEDCR2_LINK_10; + + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + cr2 |= RTL8211E_LEDCR2_LINK_100; + + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + cr2 |= RTL8211E_LEDCR2_LINK_1000; + + cr2 <<= RTL8211E_LEDCR2_SHIFT * index; + ret = rtl821x_modify_ext_page(phydev, RTL8211E_LEDCR_EXT_PAGE, + RTL8211E_LEDCR2, cr2mask, cr2); + + return ret; +} + static int rtl8211e_config_init(struct phy_device *phydev) { u16 val; @@ -1479,6 +1589,9 @@ static struct phy_driver realtek_drvs[] = { .resume = genphy_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, + .led_hw_is_supported = rtl8211x_led_hw_is_supported, + .led_hw_control_get = rtl8211e_led_hw_control_get, + .led_hw_control_set = rtl8211e_led_hw_control_set, }, { PHY_ID_MATCH_EXACT(0x001cc916), .name = "RTL8211F Gigabit Ethernet", @@ -1494,7 +1607,7 @@ static struct phy_driver realtek_drvs[] = { .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, .flags = PHY_ALWAYS_CALL_SUSPEND, - .led_hw_is_supported = rtl8211f_led_hw_is_supported, + .led_hw_is_supported = rtl8211x_led_hw_is_supported, .led_hw_control_get = rtl8211f_led_hw_control_get, .led_hw_control_set = rtl8211f_led_hw_control_set, }, { -- 2.51.0 From 955251d7b04d32610229bef09ec0a27ccbd8e370 Mon Sep 17 00:00:00 2001 From: ChunHao Lin Date: Fri, 16 May 2025 13:56:22 +0800 Subject: [PATCH 160/517] net: phy: realtek: add RTL8127-internal PHY RTL8127-internal PHY is RTL8261C which is a integrated 10Gbps PHY with ID 0x001cc890. It follows the code path of RTL8125/RTL8126 internal NBase-T PHY. Signed-off-by: ChunHao Lin Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250516055622.3772-1-hau@realtek.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 301fbe141b9b..b5e00cdf0123 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -158,6 +158,7 @@ #define RTL_8221B_VB_CG 0x001cc849 #define RTL_8221B_VN_CG 0x001cc84a #define RTL_8251B 0x001cc862 +#define RTL_8261C 0x001cc890 /* RTL8211E and RTL8211F support up to three LEDs */ #define RTL8211x_LED_COUNT 3 @@ -1370,6 +1371,7 @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) case RTL_GENERIC_PHYID: case RTL_8221B: case RTL_8251B: + case RTL_8261C: case 0x001cc841: break; default: -- 2.51.0 From c1c8742b69103888ee85bb7e55353066d4ef5457 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Wed, 13 Aug 2025 01:44:07 -0400 Subject: [PATCH 161/517] net: phy: realtek: convert RTL8226-CG to c45 only Short: Convert the RTL8226-CG to c45 so it can be used in its Realtek based ecosystems. Long: The RTL8226-CG can be mainly found on devices of the Realtek Otto switch platform. Devices like the Zyxel XGS1210-12 are based on it. These implement a hardware based phy polling in the background to update SoC status registers. The hardware provides 4 smi busses where phys are attached to. For each bus one can decide if it is polled in c45 or c22 mode. See https://svanheule.net/realtek/longan/register/smi_glb_ctrl With this setting the register access will be limited by the hardware. This is very complex (including caching and special c45-over-c22 handling). But basically it boils down to "enable protocol x and SoC will disable register access via protocol y". Mainline already gained support for the rtl9300 mdio driver in commit 24e31e474769 ("net: mdio: Add RTL9300 MDIO driver"). It covers the basic features, but a lot effort is still needed to understand hardware properly. So it runs a simple setup by selecting the proper bus mode during startup. /* Put the interfaces into C45 mode if required */ glb_ctrl_mask = GENMASK(19, 16); for (i = 0; i < MAX_SMI_BUSSES; i++) if (priv->smi_bus_is_c45[i]) glb_ctrl_val |= GLB_CTRL_INTF_SEL(i); ... err = regmap_update_bits(regmap, SMI_GLB_CTRL, glb_ctrl_mask, glb_ctrl_val); To avoid complex coding later on, it limits access by only providing either c22 or c45: bus->name = "Realtek Switch MDIO Bus"; if (priv->smi_bus_is_c45[mdio_bus]) { bus->read_c45 = rtl9300_mdio_read_c45; bus->write_c45 = rtl9300_mdio_write_c45; } else { bus->read = rtl9300_mdio_read_c22; bus->write = rtl9300_mdio_write_c22; } Because of these limitations the existing RTL8226 phy driver is not working at all on Realtek switches. Convert the driver to c45-only. Luckily the RTL8226 seems to support proper MDIO_PMA_EXTABLE flags. So standard function genphy_c45_pma_read_abilities() can call genphy_c45_pma_read_ext_abilities() and 10/100/1000 is populated right. Thus conversion is straight forward. Outputs before - REMARK: For this a "hacked" bus was used that toggles the mode for each c22/c45 access. But that is slow and produces unstable data in the SoC status registers). Settings for lan9: Supported ports: [ TP MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Advertised pause frame use: Symmetric Receive-only Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: Unknown! Duplex: Unknown! (255) Port: Twisted Pair PHYAD: 24 Transceiver: external Auto-negotiation: on MDI-X: Unknown Supports Wake-on: d Wake-on: d Link detected: no Outputs with this commit: Settings for lan9: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full 2500baseT/Full Advertised pause frame use: Symmetric Receive-only Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: Unknown! Duplex: Unknown! (255) Port: Twisted Pair PHYAD: 24 Transceiver: external Auto-negotiation: on MDI-X: Unknown Supports Wake-on: d Wake-on: d Link detected: no Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20250813054407.1108285-1-markus.stockhausen@gmx.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index b5e00cdf0123..bcfd9305e8b7 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1274,6 +1274,21 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) return 0; } +static int rtl822x_c45_soft_reset(struct phy_device *phydev) +{ + int ret, val; + + ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_RESET, MDIO_CTRL1_RESET); + if (ret < 0) + return ret; + + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, + MDIO_CTRL1, val, + !(val & MDIO_CTRL1_RESET), + 5000, 100000, true); +} + static int rtl822xb_c45_read_status(struct phy_device *phydev) { int ret; @@ -1660,13 +1675,12 @@ static struct phy_driver realtek_drvs[] = { }, { PHY_ID_MATCH_EXACT(0x001cc838), .name = "RTL8226-CG 2.5Gbps PHY", - .get_features = rtl822x_get_features, - .config_aneg = rtl822x_config_aneg, - .read_status = rtl822x_read_status, - .suspend = genphy_suspend, - .resume = rtlgen_resume, - .read_page = rtl821x_read_page, - .write_page = rtl821x_write_page, + .soft_reset = rtl822x_c45_soft_reset, + .get_features = rtl822x_c45_get_features, + .config_aneg = rtl822x_c45_config_aneg, + .read_status = rtl822x_c45_read_status, + .suspend = genphy_c45_pma_suspend, + .resume = rtlgen_c45_resume, }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -- 2.51.0 From 19770c92bfab8e1cfb144fa63e2a6fa8a9a9c791 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 15 Aug 2025 04:20:09 -0400 Subject: [PATCH 162/517] net: phy: realtek: enable serdes option mode for RTL8226-CG The RTL8226-CG can make use of the serdes option mode feature to dynamically switch between SGMII and 2500base-X. From what is known the setup sequence is much simpler with no magic values. Convert the exiting config_init() into a helper that configures the PHY depending on generation 1 or 2. Call the helper from two separated new config_init() functions. Finally convert the phy_driver specs of the RTL8226-CG to make use of the new configuration and switch over to the extended read_status() function to dynamically change the interface according to the serdes mode. Remark! The logic could be simpler if the serdes mode could be set before all other generation 2 magic values. Due to missing RTL8221B test hardware the mmd command order was kept. Tested on Zyxel XGS1210-12. Signed-off-by: Markus Stockhausen Link: https://patch.msgid.link/20250815082009.3678865-1-markus.stockhausen@gmx.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/realtek/realtek_main.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index bcfd9305e8b7..c0981932429b 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1032,7 +1032,7 @@ static int rtl822x_probe(struct phy_device *phydev) return 0; } -static int rtl822xb_config_init(struct phy_device *phydev) +static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) { bool has_2500, has_sgmii; u16 mode; @@ -1067,15 +1067,18 @@ static int rtl822xb_config_init(struct phy_device *phydev) /* the following sequence with magic numbers sets up the SerDes * option mode */ - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); - if (ret < 0) - return ret; + + if (!gen1) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0); + if (ret < 0) + return ret; + } ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION, RTL822X_VND1_SERDES_OPTION_MODE_MASK, mode); - if (ret < 0) + if (gen1 || ret < 0) return ret; ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); @@ -1089,6 +1092,16 @@ static int rtl822xb_config_init(struct phy_device *phydev) return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); } +static int rtl822x_config_init(struct phy_device *phydev) +{ + return rtl822x_set_serdes_option_mode(phydev, true); +} + +static int rtl822xb_config_init(struct phy_device *phydev) +{ + return rtl822x_set_serdes_option_mode(phydev, false); +} + static int rtl822xb_get_rate_matching(struct phy_device *phydev, phy_interface_t iface) { @@ -1678,7 +1691,8 @@ static struct phy_driver realtek_drvs[] = { .soft_reset = rtl822x_c45_soft_reset, .get_features = rtl822x_c45_get_features, .config_aneg = rtl822x_c45_config_aneg, - .read_status = rtl822x_c45_read_status, + .config_init = rtl822x_config_init, + .read_status = rtl822xb_c45_read_status, .suspend = genphy_c45_pma_suspend, .resume = rtlgen_c45_resume, }, { -- 2.51.0 From 3eda64f56ef81929d383b568d8642b7439cba90e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 17 May 2025 22:13:45 +0200 Subject: [PATCH 163/517] net: phy: pass PHY driver to .match_phy_device OP Pass PHY driver pointer to .match_phy_device OP in addition to phydev. Having access to the PHY driver struct might be useful to check the PHY ID of the driver is being matched for in case the PHY ID scanned in the phydev is not consistent. A scenario for this is a PHY that change PHY ID after a firmware is loaded, in such case, the PHY ID stored in PHY device struct is not valid anymore and PHY will manually scan the ID in the match_phy_device function. Having the PHY driver info is also useful for those PHY driver that implement multiple simple .match_phy_device OP to match specific MMD PHY ID. With this extra info if the parsing logic is the same, the matching function can be generalized by using the phy_id in the PHY driver instead of hardcoding. Rust wrapper callback is updated to align to the new match_phy_device arguments. Suggested-by: Russell King (Oracle) Reviewed-by: Russell King (Oracle) Signed-off-by: Christian Marangi Reviewed-by: Benno Lossin # for Rust Reviewed-by: FUJITA Tomonori Link: https://patch.msgid.link/20250517201353.5137-2-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/bcm87xx.c | 6 ++++-- drivers/net/phy/icplus.c | 6 ++++-- drivers/net/phy/marvell10g.c | 12 ++++++++---- drivers/net/phy/micrel.c | 6 ++++-- drivers/net/phy/nxp-c45-tja11xx.c | 6 ++++-- drivers/net/phy/nxp-tja11xx.c | 6 ++++-- drivers/net/phy/phy_device.c | 2 +- drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++--------- drivers/net/phy/teranetics.c | 3 ++- include/linux/phy.h | 3 ++- rust/kernel/net/phy.rs | 1 + 11 files changed, 52 insertions(+), 26 deletions(-) diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c index e81404bf8994..1e1e2259fc2b 100644 --- a/drivers/net/phy/bcm87xx.c +++ b/drivers/net/phy/bcm87xx.c @@ -185,12 +185,14 @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } -static int bcm8706_match_phy_device(struct phy_device *phydev) +static int bcm8706_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706; } -static int bcm8727_match_phy_device(struct phy_device *phydev) +static int bcm8727_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727; } diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index feed270ab4ea..c6950b7145c1 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -520,12 +520,14 @@ static int ip101a_g_match_phy_device(struct phy_device *phydev, bool ip101a) return ip101a == !ret; } -static int ip101a_match_phy_device(struct phy_device *phydev) +static int ip101a_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return ip101a_g_match_phy_device(phydev, true); } -static int ip101g_match_phy_device(struct phy_device *phydev) +static int ip101g_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return ip101a_g_match_phy_device(phydev, false); } diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 623bdb8466b8..2994a3570128 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -1284,7 +1284,8 @@ static int mv3310_get_number_of_ports(struct phy_device *phydev) return ret + 1; } -static int mv3310_match_phy_device(struct phy_device *phydev) +static int mv3310_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) @@ -1293,7 +1294,8 @@ static int mv3310_match_phy_device(struct phy_device *phydev) return mv3310_get_number_of_ports(phydev) == 1; } -static int mv3340_match_phy_device(struct phy_device *phydev) +static int mv3340_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) @@ -1317,12 +1319,14 @@ static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) return !!(val & MDIO_PCS_SPEED_5G) == has_5g; } -static int mv2110_match_phy_device(struct phy_device *phydev) +static int mv2110_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return mv211x_match_phy_device(phydev, true); } -static int mv2111_match_phy_device(struct phy_device *phydev) +static int mv2111_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return mv211x_match_phy_device(phydev, false); } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 655769765bc8..2c6e75789eb7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -768,7 +768,8 @@ static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, return !ret; } -static int ksz8051_match_phy_device(struct phy_device *phydev) +static int ksz8051_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return ksz8051_ksz8795_match_phy_device(phydev, true); } @@ -888,7 +889,8 @@ static int ksz8061_config_init(struct phy_device *phydev) return kszphy_config_init(phydev); } -static int ksz8795_match_phy_device(struct phy_device *phydev) +static int ksz8795_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return ksz8051_ksz8795_match_phy_device(phydev, false); } diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 9d6b336f9971..9aeae2a6c638 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -1944,13 +1944,15 @@ static int nxp_c45_macsec_ability(struct phy_device *phydev) return macsec_ability; } -static int tja1103_match_phy_device(struct phy_device *phydev) +static int tja1103_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && !nxp_c45_macsec_ability(phydev); } -static int tja1104_match_phy_device(struct phy_device *phydev) +static int tja1104_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && nxp_c45_macsec_ability(phydev); diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c index ed7fa26bac8e..08dda6926732 100644 --- a/drivers/net/phy/nxp-tja11xx.c +++ b/drivers/net/phy/nxp-tja11xx.c @@ -646,12 +646,14 @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0) return !ret; } -static int tja1102_p0_match_phy_device(struct phy_device *phydev) +static int tja1102_p0_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return tja1102_match_phy_device(phydev, true); } -static int tja1102_p1_match_phy_device(struct phy_device *phydev) +static int tja1102_p1_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return tja1102_match_phy_device(phydev, false); } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 762f909242b4..71f6cadde109 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -600,7 +600,7 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) return 0; if (phydrv->match_phy_device) - return phydrv->match_phy_device(phydev); + return phydrv->match_phy_device(phydev, phydrv); if (phydev->is_c45) { for (i = 1; i < num_ids; i++) { diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index c0981932429b..114d219562f1 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1343,13 +1343,15 @@ static bool rtlgen_supports_mmd(struct phy_device *phydev) return val > 0; } -static int rtlgen_match_phy_device(struct phy_device *phydev) +static int rtlgen_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->phy_id == RTL_GENERIC_PHYID && !rtlgen_supports_2_5gbps(phydev); } -static int rtl8226_match_phy_device(struct phy_device *phydev) +static int rtl8226_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->phy_id == RTL_GENERIC_PHYID && rtlgen_supports_2_5gbps(phydev) && @@ -1365,32 +1367,38 @@ static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, return !is_c45 && (id == phydev->phy_id); } -static int rtl8221b_match_phy_device(struct phy_device *phydev) +static int rtl8221b_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); } -static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) +static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); } -static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) +static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); } -static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) +static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); } -static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) +static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); } -static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) +static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { if (phydev->is_c45) return false; @@ -1409,7 +1417,8 @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); } -static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) +static int rtl8251b_c45_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return rtlgen_is_c45_match(phydev, RTL_8251B, true); } diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 752d4bf7bb99..46c5ff7d7b56 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -67,7 +67,8 @@ static int teranetics_read_status(struct phy_device *phydev) return 0; } -static int teranetics_match_phy_device(struct phy_device *phydev) +static int teranetics_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; } diff --git a/include/linux/phy.h b/include/linux/phy.h index df147d9d302f..1bdcc3dd8b66 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1035,7 +1035,8 @@ struct phy_driver { * driver for the given phydev. If NULL, matching is based on * phy_id and phy_id_mask. */ - int (*match_phy_device)(struct phy_device *phydev); + int (*match_phy_device)(struct phy_device *phydev, + const struct phy_driver *phydrv); /** * @set_wol: Some devices (e.g. qnap TS-119P II) require PHY diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index beb62ec712c3..40214bbe4677 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -421,6 +421,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn match_phy_device_callback( phydev: *mut bindings::phy_device, + _phydrv: *const bindings::phy_driver, ) -> crate::ffi::c_int { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on -- 2.51.0 From 175ba11ce1ac5beacdbe65b7fd3acbe9002f8d1f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 17 May 2025 22:13:48 +0200 Subject: [PATCH 164/517] net: phy: introduce genphy_match_phy_device() Introduce new API, genphy_match_phy_device(), to provide a way to check to match a PHY driver for a PHY device based on the info stored in the PHY device struct. The function generalize the logic used in phy_bus_match() to check the PHY ID whether if C45 or C22 ID should be used for matching. This is useful for custom .match_phy_device function that wants to use the generic logic under some condition. (example a PHY is already setup and provide the correct PHY ID) Reviewed-by: Russell King (Oracle) Signed-off-by: Christian Marangi Link: https://patch.msgid.link/20250517201353.5137-5-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++----------- include/linux/phy.h | 3 +++ 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 71f6cadde109..2e08d20a3cfb 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -589,20 +589,26 @@ static int phy_scan_fixups(struct phy_device *phydev) return 0; } -static int phy_bus_match(struct device *dev, const struct device_driver *drv) +/** + * genphy_match_phy_device - match a PHY device with a PHY driver + * @phydev: target phy_device struct + * @phydrv: target phy_driver struct + * + * Description: Checks whether the given PHY device matches the specified + * PHY driver. For Clause 45 PHYs, iterates over the available device + * identifiers and compares them against the driver's expected PHY ID, + * applying the provided mask. For Clause 22 PHYs, a direct ID comparison + * is performed. + * + * Return: 1 if the PHY device matches the driver, 0 otherwise. + */ +int genphy_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) { - struct phy_device *phydev = to_phy_device(dev); - const struct phy_driver *phydrv = to_phy_driver(drv); - const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); - int i; - - if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) - return 0; - - if (phydrv->match_phy_device) - return phydrv->match_phy_device(phydev, phydrv); - if (phydev->is_c45) { + const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); + int i; + for (i = 1; i < num_ids; i++) { if (phydev->c45_ids.device_ids[i] == 0xffffffff) continue; @@ -611,11 +617,27 @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) phydrv->phy_id, phydrv->phy_id_mask)) return 1; } + return 0; - } else { - return phy_id_compare(phydev->phy_id, phydrv->phy_id, - phydrv->phy_id_mask); } + + return phy_id_compare(phydev->phy_id, phydrv->phy_id, + phydrv->phy_id_mask); +} +EXPORT_SYMBOL_GPL(genphy_match_phy_device); + +static int phy_bus_match(struct device *dev, const struct device_driver *drv) +{ + struct phy_device *phydev = to_phy_device(dev); + const struct phy_driver *phydrv = to_phy_driver(drv); + + if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) + return 0; + + if (phydrv->match_phy_device) + return phydrv->match_phy_device(phydev, phydrv); + + return genphy_match_phy_device(phydev, phydrv); } static ssize_t diff --git a/include/linux/phy.h b/include/linux/phy.h index 1bdcc3dd8b66..85217937e489 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1940,6 +1940,9 @@ char *phy_attached_info_irq(struct phy_device *phydev) __malloc; void phy_attached_info(struct phy_device *phydev); +int genphy_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv); + /* Clause 22 PHY */ int genphy_read_abilities(struct phy_device *phydev); int genphy_setup_forced(struct phy_device *phydev); -- 2.51.0 From 607e13a6b9b9484da3e5e549dee6883ad71fe0d3 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 17 May 2025 22:13:49 +0200 Subject: [PATCH 165/517] net: phy: Add support for Aeonsemi AS21xxx PHYs Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs integrate an IPC to setup some configuration and require special handling to sync with the parity bit. The parity bit is a way the IPC use to follow correct order of command sent. Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, AS21210PB1 that all register with the PHY ID 0x7500 0x7510 before the firmware is loaded. They all support up to 5 LEDs with various HW mode supported. While implementing it was found some strange coincidence with using the same logic for implementing C22 in MMD regs in Broadcom PHYs. For reference here the AS21xxx PHY name logic: AS21x1xxB1 ^ ^^ | |J: Supports SyncE/PTP | |P: No SyncE/PTP support | 1: Supports 2nd Serdes | 2: Not 2nd Serdes support 0: 10G, 5G, 2.5G 5: 5G, 2.5G 2: 2.5G Reviewed-by: Andrew Lunn Signed-off-by: Christian Marangi Link: https://patch.msgid.link/20250517201353.5137-6-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 12 + drivers/net/phy/Makefile | 1 + drivers/net/phy/as21xxx.c | 1087 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1100 insertions(+) create mode 100644 drivers/net/phy/as21xxx.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f7e21a2761b8..01cc31817357 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -79,6 +79,18 @@ config SFP comment "MII PHY device drivers" +config AS21XXX_PHY + tristate "Aeonsemi AS21xxx PHYs" + help + Currently supports the Aeonsemi AS21xxx PHY. + + These are C45 PHYs 10G that require all a generic firmware. + + Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, + AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, + AS21210PB1 that all register with the PHY ID 0x7500 0x7500 + before the firmware is loaded. + config AIR_EN8811H_PHY tristate "Airoha EN8811H 2.5 Gigabit PHY" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a38b01f74db7..768d1e8ebf80 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ +obj-$(CONFIG_AS21XXX_PHY) += as21xxx.o ifdef CONFIG_AX88796B_RUST_PHY obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o else diff --git a/drivers/net/phy/as21xxx.c b/drivers/net/phy/as21xxx.c new file mode 100644 index 000000000000..037d79944eca --- /dev/null +++ b/drivers/net/phy/as21xxx.c @@ -0,0 +1,1087 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Aeonsemi AS21XXxX PHY Driver + * + * Author: Christian Marangi + */ + +#include +#include +#include +#include +#include + +#define VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR 0x3 +#define VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR 0x4 + +#define VEND1_GLB_REG_CPU_CTRL 0xe +#define VEND1_GLB_CPU_CTRL_MASK GENMASK(4, 0) +#define VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK GENMASK(12, 8) +#define VEND1_GLB_CPU_CTRL_LED_POLARITY(_n) FIELD_PREP(VEND1_GLB_CPU_CTRL_LED_POLARITY_MASK, \ + BIT(_n)) + +#define VEND1_FW_START_ADDR 0x100 + +#define VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD 0x101 +#define VEND1_GLB_REG_MDIO_INDIRECT_LOAD 0x102 + +#define VEND1_GLB_REG_MDIO_INDIRECT_STATUS 0x103 + +#define VEND1_PTP_CLK 0x142 +#define VEND1_PTP_CLK_EN BIT(6) + +/* 5 LED at step of 0x20 + * FE: Fast-Ethernet (10/100) + * GE: Gigabit-Ethernet (1000) + * NG: New-Generation (2500/5000/10000) + */ +#define VEND1_LED_REG(_n) (0x1800 + ((_n) * 0x10)) +#define VEND1_LED_REG_A_EVENT GENMASK(15, 11) +#define VEND1_LED_CONF 0x1881 +#define VEND1_LED_CONFG_BLINK GENMASK(7, 0) + +#define VEND1_SPEED_STATUS 0x4002 +#define VEND1_SPEED_MASK GENMASK(7, 0) +#define VEND1_SPEED_10000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x3) +#define VEND1_SPEED_5000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x5) +#define VEND1_SPEED_2500 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x9) +#define VEND1_SPEED_1000 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x10) +#define VEND1_SPEED_100 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x20) +#define VEND1_SPEED_10 FIELD_PREP_CONST(VEND1_SPEED_MASK, 0x0) + +#define VEND1_IPC_CMD 0x5801 +#define AEON_IPC_CMD_PARITY BIT(15) +#define AEON_IPC_CMD_SIZE GENMASK(10, 6) +#define AEON_IPC_CMD_OPCODE GENMASK(5, 0) + +#define IPC_CMD_NOOP 0x0 /* Do nothing */ +#define IPC_CMD_INFO 0x1 /* Get Firmware Version */ +#define IPC_CMD_SYS_CPU 0x2 /* SYS_CPU */ +#define IPC_CMD_BULK_DATA 0xa /* Pass bulk data in ipc registers. */ +#define IPC_CMD_BULK_WRITE 0xc /* Write bulk data to memory */ +#define IPC_CMD_CFG_PARAM 0x1a /* Write config parameters to memory */ +#define IPC_CMD_NG_TESTMODE 0x1b /* Set NG test mode and tone */ +#define IPC_CMD_TEMP_MON 0x15 /* Temperature monitoring function */ +#define IPC_CMD_SET_LED 0x23 /* Set led */ + +#define VEND1_IPC_STS 0x5802 +#define AEON_IPC_STS_PARITY BIT(15) +#define AEON_IPC_STS_SIZE GENMASK(14, 10) +#define AEON_IPC_STS_OPCODE GENMASK(9, 4) +#define AEON_IPC_STS_STATUS GENMASK(3, 0) +#define AEON_IPC_STS_STATUS_RCVD FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x1) +#define AEON_IPC_STS_STATUS_PROCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x2) +#define AEON_IPC_STS_STATUS_SUCCESS FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x4) +#define AEON_IPC_STS_STATUS_ERROR FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0x8) +#define AEON_IPC_STS_STATUS_BUSY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xe) +#define AEON_IPC_STS_STATUS_READY FIELD_PREP_CONST(AEON_IPC_STS_STATUS, 0xf) + +#define VEND1_IPC_DATA0 0x5808 +#define VEND1_IPC_DATA1 0x5809 +#define VEND1_IPC_DATA2 0x580a +#define VEND1_IPC_DATA3 0x580b +#define VEND1_IPC_DATA4 0x580c +#define VEND1_IPC_DATA5 0x580d +#define VEND1_IPC_DATA6 0x580e +#define VEND1_IPC_DATA7 0x580f +#define VEND1_IPC_DATA(_n) (VEND1_IPC_DATA0 + (_n)) + +/* Sub command of CMD_INFO */ +#define IPC_INFO_VERSION 0x1 + +/* Sub command of CMD_SYS_CPU */ +#define IPC_SYS_CPU_REBOOT 0x3 +#define IPC_SYS_CPU_IMAGE_OFST 0x4 +#define IPC_SYS_CPU_IMAGE_CHECK 0x5 +#define IPC_SYS_CPU_PHY_ENABLE 0x6 + +/* Sub command of CMD_CFG_PARAM */ +#define IPC_CFG_PARAM_DIRECT 0x4 + +/* CFG DIRECT sub command */ +#define IPC_CFG_PARAM_DIRECT_NG_PHYCTRL 0x1 +#define IPC_CFG_PARAM_DIRECT_CU_AN 0x2 +#define IPC_CFG_PARAM_DIRECT_SDS_PCS 0x3 +#define IPC_CFG_PARAM_DIRECT_AUTO_EEE 0x4 +#define IPC_CFG_PARAM_DIRECT_SDS_PMA 0x5 +#define IPC_CFG_PARAM_DIRECT_DPC_RA 0x6 +#define IPC_CFG_PARAM_DIRECT_DPC_PKT_CHK 0x7 +#define IPC_CFG_PARAM_DIRECT_DPC_SDS_WAIT_ETH 0x8 +#define IPC_CFG_PARAM_DIRECT_WDT 0x9 +#define IPC_CFG_PARAM_DIRECT_SDS_RESTART_AN 0x10 +#define IPC_CFG_PARAM_DIRECT_TEMP_MON 0x11 +#define IPC_CFG_PARAM_DIRECT_WOL 0x12 + +/* Sub command of CMD_TEMP_MON */ +#define IPC_CMD_TEMP_MON_GET 0x4 + +#define AS21XXX_MDIO_AN_C22 0xffe0 + +#define PHY_ID_AS21XXX 0x75009410 +/* AS21xxx ID Legend + * AS21x1xxB1 + * ^ ^^ + * | |J: Supports SyncE/PTP + * | |P: No SyncE/PTP support + * | 1: Supports 2nd Serdes + * | 2: Not 2nd Serdes support + * 0: 10G, 5G, 2.5G + * 5: 5G, 2.5G + * 2: 2.5G + */ +#define PHY_ID_AS21011JB1 0x75009402 +#define PHY_ID_AS21011PB1 0x75009412 +#define PHY_ID_AS21010JB1 0x75009422 +#define PHY_ID_AS21010PB1 0x75009432 +#define PHY_ID_AS21511JB1 0x75009442 +#define PHY_ID_AS21511PB1 0x75009452 +#define PHY_ID_AS21510JB1 0x75009462 +#define PHY_ID_AS21510PB1 0x75009472 +#define PHY_ID_AS21210JB1 0x75009482 +#define PHY_ID_AS21210PB1 0x75009492 +#define PHY_VENDOR_AEONSEMI 0x75009400 + +#define AEON_MAX_LEDS 5 +#define AEON_IPC_DELAY 10000 +#define AEON_IPC_TIMEOUT (AEON_IPC_DELAY * 100) +#define AEON_IPC_DATA_NUM_REGISTERS 8 +#define AEON_IPC_DATA_MAX (AEON_IPC_DATA_NUM_REGISTERS * sizeof(u16)) + +#define AEON_BOOT_ADDR 0x1000 +#define AEON_CPU_BOOT_ADDR 0x2000 +#define AEON_CPU_CTRL_FW_LOAD (BIT(4) | BIT(2) | BIT(1) | BIT(0)) +#define AEON_CPU_CTRL_FW_START BIT(0) + +enum as21xxx_led_event { + VEND1_LED_REG_A_EVENT_ON_10 = 0x0, + VEND1_LED_REG_A_EVENT_ON_100, + VEND1_LED_REG_A_EVENT_ON_1000, + VEND1_LED_REG_A_EVENT_ON_2500, + VEND1_LED_REG_A_EVENT_ON_5000, + VEND1_LED_REG_A_EVENT_ON_10000, + VEND1_LED_REG_A_EVENT_ON_FE_GE, + VEND1_LED_REG_A_EVENT_ON_NG, + VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX, + VEND1_LED_REG_A_EVENT_ON_COLLISION, + VEND1_LED_REG_A_EVENT_BLINK_TX, + VEND1_LED_REG_A_EVENT_BLINK_RX, + VEND1_LED_REG_A_EVENT_BLINK_ACT, + VEND1_LED_REG_A_EVENT_ON_LINK, + VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT, + VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX, + VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT, + VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT, + VEND1_LED_REG_A_EVENT_ON_NG_BLINK_FE_GE, + VEND1_LED_REG_A_EVENT_ON_FD_BLINK_COLLISION, + VEND1_LED_REG_A_EVENT_ON, + VEND1_LED_REG_A_EVENT_OFF, +}; + +struct as21xxx_led_pattern_info { + unsigned int pattern; + u16 val; +}; + +struct as21xxx_priv { + bool parity_status; + /* Protect concurrent IPC access */ + struct mutex ipc_lock; +}; + +static struct as21xxx_led_pattern_info as21xxx_led_supported_pattern[] = { + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10), + .val = VEND1_LED_REG_A_EVENT_ON_10 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_100), + .val = VEND1_LED_REG_A_EVENT_ON_100 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_1000), + .val = VEND1_LED_REG_A_EVENT_ON_1000 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_2500), + .val = VEND1_LED_REG_A_EVENT_ON_2500 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_5000), + .val = VEND1_LED_REG_A_EVENT_ON_5000 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10000), + .val = VEND1_LED_REG_A_EVENT_ON_10000 + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK), + .val = VEND1_LED_REG_A_EVENT_ON_LINK + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000), + .val = VEND1_LED_REG_A_EVENT_ON_FE_GE + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_LINK_5000) | + BIT(TRIGGER_NETDEV_LINK_10000), + .val = VEND1_LED_REG_A_EVENT_ON_NG + }, + { + .pattern = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .val = VEND1_LED_REG_A_EVENT_ON_FULL_DUPLEX + }, + { + .pattern = BIT(TRIGGER_NETDEV_TX), + .val = VEND1_LED_REG_A_EVENT_BLINK_TX + }, + { + .pattern = BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_BLINK_RX + }, + { + .pattern = BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_BLINK_ACT + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_LINK_5000) | + BIT(TRIGGER_NETDEV_LINK_10000), + .val = VEND1_LED_REG_A_EVENT_ON_LINK + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_LINK_5000) | + BIT(TRIGGER_NETDEV_LINK_10000) | + BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_ACT + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_LINK_5000) | + BIT(TRIGGER_NETDEV_LINK_10000) | + BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_ON_LINK_BLINK_RX + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_ON_FE_GE_BLINK_ACT + }, + { + .pattern = BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_LINK_5000) | + BIT(TRIGGER_NETDEV_LINK_10000) | + BIT(TRIGGER_NETDEV_TX) | + BIT(TRIGGER_NETDEV_RX), + .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT + } +}; + +static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data, + size_t size) +{ + int i, ret; + u16 val; + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, + VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_LOAD); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR, + AEON_BOOT_ADDR); + if (ret) + return ret; + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD, + 0x3ffc, 0xc000); + if (ret) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_MDIO_INDIRECT_STATUS); + if (val > 1) { + phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val); + return -EINVAL; + } + + /* Firmware is always aligned to u16 */ + for (i = 0; i < size; i += 2) { + val = data[i + 1] << 8 | data[i]; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val); + if (ret) + return ret; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR, + lower_16_bits(AEON_CPU_BOOT_ADDR)); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR, + upper_16_bits(AEON_CPU_BOOT_ADDR)); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, + VEND1_GLB_CPU_CTRL_MASK, AEON_CPU_CTRL_FW_START); +} + +static int aeon_firmware_load(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw; + const char *fw_name; + int ret; + + ret = of_property_read_string(dev->of_node, "firmware-name", + &fw_name); + if (ret) + return ret; + + ret = request_firmware(&fw, fw_name, dev); + if (ret) { + phydev_err(phydev, "failed to find FW file %s (%d)\n", + fw_name, ret); + return ret; + } + + ret = aeon_firmware_boot(phydev, fw->data, fw->size); + + release_firmware(fw); + + return ret; +} + +static bool aeon_ipc_ready(u16 val, bool parity_status) +{ + u16 status; + + if (FIELD_GET(AEON_IPC_STS_PARITY, val) != parity_status) + return false; + + status = val & AEON_IPC_STS_STATUS; + + return status != AEON_IPC_STS_STATUS_RCVD && + status != AEON_IPC_STS_STATUS_PROCESS && + status != AEON_IPC_STS_STATUS_BUSY; +} + +static int aeon_ipc_wait_cmd(struct phy_device *phydev, bool parity_status) +{ + u16 val; + + /* Exit condition logic: + * - Wait for parity bit equal + * - Wait for status success, error OR ready + */ + return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS, val, + aeon_ipc_ready(val, parity_status), + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); +} + +static int aeon_ipc_send_cmd(struct phy_device *phydev, + struct as21xxx_priv *priv, + u16 cmd, u16 *ret_sts) +{ + bool curr_parity; + int ret; + + /* The IPC sync by using a single parity bit. + * Each CMD have alternately this bit set or clear + * to understand correct flow and packet order. + */ + curr_parity = priv->parity_status; + if (priv->parity_status) + cmd |= AEON_IPC_CMD_PARITY; + + /* Always update parity for next packet */ + priv->parity_status = !priv->parity_status; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_CMD, cmd); + if (ret) + return ret; + + /* Wait for packet to be processed */ + usleep_range(AEON_IPC_DELAY, AEON_IPC_DELAY + 5000); + + /* With no ret_sts, ignore waiting for packet completion + * (ipc parity bit sync) + */ + if (!ret_sts) + return 0; + + ret = aeon_ipc_wait_cmd(phydev, curr_parity); + if (ret) + return ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_STS); + if (ret < 0) + return ret; + + *ret_sts = ret; + if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS) + return -EINVAL; + + return 0; +} + +/* If data is NULL, return 0 or negative error. + * If data not NULL, return number of Bytes received from IPC or + * a negative error. + */ +static int aeon_ipc_send_msg(struct phy_device *phydev, + u16 opcode, u16 *data, unsigned int data_len, + u16 *ret_data) +{ + struct as21xxx_priv *priv = phydev->priv; + unsigned int ret_size; + u16 cmd, ret_sts; + int ret; + int i; + + /* IPC have a max of 8 register to transfer data, + * make sure we never exceed this. + */ + if (data_len > AEON_IPC_DATA_MAX) + return -EINVAL; + + for (i = 0; i < data_len / sizeof(u16); i++) + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i), + data[i]); + + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) | + FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode); + + mutex_lock(&priv->ipc_lock); + + ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts); + if (ret) { + phydev_err(phydev, "failed to send ipc msg for %x: %d\n", + opcode, ret); + goto out; + } + + if (!data) + goto out; + + if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) { + ret = -EINVAL; + goto out; + } + + /* Prevent IPC from stack smashing the kernel. + * We can't trust IPC to return a good value and we always + * preallocate space for 16 Bytes. + */ + ret_size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts); + if (ret_size > AEON_IPC_DATA_MAX) { + ret = -EINVAL; + goto out; + } + + /* Read data from IPC data register for ret_size value from IPC */ + for (i = 0; i < DIV_ROUND_UP(ret_size, sizeof(u16)); i++) { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i)); + if (ret < 0) + goto out; + + ret_data[i] = ret; + } + + ret = ret_size; + +out: + mutex_unlock(&priv->ipc_lock); + + return ret; +} + +static int aeon_ipc_noop(struct phy_device *phydev, + struct as21xxx_priv *priv, u16 *ret_sts) +{ + u16 cmd; + + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) | + FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP); + + return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts); +} + +/* Logic to sync parity bit with IPC. + * We send 2 NOP cmd with same partity and we wait for IPC + * to handle the packet only for the second one. This way + * we make sure we are sync for every next cmd. + */ +static int aeon_ipc_sync_parity(struct phy_device *phydev, + struct as21xxx_priv *priv) +{ + u16 ret_sts; + int ret; + + mutex_lock(&priv->ipc_lock); + + /* Send NOP with no parity */ + aeon_ipc_noop(phydev, priv, NULL); + + /* Reset packet parity */ + priv->parity_status = false; + + /* Send second NOP with no parity */ + ret = aeon_ipc_noop(phydev, priv, &ret_sts); + + mutex_unlock(&priv->ipc_lock); + + /* We expect to return -EINVAL */ + if (ret != -EINVAL) + return ret; + + if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) { + phydev_err(phydev, "Invalid IPC status on sync parity: %x\n", + ret_sts); + return -EINVAL; + } + + return 0; +} + +static int aeon_ipc_get_fw_version(struct phy_device *phydev) +{ + u16 ret_data[AEON_IPC_DATA_NUM_REGISTERS], data[1]; + char fw_version[AEON_IPC_DATA_MAX + 1]; + int ret; + + data[0] = IPC_INFO_VERSION; + + ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data, + sizeof(data), ret_data); + if (ret < 0) + return ret; + + /* Make sure FW version is NULL terminated */ + memcpy(fw_version, ret_data, ret); + fw_version[ret] = '\0'; + + phydev_info(phydev, "Firmware Version: %s\n", fw_version); + + return 0; +} + +static int aeon_dpc_ra_enable(struct phy_device *phydev) +{ + u16 data[2]; + + data[0] = IPC_CFG_PARAM_DIRECT; + data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA; + + return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data, + sizeof(data), NULL); +} + +static int as21xxx_probe(struct phy_device *phydev) +{ + struct as21xxx_priv *priv; + int ret; + + priv = devm_kzalloc(&phydev->mdio.dev, + sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + phydev->priv = priv; + + ret = devm_mutex_init(&phydev->mdio.dev, + &priv->ipc_lock); + if (ret) + return ret; + + ret = aeon_ipc_sync_parity(phydev, priv); + if (ret) + return ret; + + ret = aeon_ipc_get_fw_version(phydev); + if (ret) + return ret; + + /* Enable PTP clk if not already Enabled */ + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, + VEND1_PTP_CLK_EN); + if (ret) + return ret; + + return aeon_dpc_ra_enable(phydev); +} + +static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) +{ + int status; + + /* Normal C22 BMCR report inconsistent data, use + * the mapped C22 in C45 to have more consistent link info. + */ + *bmcr = phy_read_mmd(phydev, MDIO_MMD_AN, + AS21XXX_MDIO_AN_C22 + MII_BMCR); + if (*bmcr < 0) + return *bmcr; + + /* Autoneg is being started, therefore disregard current + * link status and report link as down. + */ + if (*bmcr & BMCR_ANRESTART) { + phydev->link = 0; + return 0; + } + + status = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (status < 0) + return status; + + phydev->link = !!(status & MDIO_STAT1_LSTATUS); + + return 0; +} + +static int as21xxx_read_c22_lpa(struct phy_device *phydev) +{ + int lpagb; + + /* MII_STAT1000 are only filled in the mapped C22 + * in C45, use that to fill lpagb values and check. + */ + lpagb = phy_read_mmd(phydev, MDIO_MMD_AN, + AS21XXX_MDIO_AN_C22 + MII_STAT1000); + if (lpagb < 0) + return lpagb; + + if (lpagb & LPA_1000MSFAIL) { + int adv = phy_read_mmd(phydev, MDIO_MMD_AN, + AS21XXX_MDIO_AN_C22 + MII_CTRL1000); + + if (adv < 0) + return adv; + + if (adv & CTL1000_ENABLE_MASTER) + phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n"); + else + phydev_err(phydev, "Master/Slave resolution failed\n"); + return -ENOLINK; + } + + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, + lpagb); + + return 0; +} + +static int as21xxx_read_status(struct phy_device *phydev) +{ + int bmcr, old_link = phydev->link; + int ret; + + ret = as21xxx_read_link(phydev, &bmcr); + if (ret) + return ret; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (phydev->autoneg == AUTONEG_ENABLE) { + ret = genphy_c45_read_lpa(phydev); + if (ret) + return ret; + + ret = as21xxx_read_c22_lpa(phydev); + if (ret) + return ret; + + phy_resolve_aneg_linkmode(phydev); + } else { + int speed; + + linkmode_zero(phydev->lp_advertising); + + speed = phy_read_mmd(phydev, MDIO_MMD_VEND1, + VEND1_SPEED_STATUS); + if (speed < 0) + return speed; + + switch (speed & VEND1_SPEED_STATUS) { + case VEND1_SPEED_10000: + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + break; + case VEND1_SPEED_5000: + phydev->speed = SPEED_5000; + phydev->duplex = DUPLEX_FULL; + break; + case VEND1_SPEED_2500: + phydev->speed = SPEED_2500; + phydev->duplex = DUPLEX_FULL; + break; + case VEND1_SPEED_1000: + phydev->speed = SPEED_1000; + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + break; + case VEND1_SPEED_100: + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + break; + case VEND1_SPEED_10: + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_FULL; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int as21xxx_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u16 val = VEND1_LED_REG_A_EVENT_OFF; + + if (index > AEON_MAX_LEDS) + return -EINVAL; + + if (value) + val = VEND1_LED_REG_A_EVENT_ON; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, + VEND1_LED_REG(index), + VEND1_LED_REG_A_EVENT, + FIELD_PREP(VEND1_LED_REG_A_EVENT, val)); +} + +static int as21xxx_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + int i; + + if (index > AEON_MAX_LEDS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) + if (rules == as21xxx_led_supported_pattern[i].pattern) + return 0; + + return -EOPNOTSUPP; +} + +static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int i, val; + + if (index > AEON_MAX_LEDS) + return -EINVAL; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index)); + if (val < 0) + return val; + + val = FIELD_GET(VEND1_LED_REG_A_EVENT, val); + for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) + if (val == as21xxx_led_supported_pattern[i].val) { + *rules = as21xxx_led_supported_pattern[i].pattern; + return 0; + } + + /* Should be impossible */ + return -EINVAL; +} + +static int as21xxx_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 val = 0; + int i; + + if (index > AEON_MAX_LEDS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(as21xxx_led_supported_pattern); i++) + if (rules == as21xxx_led_supported_pattern[i].pattern) { + val = as21xxx_led_supported_pattern[i].val; + break; + } + + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, + VEND1_LED_REG(index), + VEND1_LED_REG_A_EVENT, + FIELD_PREP(VEND1_LED_REG_A_EVENT, val)); +} + +static int as21xxx_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool led_active_low = false; + u16 mask, val = 0; + u32 mode; + + if (index > AEON_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + led_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: /* default mode */ + led_active_low = false; + break; + default: + return -EINVAL; + } + } + + mask = VEND1_GLB_CPU_CTRL_LED_POLARITY(index); + if (led_active_low) + val = VEND1_GLB_CPU_CTRL_LED_POLARITY(index); + + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, + VEND1_GLB_REG_CPU_CTRL, + mask, val); +} + +static int as21xxx_match_phy_device(struct phy_device *phydev, + const struct phy_driver *phydrv) +{ + struct as21xxx_priv *priv; + u16 ret_sts; + u32 phy_id; + int ret; + + /* Skip PHY that are not AS21xxx or already have firmware loaded */ + if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX) + return genphy_match_phy_device(phydev, (struct phy_driver *)phydrv); + + /* Read PHY ID to handle firmware just loaded */ + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1); + if (ret < 0) + return ret; + phy_id = ret << 16; + + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2); + if (ret < 0) + return ret; + phy_id |= ret; + + /* With PHY ID not the generic AS21xxx one assume + * the firmware just loaded + */ + if (phy_id != PHY_ID_AS21XXX) + return phy_id == phydrv->phy_id; + + /* Allocate temp priv and load the firmware */ + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->ipc_lock); + + ret = aeon_firmware_load(phydev); + if (ret) + goto out; + + /* Sync parity... */ + ret = aeon_ipc_sync_parity(phydev, priv); + if (ret) + goto out; + + /* ...and send a third NOOP cmd to wait for firmware finish loading */ + ret = aeon_ipc_noop(phydev, priv, &ret_sts); + if (ret) + goto out; + +out: + mutex_destroy(&priv->ipc_lock); + kfree(priv); + + /* Return can either be 0 or a negative error code. + * Returning 0 here means THIS is NOT a suitable PHY. + * + * For the specific case of the generic Aeonsemi PHY ID that + * needs the firmware the be loaded first to have a correct PHY ID, + * this is OK as a matching PHY ID will be found right after. + * This relies on the driver probe order where the first PHY driver + * probed is the generic one. + */ + return ret; +} + +static struct phy_driver as21xxx_drivers[] = { + { + /* PHY expose in C45 as 0x7500 0x9410 + * before firmware is loaded. + * This driver entry must be attempted first to load + * the firmware and thus update the ID registers. + */ + PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), + .name = "Aeonsemi AS21xxx", + .match_phy_device = as21xxx_match_phy_device, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1), + .name = "Aeonsemi AS21011JB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1), + .name = "Aeonsemi AS21011PB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1), + .name = "Aeonsemi AS21010PB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1), + .name = "Aeonsemi AS21010JB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1), + .name = "Aeonsemi AS21210PB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1), + .name = "Aeonsemi AS21510JB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1), + .name = "Aeonsemi AS21510PB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1), + .name = "Aeonsemi AS21511JB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1), + .name = "Aeonsemi AS21210JB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1), + .name = "Aeonsemi AS21511PB1", + .probe = as21xxx_probe, + .match_phy_device = as21xxx_match_phy_device, + .read_status = as21xxx_read_status, + .led_brightness_set = as21xxx_led_brightness_set, + .led_hw_is_supported = as21xxx_led_hw_is_supported, + .led_hw_control_set = as21xxx_led_hw_control_set, + .led_hw_control_get = as21xxx_led_hw_control_get, + .led_polarity_set = as21xxx_led_polarity_set, + }, +}; +module_phy_driver(as21xxx_drivers); + +static struct mdio_device_id __maybe_unused as21xxx_tbl[] = { + { PHY_ID_MATCH_VENDOR(PHY_VENDOR_AEONSEMI) }, + { } +}; +MODULE_DEVICE_TABLE(mdio, as21xxx_tbl); + +MODULE_DESCRIPTION("Aeonsemi AS21xxx PHY driver"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); -- 2.51.0 From 1eef9ac782f05b464534e831280399d76c3eba32 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:03 +0200 Subject: [PATCH 166/517] net: dsa: Move KS8995 to the DSA subsystem By reading the datasheets for the KS8995 it is obvious that this is a 100 Mbit DSA switch. Let us start the refactoring by moving it to the DSA subsystem to preserve development history. Verified that the chip still probes the same after this patch provided CONFIG_HAVE_NET_DSA, CONFIG_NET_DSA and CONFIG_DSA_KS8995 are selected. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-1-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/Kconfig | 7 +++++++ drivers/net/dsa/Makefile | 1 + drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} | 0 drivers/net/phy/Kconfig | 4 ---- drivers/net/phy/Makefile | 1 - 5 files changed, 8 insertions(+), 5 deletions(-) rename drivers/net/{phy/spi_ks8995.c => dsa/ks8995.c} (100%) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 2d10b4d6cfbb..4367cbdb92d5 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -98,6 +98,13 @@ config NET_DSA_RZN1_A5PSW This driver supports the A5PSW switch, which is embedded in Renesas RZ/N1 SoC. +config NET_DSA_KS8995 + tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" + depends on SPI + help + This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet + switches, managed over SPI. + config NET_DSA_SMSC_LAN9303 tristate select NET_DSA_TAG_LAN9303 diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index cb9a97340e58..23dbdf1a36a8 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP) += dsa_loop.o ifdef CONFIG_NET_DSA_LOOP obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o endif +obj-$(CONFIG_NET_DSA_KS8995) += ks8995.o obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/dsa/ks8995.c similarity index 100% rename from drivers/net/phy/spi_ks8995.c rename to drivers/net/dsa/ks8995.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 01cc31817357..bf7c34402e74 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -443,7 +443,3 @@ config XILINX_GMII2RGMII Ethernet physical media devices and the Gigabit Ethernet controller. endif # PHYLIB - -config MICREL_KS8995MA - tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" - depends on SPI diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 768d1e8ebf80..a9080b8d604e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o obj-y += mediatek/ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o -obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MICROCHIP_PHY) += microchip.o obj-$(CONFIG_MICROCHIP_T1_PHY) += microchip_t1.o -- 2.51.0 From b5868880d0272cf14e28b438c869027c53ce97e8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:04 +0200 Subject: [PATCH 167/517] net: dsa: ks8995: Add proper RESET delay According to the datasheet we need to wait 100us before accessing any registers in the KS8995 after a reset de-assertion. Add this delay, if and only if we obtained a GPIO descriptor, otherwise it is just a pointless delay. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-2-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ks8995.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index 7196e927c2cd..ab266b3ead02 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -438,9 +438,15 @@ static int ks8995_probe(struct spi_device *spi) if (err) return err; - /* de-assert switch reset */ - /* FIXME: this likely requires a delay */ - gpiod_set_value_cansleep(ks->reset_gpio, 0); + if (ks->reset_gpio) { + /* + * If a reset line was obtained, wait for 100us after + * de-asserting RESET before accessing any registers, see + * the KS8995MA datasheet, page 44. + */ + gpiod_set_value_cansleep(ks->reset_gpio, 0); + udelay(100); + } spi_set_drvdata(spi, ks); -- 2.51.0 From eb531dff7bf14239f05748e1f299a346633f6165 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:05 +0200 Subject: [PATCH 168/517] net: dsa: ks8995: Delete sysfs register access There is some sysfs file to read and write registers randomly in the ks8995 driver. The contemporary way to achieve the same thing is to implement regmap abstractions, if needed. Delete this and implement regmap later if we want to be able to inspect individual registers. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-3-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ks8995.c | 48 ---------------------------------------- 1 file changed, 48 deletions(-) diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index ab266b3ead02..45f01c81d0b8 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -140,7 +140,6 @@ struct ks8995_switch { struct spi_device *spi; struct mutex lock; struct gpio_desc *reset_gpio; - struct bin_attribute regs_attr; const struct ks8995_chip_params *chip; int revision_id; }; @@ -288,30 +287,6 @@ static int ks8995_reset(struct ks8995_switch *ks) return ks8995_start(ks); } -static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct ks8995_switch *ks8995; - - dev = kobj_to_dev(kobj); - ks8995 = dev_get_drvdata(dev); - - return ks8995_read(ks8995, buf, off, count); -} - -static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct ks8995_switch *ks8995; - - dev = kobj_to_dev(kobj); - ks8995 = dev_get_drvdata(dev); - - return ks8995_write(ks8995, buf, off, count); -} - /* ks8995_get_revision - get chip revision * @ks: pointer to switch instance * @@ -395,16 +370,6 @@ static int ks8995_get_revision(struct ks8995_switch *ks) return err; } -static const struct bin_attribute ks8995_registers_attr = { - .attr = { - .name = "registers", - .mode = 0600, - }, - .size = KS8995_REGS_SIZE, - .read = ks8995_registers_read, - .write = ks8995_registers_write, -}; - /* ------------------------------------------------------------------------ */ static int ks8995_probe(struct spi_device *spi) { @@ -462,21 +427,10 @@ static int ks8995_probe(struct spi_device *spi) if (err) return err; - memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr)); - ks->regs_attr.size = ks->chip->regs_size; - err = ks8995_reset(ks); if (err) return err; - sysfs_attr_init(&ks->regs_attr.attr); - err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr); - if (err) { - dev_err(&spi->dev, "unable to create sysfs file, err=%d\n", - err); - return err; - } - dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", ks->chip->name, ks->chip->chip_id, ks->revision_id); @@ -487,8 +441,6 @@ static void ks8995_remove(struct spi_device *spi) { struct ks8995_switch *ks = spi_get_drvdata(spi); - sysfs_remove_bin_file(&spi->dev.kobj, &ks->regs_attr); - /* assert reset */ gpiod_set_value_cansleep(ks->reset_gpio, 1); } -- 2.51.0 From 20f057c95e429fc9d1a85736837129570f4714b1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 13 Aug 2025 23:43:06 +0200 Subject: [PATCH 169/517] net: dsa: ks8995: Add basic switch set-up We start to extend the KS8995 driver by simply registering it as a DSA device and implementing a few switch callbacks for STP set-up and such to begin with. No special tags or other advanced stuff: we use DSA_TAG_NONE and rely on the default set-up in the switch with the special DSA tags turned off. This makes the switch wire up properly to all its PHY's and simple bridge traffic works properly. After this the bridge DT bindings are respected, ports and their PHYs get connected to the switch and react appropriately through the phylib when cables are plugged in etc. Tested like this in a hacky OpenWrt image: Bring up conduit interface manually: ixp4xx_eth c8009000.ethernet eth0: eth0: link up, speed 100 Mb/s, full duplex spi-ks8995 spi0.0: enable port 0 spi-ks8995 spi0.0: set KS8995_REG_PC2 for port 0 to 06 spi-ks8995 spi0.0 lan1: configuring for phy/mii link mode spi-ks8995 spi0.0 lan1: Link is Up - 100Mbps/Full - flow control rx/tx PING 169.254.1.1 (169.254.1.1): 56 data bytes 64 bytes from 169.254.1.1: seq=0 ttl=64 time=1.629 ms 64 bytes from 169.254.1.1: seq=1 ttl=64 time=0.951 ms I also tested SSH from the device to the host and it works fine. It also works fine to ping the device from the host and to SSH into the device from the host. This brings the ks8995 driver to a reasonable state where it can be used from the current device tree bindings and the existing device trees in the kernel. Signed-off-by: Linus Walleij Reviewed-by: Andrew Lunn Link: https://patch.msgid.link/20250813-ks8995-to-dsa-v1-4-75c359ede3a5@linaro.org Signed-off-by: Jakub Kicinski --- drivers/net/dsa/Kconfig | 1 + drivers/net/dsa/ks8995.c | 398 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 396 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 4367cbdb92d5..b7b473e3fc02 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -101,6 +101,7 @@ config NET_DSA_RZN1_A5PSW config NET_DSA_KS8995 tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches" depends on SPI + select NET_DSA_TAG_NONE help This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet switches, managed over SPI. diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c index 45f01c81d0b8..364e8d16c936 100644 --- a/drivers/net/dsa/ks8995.c +++ b/drivers/net/dsa/ks8995.c @@ -3,6 +3,7 @@ * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches * * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2025 Linus Walleij * * This file was based on: drivers/spi/at25.c * Copyright (C) 2006 David Brownell @@ -10,6 +11,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include #include #include #include @@ -17,8 +21,8 @@ #include #include #include - #include +#include #define DRV_VERSION "0.1.1" #define DRV_DESC "Micrel KS8995 Ethernet switch SPI driver" @@ -29,18 +33,59 @@ #define KS8995_REG_ID1 0x01 /* Chip ID1 */ #define KS8995_REG_GC0 0x02 /* Global Control 0 */ + +#define KS8995_GC0_P5_PHY BIT(3) /* Port 5 PHY enabled */ + #define KS8995_REG_GC1 0x03 /* Global Control 1 */ #define KS8995_REG_GC2 0x04 /* Global Control 2 */ + +#define KS8995_GC2_HUGE BIT(2) /* Huge packet support */ +#define KS8995_GC2_LEGAL BIT(1) /* Legal size override */ + #define KS8995_REG_GC3 0x05 /* Global Control 3 */ #define KS8995_REG_GC4 0x06 /* Global Control 4 */ + +#define KS8995_GC4_10BT BIT(4) /* Force switch to 10Mbit */ +#define KS8995_GC4_MII_FLOW BIT(5) /* MII full-duplex flow control enable */ +#define KS8995_GC4_MII_HD BIT(6) /* MII half-duplex mode enable */ + #define KS8995_REG_GC5 0x07 /* Global Control 5 */ #define KS8995_REG_GC6 0x08 /* Global Control 6 */ #define KS8995_REG_GC7 0x09 /* Global Control 7 */ #define KS8995_REG_GC8 0x0a /* Global Control 8 */ #define KS8995_REG_GC9 0x0b /* Global Control 9 */ -#define KS8995_REG_PC(p, r) ((0x10 * p) + r) /* Port Control */ -#define KS8995_REG_PS(p, r) ((0x10 * p) + r + 0xe) /* Port Status */ +#define KS8995_GC9_SPECIAL BIT(0) /* Special tagging mode (DSA) */ + +/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */ +#define KS8995_REG_PC(p, r) (0x10 + (0x10 * (p)) + (r)) /* Port Control */ +#define KS8995_REG_PS(p, r) (0x1e + (0x10 * (p)) + (r)) /* Port Status */ + +#define KS8995_REG_PC0 0x00 /* Port Control 0 */ +#define KS8995_REG_PC1 0x01 /* Port Control 1 */ +#define KS8995_REG_PC2 0x02 /* Port Control 2 */ +#define KS8995_REG_PC3 0x03 /* Port Control 3 */ +#define KS8995_REG_PC4 0x04 /* Port Control 4 */ +#define KS8995_REG_PC5 0x05 /* Port Control 5 */ +#define KS8995_REG_PC6 0x06 /* Port Control 6 */ +#define KS8995_REG_PC7 0x07 /* Port Control 7 */ +#define KS8995_REG_PC8 0x08 /* Port Control 8 */ +#define KS8995_REG_PC9 0x09 /* Port Control 9 */ +#define KS8995_REG_PC10 0x0a /* Port Control 10 */ +#define KS8995_REG_PC11 0x0b /* Port Control 11 */ +#define KS8995_REG_PC12 0x0c /* Port Control 12 */ +#define KS8995_REG_PC13 0x0d /* Port Control 13 */ + +#define KS8995_PC0_TAG_INS BIT(2) /* Enable tag insertion on port */ +#define KS8995_PC0_TAG_REM BIT(1) /* Enable tag removal on port */ +#define KS8995_PC0_PRIO_EN BIT(0) /* Enable priority handling */ + +#define KS8995_PC2_TXEN BIT(2) /* Enable TX on port */ +#define KS8995_PC2_RXEN BIT(1) /* Enable RX on port */ +#define KS8995_PC2_LEARN_DIS BIT(0) /* Disable learning on port */ + +#define KS8995_PC13_TXDIS BIT(6) /* Disable transmitter */ +#define KS8995_PC13_PWDN BIT(3) /* Power down */ #define KS8995_REG_TPC0 0x60 /* TOS Priority Control 0 */ #define KS8995_REG_TPC1 0x61 /* TOS Priority Control 1 */ @@ -91,6 +136,8 @@ #define KS8995_CMD_WRITE 0x02U #define KS8995_CMD_READ 0x03U +#define KS8995_CPU_PORT 4 +#define KS8995_NUM_PORTS 5 /* 5 ports including the CPU port */ #define KS8995_RESET_DELAY 10 /* usec */ enum ks8995_chip_variant { @@ -138,10 +185,13 @@ static const struct ks8995_chip_params ks8995_chip[] = { struct ks8995_switch { struct spi_device *spi; + struct device *dev; + struct dsa_switch *ds; struct mutex lock; struct gpio_desc *reset_gpio; const struct ks8995_chip_params *chip; int revision_id; + unsigned int max_mtu[KS8995_NUM_PORTS]; }; static const struct spi_device_id ks8995_id[] = { @@ -370,6 +420,327 @@ static int ks8995_get_revision(struct ks8995_switch *ks) return err; } +static int ks8995_check_config(struct ks8995_switch *ks) +{ + int ret; + u8 val; + + ret = ks8995_read_reg(ks, KS8995_REG_GC0, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC0\n"); + return ret; + } + + dev_dbg(ks->dev, "port 5 PHY %senabled\n", + (val & KS8995_GC0_P5_PHY) ? "" : "not "); + + val |= KS8995_GC0_P5_PHY; + ret = ks8995_write_reg(ks, KS8995_REG_GC0, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC0\n"); + + dev_dbg(ks->dev, "set KS8995_REG_GC0 to 0x%02x\n", val); + + return 0; +} + +static void +ks8995_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void +ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ks8995_switch *ks = dp->ds->priv; + int port = dp->index; + int ret; + u8 val; + + /* Allow forcing the mode on the fixed CPU port, no autonegotiation. + * We assume autonegotiation works on the PHY-facing ports. + */ + if (port != KS8995_CPU_PORT) + return; + + dev_dbg(ks->dev, "MAC link up on CPU port (%d)\n", port); + + ret = ks8995_read_reg(ks, KS8995_REG_GC4, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC4\n"); + return; + } + + /* Conjure port config */ + switch (speed) { + case SPEED_10: + dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); + val |= KS8995_GC4_10BT; + break; + case SPEED_100: + default: + dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n"); + val &= ~KS8995_GC4_10BT; + break; + } + + if (duplex == DUPLEX_HALF) { + dev_dbg(ks->dev, "set switch MII to half duplex\n"); + val |= KS8995_GC4_MII_HD; + } else { + dev_dbg(ks->dev, "set switch MII to full duplex\n"); + val &= ~KS8995_GC4_MII_HD; + } + + dev_dbg(ks->dev, "set KS8995_REG_GC4 to %02x\n", val); + + /* Enable the CPU port */ + ret = ks8995_write_reg(ks, KS8995_REG_GC4, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC4\n"); +} + +static void +ks8995_mac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct dsa_port *dp = dsa_phylink_to_port(config); + struct ks8995_switch *ks = dp->ds->priv; + int port = dp->index; + + if (port != KS8995_CPU_PORT) + return; + + dev_dbg(ks->dev, "MAC link down on CPU port (%d)\n", port); + + /* Disable the CPU port */ +} + +static const struct phylink_mac_ops ks8995_phylink_mac_ops = { + .mac_config = ks8995_mac_config, + .mac_link_up = ks8995_mac_link_up, + .mac_link_down = ks8995_mac_link_down, +}; + +static enum +dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds, + int port, + enum dsa_tag_protocol mp) +{ + /* This switch actually uses the 6 byte KS8995 protocol */ + return DSA_TAG_PROTO_NONE; +} + +static int ks8995_setup(struct dsa_switch *ds) +{ + return 0; +} + +static int ks8995_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ks8995_switch *ks = ds->priv; + + dev_dbg(ks->dev, "enable port %d\n", port); + + return 0; +} + +static void ks8995_port_disable(struct dsa_switch *ds, int port) +{ + struct ks8995_switch *ks = ds->priv; + + dev_dbg(ks->dev, "disable port %d\n", port); +} + +static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + /* We support enabling/disabling learning */ + if (flags.mask & ~(BR_LEARNING)) + return -EINVAL; + + return 0; +} + +static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct ks8995_switch *ks = ds->priv; + int ret; + u8 val; + + if (flags.mask & BR_LEARNING) { + ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); + return ret; + } + + if (flags.val & BR_LEARNING) + val &= ~KS8995_PC2_LEARN_DIS; + else + val |= KS8995_PC2_LEARN_DIS; + + ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); + if (ret) { + dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); + return ret; + } + } + + return 0; +} + +static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +{ + struct ks8995_switch *ks = ds->priv; + int ret; + u8 val; + + ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port); + return; + } + + /* Set the bits for the different STP states in accordance with + * the datasheet, pages 36-37 "Spanning tree support". + */ + switch (state) { + case BR_STATE_DISABLED: + case BR_STATE_BLOCKING: + case BR_STATE_LISTENING: + val &= ~KS8995_PC2_TXEN; + val &= ~KS8995_PC2_RXEN; + val |= KS8995_PC2_LEARN_DIS; + break; + case BR_STATE_LEARNING: + val &= ~KS8995_PC2_TXEN; + val &= ~KS8995_PC2_RXEN; + val &= ~KS8995_PC2_LEARN_DIS; + break; + case BR_STATE_FORWARDING: + val |= KS8995_PC2_TXEN; + val |= KS8995_PC2_RXEN; + val &= ~KS8995_PC2_LEARN_DIS; + break; + default: + dev_err(ks->dev, "unknown bridge state requested\n"); + return; + } + + ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val); + if (ret) { + dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port); + return; + } + + dev_dbg(ks->dev, "set KS8995_REG_PC2 for port %d to %02x\n", port, val); +} + +static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port, + struct phylink_config *config) +{ + unsigned long *interfaces = config->supported_interfaces; + + if (port == KS8995_CPU_PORT) + __set_bit(PHY_INTERFACE_MODE_MII, interfaces); + + if (port <= 3) { + /* Internal PHYs */ + __set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces); + /* phylib default */ + __set_bit(PHY_INTERFACE_MODE_MII, interfaces); + } + + config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; +} + +/* Huge packet support up to 1916 byte packages "inclusive" + * which means that tags are included. If the bit is not set + * it is 1536 bytes "inclusive". We present the length without + * tags or ethernet headers. The setting affects all ports. + */ +static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +{ + struct ks8995_switch *ks = ds->priv; + unsigned int max_mtu; + int ret; + u8 val; + int i; + + ks->max_mtu[port] = new_mtu; + + /* Roof out the MTU for the entire switch to the greatest + * common denominator: the biggest set for any one port will + * be the biggest MTU for the switch. + */ + max_mtu = ETH_DATA_LEN; + for (i = 0; i < KS8995_NUM_PORTS; i++) { + if (ks->max_mtu[i] > max_mtu) + max_mtu = ks->max_mtu[i]; + } + + /* Translate to layer 2 size. + * Add ethernet and (possible) VLAN headers, and checksum to the size. + * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes. + */ + max_mtu += VLAN_ETH_HLEN; + max_mtu += ETH_FCS_LEN; + + ret = ks8995_read_reg(ks, KS8995_REG_GC2, &val); + if (ret) { + dev_err(ks->dev, "failed to read KS8995_REG_GC2\n"); + return ret; + } + + if (max_mtu <= 1522) { + val &= ~KS8995_GC2_HUGE; + val &= ~KS8995_GC2_LEGAL; + } else if (max_mtu > 1522 && max_mtu <= 1536) { + /* This accepts packets up to 1536 bytes */ + val &= ~KS8995_GC2_HUGE; + val |= KS8995_GC2_LEGAL; + } else { + /* This accepts packets up to 1916 bytes */ + val |= KS8995_GC2_HUGE; + val |= KS8995_GC2_LEGAL; + } + + dev_dbg(ks->dev, "new max MTU %d bytes (inclusive)\n", max_mtu); + + ret = ks8995_write_reg(ks, KS8995_REG_GC2, val); + if (ret) + dev_err(ks->dev, "failed to set KS8995_REG_GC2\n"); + + return ret; +} + +static int ks8995_get_max_mtu(struct dsa_switch *ds, int port) +{ + return 1916 - ETH_HLEN - ETH_FCS_LEN; +} + +static const struct dsa_switch_ops ks8995_ds_ops = { + .get_tag_protocol = ks8995_get_tag_protocol, + .setup = ks8995_setup, + .port_pre_bridge_flags = ks8995_port_pre_bridge_flags, + .port_bridge_flags = ks8995_port_bridge_flags, + .port_enable = ks8995_port_enable, + .port_disable = ks8995_port_disable, + .port_stp_state_set = ks8995_port_stp_state_set, + .port_change_mtu = ks8995_change_mtu, + .port_max_mtu = ks8995_get_max_mtu, + .phylink_get_caps = ks8995_phylink_get_caps, +}; + /* ------------------------------------------------------------------------ */ static int ks8995_probe(struct spi_device *spi) { @@ -388,6 +759,7 @@ static int ks8995_probe(struct spi_device *spi) mutex_init(&ks->lock); ks->spi = spi; + ks->dev = &spi->dev; ks->chip = &ks8995_chip[variant]; ks->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", @@ -434,6 +806,25 @@ static int ks8995_probe(struct spi_device *spi) dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n", ks->chip->name, ks->chip->chip_id, ks->revision_id); + err = ks8995_check_config(ks); + if (err) + return err; + + ks->ds = devm_kzalloc(&spi->dev, sizeof(*ks->ds), GFP_KERNEL); + if (!ks->ds) + return -ENOMEM; + + ks->ds->dev = &spi->dev; + ks->ds->num_ports = KS8995_NUM_PORTS; + ks->ds->ops = &ks8995_ds_ops; + ks->ds->phylink_mac_ops = &ks8995_phylink_mac_ops; + ks->ds->priv = ks; + + err = dsa_register_switch(ks->ds); + if (err) + return dev_err_probe(&spi->dev, err, + "unable to register DSA switch\n"); + return 0; } @@ -441,6 +832,7 @@ static void ks8995_remove(struct spi_device *spi) { struct ks8995_switch *ks = spi_get_drvdata(spi); + dsa_unregister_switch(ks->ds); /* assert reset */ gpiod_set_value_cansleep(ks->reset_gpio, 1); } -- 2.51.0 From c5a714e79548a715750999c9547a52a486e0e851 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 10 Oct 2024 21:35:42 +0200 Subject: [PATCH 170/517] hwmon: Add static visibility member to struct hwmon_ops Several drivers return the same static value in their is_visible callback, what results in code duplication. Therefore add an option for drivers to specify a static visibility directly. Signed-off-by: Heiner Kallweit Message-ID: <89690b81-2c73-47ae-9ae9-45c77b45ca0c@gmail.com> groeck: Renamed hwmon_ops_is_visible -> hwmon_is_visible Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 19 +++++++++++++++---- include/linux/hwmon.h | 5 ++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9c35c4d0369d..49b366254529 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -145,6 +145,17 @@ static const struct class hwmon_class = { static DEFINE_IDA(hwmon_ida); +static umode_t hwmon_is_visible(const struct hwmon_ops *ops, + const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (ops->visible) + return ops->visible; + + return ops->is_visible(drvdata, type, attr, channel); +} + /* Thermal zone handling */ /* @@ -267,8 +278,8 @@ static int hwmon_thermal_register_sensors(struct device *dev) int err; if (!(info[i]->config[j] & HWMON_T_INPUT) || - !chip->ops->is_visible(drvdata, hwmon_temp, - hwmon_temp_input, j)) + !hwmon_is_visible(chip->ops, drvdata, hwmon_temp, + hwmon_temp_input, j)) continue; err = hwmon_thermal_add_sensor(dev, j); @@ -506,7 +517,7 @@ static struct attribute *hwmon_genattr(const void *drvdata, const char *name; bool is_string = is_string_attr(type, attr); - mode = ops->is_visible(drvdata, type, attr, index); + mode = hwmon_is_visible(ops, drvdata, type, attr, index); if (!mode) return ERR_PTR(-ENOENT); @@ -1033,7 +1044,7 @@ hwmon_device_register_with_info(struct device *dev, const char *name, if (!dev || !name || !chip) return ERR_PTR(-EINVAL); - if (!chip->ops || !chip->ops->is_visible || !chip->info) + if (!chip->ops || !(chip->ops->visible || chip->ops->is_visible) || !chip->info) return ERR_PTR(-EINVAL); return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 5c6a421ad580..3a63dff62d03 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -368,7 +368,9 @@ enum hwmon_intrusion_attributes { /** * struct hwmon_ops - hwmon device operations - * @is_visible: Callback to return attribute visibility. Mandatory. + * @visible: Static visibility. If non-zero, 'is_visible' is ignored. + * @is_visible: Callback to return attribute visibility. Mandatory unless + * 'visible' is non-zero. * Parameters are: * @const void *drvdata: * Pointer to driver-private data structure passed @@ -412,6 +414,7 @@ enum hwmon_intrusion_attributes { * The function returns 0 on success or a negative error number. */ struct hwmon_ops { + umode_t visible; umode_t (*is_visible)(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel); int (*read)(struct device *dev, enum hwmon_sensor_types type, -- 2.51.0 From e49d38bee83d91a1cf8d4e8fa67b2bc455ddd028 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 6 Sep 2024 10:25:07 +0200 Subject: [PATCH 171/517] dt-bindings: clocks: add binding for gated-fixed-clocks In contrast to fixed clocks that are described as ungateable, boards sometimes use additional oscillators for things like PCIe reference clocks, that need actual supplies to get enabled and enable-gpios to be toggled for them to work. This adds a binding for such oscillators that are not configurable themself, but need to handle supplies for them to work. In schematics they often can be seen as ---------------- Enable - | 100MHz,3.3V, | - VDD | 3225 | GND - | | - OUT ---------------- or similar. The enable pin might be separate but can also just be tied to the vdd supply, hence it is optional in the binding. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring (Arm) Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20240906082511.2963890-2-heiko@sntech.de Signed-off-by: Stephen Boyd --- .../bindings/clock/gated-fixed-clock.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml new file mode 100644 index 000000000000..d3e0faf3c64d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Gated Fixed clock + +maintainers: + - Heiko Stuebner + +properties: + compatible: + const: gated-fixed-clock + + "#clock-cells": + const: 0 + + clock-frequency: true + + clock-output-names: + maxItems: 1 + + enable-gpios: + description: + Contains a single GPIO specifier for the GPIO that enables and disables + the oscillator. + maxItems: 1 + + vdd-supply: + description: handle of the regulator that provides the supply voltage + +required: + - compatible + - "#clock-cells" + - clock-frequency + - vdd-supply + +additionalProperties: false + +examples: + - | + clock-1000000000 { + compatible = "gated-fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + vdd-supply = <®_vdd>; + }; +... -- 2.51.0 From a821d7186c5d4f7289edfbcc0091f744729e0880 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 6 Sep 2024 10:25:08 +0200 Subject: [PATCH 172/517] clk: clk-gpio: update documentation for gpio-gate clock The main documentation block seems to be from a time before the driver handled sleeping and non-sleeping gpios and with that change it seems updating the doc was overlooked. So do that now. Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20240906082511.2963890-3-heiko@sntech.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 5b114043771d..98415782f9a2 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -22,8 +22,9 @@ * DOC: basic gpio gated clock which can be enabled and disabled * with gpio output * Traits of this clock: - * prepare - clk_(un)prepare only ensures parent is (un)prepared - * enable - clk_enable and clk_disable are functional & control gpio + * prepare - clk_(un)prepare are functional and control a gpio that can sleep + * enable - clk_enable and clk_disable are functional & control + * non-sleeping gpio * rate - inherits rate from parent. No clk_set_rate support * parent - fixed parent. No clk_set_parent support */ -- 2.51.0 From 1d8ecd6adc09ddf3d97c8d3db6c13fc109f9f24d Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 6 Sep 2024 10:25:09 +0200 Subject: [PATCH 173/517] clk: clk-gpio: use dev_err_probe for gpio-get failure This is a real driver and dev_err_probe will hide the distinction between EPROBE_DEFER and other errors automatically, so there is no need to open-code this. Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20240906082511.2963890-4-heiko@sntech.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 98415782f9a2..cda362a2eca0 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -200,7 +200,6 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) struct gpio_desc *gpiod; struct clk_hw *hw; bool is_mux; - int ret; is_mux = of_device_is_compatible(node, "gpio-mux-clock"); @@ -212,17 +211,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) gpio_name = is_mux ? "select" : "enable"; gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) { - ret = PTR_ERR(gpiod); - if (ret == -EPROBE_DEFER) - pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", - node, __func__); - else - pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", - node, __func__, - gpio_name); - return ret; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), + "Can't get '%s' named GPIO property\n", gpio_name); if (is_mux) hw = clk_hw_register_gpio_mux(dev, gpiod); -- 2.51.0 From ee31cfe9b43e3d8aa62c15b695cdb655bf428db5 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 6 Sep 2024 10:25:10 +0200 Subject: [PATCH 174/517] clk: clk-gpio: add driver for gated-fixed-clocks In contrast to fixed clocks that are described as ungateable, boards sometimes use additional oscillators for things like PCIe reference clocks, that need actual supplies to get enabled and enable-gpios to be toggled for them to work. This adds a driver for those generic gated-fixed-clocks that can show up in schematics looking like ---------------- Enable - | 100MHz,3.3V, | - VDD | 3225 | GND - | | - OUT ---------------- The new driver gets grouped together with the existing gpio-gate and gpio-mux, as it for one re-uses a lot of the gpio-gate functions and also in its core it's just another gpio-controlled clock, just with a fixed rate and a regulator-supply added in. The regulator-API provides function stubs for the !CONFIG_REGULATOR case, so no special handling is necessary. Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20240906082511.2963890-5-heiko@sntech.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 185 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index cda362a2eca0..9099c57e2715 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -17,6 +17,7 @@ #include #include #include +#include /** * DOC: basic gpio gated clock which can be enabled and disabled @@ -239,3 +240,187 @@ static struct platform_driver gpio_clk_driver = { }, }; builtin_platform_driver(gpio_clk_driver); + +/** + * DOC: gated fixed clock, controlled with a gpio output and a regulator + * Traits of this clock: + * prepare - clk_prepare and clk_unprepare are function & control regulator + * optionally a gpio that can sleep + * enable - clk_enable and clk_disable are functional & control gpio + * rate - rate is fixed and set on clock registration + * parent - fixed clock is a root clock and has no parent + */ + +/** + * struct clk_gated_fixed - Gateable fixed rate clock + * @clk_gpio: instance of clk_gpio for gate-gpio + * @supply: supply regulator + * @rate: fixed rate + */ +struct clk_gated_fixed { + struct clk_gpio clk_gpio; + struct regulator *supply; + unsigned long rate; +}; + +#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio) + +static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return to_clk_gated_fixed(to_clk_gpio(hw))->rate; +} + +static int clk_gated_fixed_prepare(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return 0; + + return regulator_enable(clk->supply); +} + +static void clk_gated_fixed_unprepare(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return; + + regulator_disable(clk->supply); +} + +static int clk_gated_fixed_is_prepared(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return true; + + return regulator_is_enabled(clk->supply); +} + +/* + * Fixed gated clock with non-sleeping gpio. + * + * Prepare operation turns on the supply regulator + * and the enable operation switches the enable-gpio. + */ +static const struct clk_ops clk_gated_fixed_ops = { + .prepare = clk_gated_fixed_prepare, + .unprepare = clk_gated_fixed_unprepare, + .is_prepared = clk_gated_fixed_is_prepared, + .enable = clk_gpio_gate_enable, + .disable = clk_gpio_gate_disable, + .is_enabled = clk_gpio_gate_is_enabled, + .recalc_rate = clk_gated_fixed_recalc_rate, +}; + +static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw) +{ + int ret; + + ret = clk_gated_fixed_prepare(hw); + if (ret) + return ret; + + ret = clk_sleeping_gpio_gate_prepare(hw); + if (ret) + clk_gated_fixed_unprepare(hw); + + return ret; +} + +static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw) +{ + clk_gated_fixed_unprepare(hw); + clk_sleeping_gpio_gate_unprepare(hw); +} + +/* + * Fixed gated clock with non-sleeping gpio. + * + * Enabling the supply regulator and switching the enable-gpio happens + * both in the prepare step. + * is_prepared only needs to check the gpio state, as toggling the + * gpio is the last step when preparing. + */ +static const struct clk_ops clk_sleeping_gated_fixed_ops = { + .prepare = clk_sleeping_gated_fixed_prepare, + .unprepare = clk_sleeping_gated_fixed_unprepare, + .is_prepared = clk_sleeping_gpio_gate_is_prepared, + .recalc_rate = clk_gated_fixed_recalc_rate, +}; + +static int clk_gated_fixed_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct clk_gated_fixed *clk; + const struct clk_ops *ops; + const char *clk_name; + u32 rate; + int ret; + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + + ret = device_property_read_u32(dev, "clock-frequency", &rate); + if (ret) + return dev_err_probe(dev, ret, "Failed to get clock-frequency\n"); + clk->rate = rate; + + ret = device_property_read_string(dev, "clock-output-names", &clk_name); + if (ret) + clk_name = fwnode_get_name(dev->fwnode); + + clk->supply = devm_regulator_get_optional(dev, "vdd"); + if (IS_ERR(clk->supply)) { + if (PTR_ERR(clk->supply) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(clk->supply), + "Failed to get regulator\n"); + clk->supply = NULL; + } + + clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(clk->clk_gpio.gpiod)) + return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod), + "Failed to get gpio\n"); + + if (gpiod_cansleep(clk->clk_gpio.gpiod)) + ops = &clk_sleeping_gated_fixed_ops; + else + ops = &clk_gated_fixed_ops; + + clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0); + + /* register the clock */ + ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clock\n"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &clk->clk_gpio.hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clock provider\n"); + + return 0; +} + +static const struct of_device_id gated_fixed_clk_match_table[] = { + { .compatible = "gated-fixed-clock" }, + { /* sentinel */ } +}; + +static struct platform_driver gated_fixed_clk_driver = { + .probe = clk_gated_fixed_probe, + .driver = { + .name = "gated-fixed-clk", + .of_match_table = gated_fixed_clk_match_table, + }, +}; +builtin_platform_driver(gated_fixed_clk_driver); -- 2.51.0 From 039a2eb86e84a84208a807044b945bde9f844f55 Mon Sep 17 00:00:00 2001 From: Sander Vanheule Date: Tue, 7 Jan 2025 21:16:20 +0100 Subject: [PATCH 175/517] gpio: regmap: Use generic request/free ops Set the gpiochip request and free ops to the generic implementations. This way a user can provide a gpio-ranges property defined for a pinmux, easing muxing of gpio functions. Provided that the pin controller implementents the pinmux op .gpio_request_enable(), pins will automatically be muxed to their GPIO function when requested. Signed-off-by: Sander Vanheule Acked-by: Michael Walle Link: https://lore.kernel.org/r/20250107201621.12467-1-sander@svanheule.net Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-regmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 71684dee2ca5..05f8781b5204 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config chip->label = config->label ?: dev_name(config->parent); chip->can_sleep = regmap_might_sleep(config->regmap); + chip->request = gpiochip_generic_request; + chip->free = gpiochip_generic_free; chip->get = gpio_regmap_get; if (gpio->reg_set_base && gpio->reg_clr_base) chip->set = gpio_regmap_set_with_clear; -- 2.51.0 From 555fd2a1b2e46bbede23b8477230cd77af346fe2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Apr 2025 15:27:41 -0700 Subject: [PATCH 176/517] power: supply: sysfs: Remove duplicate NUL termination GCC 15's new -Wunterminated-string-initialization notices that one of the sysfs attr strings would lack the implicit trailing NUL byte during initialization: drivers/power/supply/power_supply_sysfs.c:183:57: warning: initializer-string for array of 'char' truncates NUL terminator but destination lacks 'nonstring' attribute (32 chars into 31 available) [-Wunterminated-string-initialization] 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD), | ^ drivers/power/supply/power_supply_sysfs.c:36:23: note: in definition of macro '_POWER_SUPPLY_ATTR' 36 | .attr_name = #_name "\0", \ | ^~~~~ drivers/power/supply/power_supply_sysfs.c:183:9: note: in expansion of macro 'POWER_SUPPLY_ATTR' 183 | POWER_SUPPLY_ATTR(CHARGE_CONTROL_START_THRESHOLD), | ^~~~~~~~~~~~~~~~~ However, the macro used was explicitly adding a trailing NUL byte (which is not needed). Remove this to avoid the GCC warning. No binary differences are seen after this change (there was always run for a NUL byte, it's just that the _second_ NUL byte was getting truncated). Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20250416222740.work.569-kees@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 16b3c5880cd8..df6b16c77279 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -33,7 +33,7 @@ struct power_supply_attr { [POWER_SUPPLY_PROP_ ## _name] = \ { \ .prop_name = #_name, \ - .attr_name = #_name "\0", \ + .attr_name = #_name, \ .text_values = _text, \ .text_values_len = _len, \ } -- 2.51.0 From 7fb95e70810dd24974c57ab56fb2dc919e5b1665 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 22 Oct 2020 22:00:03 +0200 Subject: [PATCH 177/517] compiler.h: only include asm/rwonce.h for kernel code This header file is not in uapi, which makes any user space code that includes linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory' Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h") Signed-off-by: Felix Fietkau --- include/linux/compiler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index d18542d7e17b..23b43f6093b1 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -191,6 +191,8 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, __v; \ }) +#include + #endif /* __KERNEL__ */ /** @@ -298,6 +300,4 @@ static inline void *offset_to_ptr(const int *off) */ #define prevent_tail_call_optimization() mb() -#include - #endif /* __LINUX_COMPILER_H */ -- 2.51.0 From 65c264e73e6464600d94d7aa80a1513b0cc13d77 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 18 Apr 2018 10:50:05 +0200 Subject: [PATCH 178/517] MIPS: only process negative stack offsets on stack traces Fixes endless back traces in cases where the compiler emits a stack pointer increase in a branch delay slot (probably for some form of function return). [ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low! [ 3.480070] turning off the locking correctness validator. [ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0 [ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000 [ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f [ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000 [ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000 [ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000 [ 3.532942] ... [ 3.535362] Call Trace: [ 3.537818] [<80010a48>] show_stack+0x58/0x100 [ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170 [ 3.546613] [<80079f90>] save_trace+0xf0/0x110 [ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c [ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08 [ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c [ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78 [ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac [ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac [ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac [ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac [ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac [ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac [ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac [ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac [ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0 [ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac Signed-off-by: Felix Fietkau --- arch/mips/kernel/process.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 02aa6a04a21d..d84ff2484e6b 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -395,6 +395,8 @@ static inline int is_sp_move_ins(union mips_instruction *ip, int *frame_size) if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) { + if (ip->i_format.simmediate > 0) + return 0; *frame_size = -ip->i_format.simmediate; return 1; } -- 2.51.0 From 5fb9ed3fa96df7607d624af7500a8b28005008bb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jul 2017 00:26:53 +0200 Subject: [PATCH 179/517] kernel: add compile fix for linux 4.9 on x86 Signed-off-by: Felix Fietkau --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d4c679b2d4bc..adebb89c7db4 100644 --- a/Makefile +++ b/Makefile @@ -589,7 +589,7 @@ export RUSTC_BOOTSTRAP := 1 # Allows finding `.clippy.toml` in out-of-srctree builds. export CLIPPY_CONF_DIR := $(srctree) -export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG +export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN export HOSTRUSTC KBUILD_HOSTRUSTFLAGS export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL -- 2.51.0 From 24ba3611cd2096392227e4f47f8970e7fc03d445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 28 Apr 2022 11:13:23 +0200 Subject: [PATCH 180/517] watchdog: max63xx_wdt: Add support for specifying WDI logic via GPIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some boards is WDI logic of max6370 chip connected via GPIO. So extend max63xx_wdt driver to allow specifying WDI logic via GPIO. Signed-off-by: Pali Rohár --- drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 21935f9620e4..041ae121f981 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c @@ -24,6 +24,7 @@ #include #include #include +#include #define DEFAULT_HEARTBEAT 60 #define MAX_HEARTBEAT 60 @@ -50,6 +51,9 @@ struct max63xx_wdt { void __iomem *base; spinlock_t lock; + /* GPIOs */ + struct gpio_desc *gpio_wdi; + /* WDI and WSET bits write access routines */ void (*ping)(struct max63xx_wdt *wdt); void (*set)(struct max63xx_wdt *wdt, u8 set); @@ -155,6 +159,17 @@ static const struct watchdog_info max63xx_wdt_info = { .identity = "max63xx Watchdog", }; +static void max63xx_gpio_ping(struct max63xx_wdt *wdt) +{ + spin_lock(&wdt->lock); + + gpiod_set_value(wdt->gpio_wdi, 1); + udelay(1); + gpiod_set_value(wdt->gpio_wdi, 0); + + spin_unlock(&wdt->lock); +} + static void max63xx_mmap_ping(struct max63xx_wdt *wdt) { u8 val; @@ -222,10 +237,19 @@ static int max63xx_wdt_probe(struct platform_device *pdev) return -EINVAL; } + wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT); + if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT) + return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi), + "unable to request gpio: %ld\n", + PTR_ERR(wdt->gpio_wdi)); + err = max63xx_mmap_init(pdev, wdt); if (err) return err; + if (!IS_ERR(wdt->gpio_wdi)) + wdt->ping = max63xx_gpio_ping; + platform_set_drvdata(pdev, &wdt->wdd); watchdog_set_drvdata(&wdt->wdd, wdt); -- 2.51.0 From 3a45749cae25f2d9e0eb86b03f7283dab7086b14 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:31 +0100 Subject: [PATCH 181/517] jffs2: use .rename2 and add RENAME_WHITEOUT support It is required for renames on overlayfs Signed-off-by: Felix Fietkau --- fs/jffs2/dir.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 2b2938970da3..8ceef593258e 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -620,8 +620,8 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) return ret; } -static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, - struct dentry *dentry, umode_t mode, dev_t rdev) +static int __jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, + struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -761,7 +761,11 @@ static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); - d_instantiate_new(dentry, inode); + if (!whiteout) + d_instantiate_new(dentry, inode); + else + unlock_new_inode(inode); + return 0; fail: @@ -769,6 +773,19 @@ static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, return ret; } +static int jffs2_mknod (struct mnt_idmap *idmap, struct inode *dir_i, + struct dentry *dentry, umode_t mode, dev_t rdev) +{ + return __jffs2_mknod(idmap, dir_i, dentry, mode, rdev, false); +} + +static int jffs2_whiteout (struct mnt_idmap *idmap, struct inode *old_dir, + struct dentry *old_dentry) +{ + return __jffs2_mknod(idmap, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, + WHITEOUT_DEV, true); +} + static int jffs2_rename (struct mnt_idmap *idmap, struct inode *old_dir_i, struct dentry *old_dentry, struct inode *new_dir_i, struct dentry *new_dentry, @@ -780,7 +797,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, uint8_t type; uint32_t now; - if (flags & ~RENAME_NOREPLACE) + if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) return -EINVAL; /* The VFS will check for us and prevent trying to rename a @@ -846,9 +863,14 @@ static int jffs2_rename (struct mnt_idmap *idmap, if (d_is_dir(old_dentry) && !victim_f) inc_nlink(new_dir_i); - /* Unlink the original */ - ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), - old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(idmap, old_dir_i, old_dentry); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + old_dentry->d_name.name, + old_dentry->d_name.len, NULL, now); /* We don't touch inode->i_nlink */ -- 2.51.0 From 3b035d50ebdd949b59df84accf8c390e5857869b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:32 +0100 Subject: [PATCH 182/517] jffs2: add RENAME_EXCHANGE support Signed-off-by: Felix Fietkau --- fs/jffs2/dir.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 8ceef593258e..198bc4bf6aed 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -794,18 +794,31 @@ static int jffs2_rename (struct mnt_idmap *idmap, int ret; struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; + struct inode *fst_inode = d_inode(old_dentry); + struct inode *snd_inode = d_inode(new_dentry); uint8_t type; uint32_t now; - if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) + if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE)) return -EINVAL; + if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) { + if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { + inc_nlink(new_dir_i); + drop_nlink(old_dir_i); + } + else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { + drop_nlink(new_dir_i); + inc_nlink(old_dir_i); + } + } + /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. */ - if (d_really_is_positive(new_dentry)) { + if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) { victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); if (d_is_dir(new_dentry)) { struct jffs2_full_dirent *fd; @@ -840,7 +853,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, if (ret) return ret; - if (victim_f) { + if (victim_f && !(flags & RENAME_EXCHANGE)) { /* There was a victim. Kill it off nicely */ if (d_is_dir(new_dentry)) clear_nlink(d_inode(new_dentry)); @@ -866,6 +879,12 @@ static int jffs2_rename (struct mnt_idmap *idmap, if (flags & RENAME_WHITEOUT) /* Replace with whiteout */ ret = jffs2_whiteout(idmap, old_dir_i, old_dentry); + else if (flags & RENAME_EXCHANGE) + /* Replace the original */ + ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), + d_inode(new_dentry)->i_ino, type, + old_dentry->d_name.name, old_dentry->d_name.len, + now); else /* Unlink the original */ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), @@ -898,7 +917,7 @@ static int jffs2_rename (struct mnt_idmap *idmap, return ret; } - if (d_is_dir(old_dentry)) + if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) drop_nlink(old_dir_i); inode_set_mtime_to_ts(old_dir_i, -- 2.51.0 From 45c9e05782807facb6e64541dc9a86119ed266f1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:32 +0100 Subject: [PATCH 183/517] jffs2: add splice ops Add splice_read using generic_file_splice_read. Add splice_write using iter_file_splice_write Signed-off-by: Felix Fietkau --- fs/jffs2/file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 13c18ccc13b0..b08616967891 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -53,6 +53,8 @@ const struct file_operations jffs2_file_operations = .open = generic_file_open, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, + .splice_read = filemap_splice_read, + .splice_write = iter_file_splice_write, .unlocked_ioctl=jffs2_ioctl, .mmap = generic_file_readonly_mmap, .fsync = jffs2_fsync, -- 2.51.0 From f772c8f03f55a56dc910561555de3b1237994f1e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 3 Nov 2025 15:49:32 +0100 Subject: [PATCH 184/517] bridge: allow receiption on disabled port When an ethernet device is enslaved to a bridge, and the bridge STP detects loss of carrier (or operational state down), then normally packet receiption is blocked. This breaks control applications like WPA which maybe expecting to receive packets to negotiate to bring link up. The bridge needs to block forwarding packets from these disabled ports, but there is no hard requirement to not allow local packet delivery. Signed-off-by: Stephen Hemminger Signed-off-by: Felix Fietkau --- net/bridge/br_input.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index c059e5657db3..0332371d19ab 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -245,6 +245,9 @@ static void __br_handle_local_finish(struct sk_buff *skb) /* note: already called with rcu_read_lock */ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + struct net_bridge_port *p = br_port_get_rcu(skb->dev); + + if (p->state != BR_STATE_DISABLED) __br_handle_local_finish(skb); /* return 1 to signal the okfn() was called so it's ok to use the skb */ @@ -416,6 +419,17 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) goto defer_stp_filtering; switch (p->state) { + case BR_STATE_DISABLED: + if (ether_addr_equal(p->br->dev->dev_addr, dest)) + skb->pkt_type = PACKET_HOST; + + if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, + dev_net(skb->dev), NULL, skb, skb->dev, NULL, + br_handle_local_finish) == 1) { + return RX_HANDLER_PASS; + } + break; + case BR_STATE_FORWARDING: case BR_STATE_LEARNING: defer_stp_filtering: -- 2.51.0 From f8a675acf745105364469ccd2c10ae11f0ff58dd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 4 Jan 2024 15:21:21 +0100 Subject: [PATCH 185/517] net: bridge: do not send arp replies if src and target hw addr is the same There are broken devices in the wild that handle duplicate IP address detection by sending out ARP requests for the IP that they received from a DHCP server and refuse the address if they get a reply. When proxyarp is enabled, they would go into a loop of requesting an address and then NAKing it again. Link: https://github.com/openwrt/openwrt/issues/14309 Signed-off-by: Felix Fietkau --- net/bridge/br_arp_nd_proxy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c index c7869a286df4..3a2770938374 100644 --- a/net/bridge/br_arp_nd_proxy.c +++ b/net/bridge/br_arp_nd_proxy.c @@ -204,7 +204,10 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, if ((p && (p->flags & BR_PROXYARP)) || (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)) || br_is_neigh_suppress_enabled(f->dst, vid)) { - if (!vid) + replied = true; + if (!memcmp(n->ha, sha, dev->addr_len)) + replied = false; + else if (!vid) br_arp_send(br, p, skb->dev, sip, tip, sha, n->ha, sha, 0, 0); else @@ -212,7 +215,6 @@ void br_do_proxy_suppress_arp(struct sk_buff *skb, struct net_bridge *br, sha, n->ha, sha, skb->vlan_proto, skb_vlan_tag_get(skb)); - replied = true; } /* If we have replied or as long as we know the -- 2.51.0 From 5e09714675351cc1bfc7be2cdf06a96371415a00 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 21 May 2025 23:27:04 +0200 Subject: [PATCH 186/517] wireguard: global: add __nonstring annotations for unterminated strings When a character array without a terminating NUL character has a static initializer, GCC 15's -Wunterminated-string-initialization will only warn if the array lacks the "nonstring" attribute[1]. Mark the arrays with __nonstring to correctly identify the char array as "not a C string" and thereby eliminate the warning: ../drivers/net/wireguard/cookie.c:29:56: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization] 29 | static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----"; | ^~~~~~~~~~ ../drivers/net/wireguard/cookie.c:30:58: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (9 chars into 8 available) [-Wunterminated-string-initialization] 30 | static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--"; | ^~~~~~~~~~ ../drivers/net/wireguard/noise.c:28:38: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (38 chars into 37 available) [-Wunterminated-string-initialization] 28 | static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../drivers/net/wireguard/noise.c:29:39: warning: initializer-string for array of 'unsigned char' truncates NUL terminator but destination lacks 'nonstring' attribute (35 chars into 34 available) [-Wunterminated-string-initialization] 29 | static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The arrays are always used with their fixed size, so use __nonstring. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117178 [1] Signed-off-by: Kees Cook Signed-off-by: Jason A. Donenfeld Link: https://patch.msgid.link/20250521212707.1767879-3-Jason@zx2c4.com Signed-off-by: Paolo Abeni --- drivers/net/wireguard/cookie.c | 4 ++-- drivers/net/wireguard/noise.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireguard/cookie.c b/drivers/net/wireguard/cookie.c index f89581b5e8cb..94d0a7206084 100644 --- a/drivers/net/wireguard/cookie.c +++ b/drivers/net/wireguard/cookie.c @@ -26,8 +26,8 @@ void wg_cookie_checker_init(struct cookie_checker *checker, } enum { COOKIE_KEY_LABEL_LEN = 8 }; -static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----"; -static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--"; +static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "mac1----"; +static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] __nonstring = "cookie--"; static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], const u8 pubkey[NOISE_PUBLIC_KEY_LEN], diff --git a/drivers/net/wireguard/noise.c b/drivers/net/wireguard/noise.c index 202a33af5a72..7eb9a23a3d4d 100644 --- a/drivers/net/wireguard/noise.c +++ b/drivers/net/wireguard/noise.c @@ -25,8 +25,8 @@ * <- e, ee, se, psk, {} */ -static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; -static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; +static const u8 handshake_name[37] __nonstring = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; +static const u8 identifier_name[34] __nonstring = "WireGuard v1 zx2c4 Jason@zx2c4.com"; static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init; static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init; static atomic64_t keypair_counter = ATOMIC64_INIT(0); -- 2.51.0 From 521a25813c3413cc25032dd5b0b090950f0057c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Cabanelas?= Date: Mon, 3 Nov 2025 15:49:33 +0100 Subject: [PATCH 187/517] rtc: rs5c372: support alarms up to 1 week MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week alarms. Read the "wday" alarm register and convert it to a date to support up 1 week in our driver. Signed-off-by: Daniel González Cabanelas --- drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index f8fab0205f8c..e19aef158938 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); - int status; + int status, wday_offs; + struct rtc_time rtc; + unsigned long alarm_secs; status = rs5c_get_regs(rs5c); if (status < 0) @@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) t->time.tm_sec = 0; t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); + t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1; + + /* determine the day, month and year based on alarm wday, taking as a + * reference the current time from the rtc + */ + status = rs5c372_rtc_read_time(dev, &rtc); + if (status < 0) + return status; + + wday_offs = t->time.tm_wday - rtc.tm_wday; + alarm_secs = mktime64(rtc.tm_year + 1900, + rtc.tm_mon + 1, + rtc.tm_mday + wday_offs, + t->time.tm_hour, + t->time.tm_min, + t->time.tm_sec); + + if (wday_offs < 0 || (wday_offs == 0 && + (t->time.tm_hour < rtc.tm_hour || + (t->time.tm_hour == rtc.tm_hour && + t->time.tm_min <= rtc.tm_min)))) + alarm_secs += 7 * 86400; + + rtc_time64_to_tm(alarm_secs, &t->time); /* ... and status */ t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); @@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) struct rs5c372 *rs5c = i2c_get_clientdata(client); int status, addr, i; unsigned char buf[3]; + struct rtc_time rtc_tm; + unsigned long rtc_secs, alarm_secs; - /* only handle up to 24 hours in the future, like RTC_ALM_SET */ - if (t->time.tm_mday != -1 - || t->time.tm_mon != -1 - || t->time.tm_year != -1) + /* chip only can handle alarms up to one week in the future*/ + status = rs5c372_rtc_read_time(dev, &rtc_tm); + if (status) + return status; + rtc_secs = rtc_tm_to_time64(&rtc_tm); + alarm_secs = rtc_tm_to_time64(&t->time); + if (alarm_secs >= rtc_secs + 7 * 86400) { + dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n", + __func__, status); return -EINVAL; + } /* REVISIT: round up tm_sec */ @@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) /* set alarm */ buf[0] = bin2bcd(t->time.tm_min); buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); - buf[2] = 0x7f; /* any/all days */ + /* each bit is the day of the week, 0x7f means all days */ + buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ? + BIT(t->time.tm_wday) : 0x7f; for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); -- 2.51.0 From 3625b65094981635964c425d20e84532c4f9ac11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Cabanelas?= Date: Mon, 3 Nov 2025 15:49:33 +0100 Subject: [PATCH 188/517] rtc: rs5c372: let the alarm to be used as wakeup source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there is no use for the interrupts on the rs5c372 RTC and the wakealarm isn't enabled. There are some devices like NASes which use this RTC to wake up from the power off state when the INTR pin is activated by the alarm clock. Enable the alarm and let to be used as a wakeup source. Tested on a Buffalo LS421DE NAS. Signed-off-by: Daniel González Cabanelas --- drivers/rtc/rtc-rs5c372.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index e19aef158938..b3f7e859e5d5 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -832,6 +832,7 @@ static int rs5c372_probe(struct i2c_client *client) int err = 0; int smbus_mode = 0; struct rs5c372 *rs5c372; + bool rs5c372_can_wakeup_device = false; dev_dbg(&client->dev, "%s\n", __func__); @@ -868,6 +869,12 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->type = id->driver_data; } +#ifdef CONFIG_OF + if(of_property_read_bool(client->dev.of_node, + "wakeup-source")) + rs5c372_can_wakeup_device = true; +#endif + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ rs5c372->regs = &rs5c372->buf[1]; rs5c372->smbus = smbus_mode; @@ -901,6 +908,8 @@ static int rs5c372_probe(struct i2c_client *client) goto exit; } + rs5c372->has_irq = 1; + /* if the oscillator lost power and no other software (like * the bootloader) set it up, do it here. * @@ -927,6 +936,10 @@ static int rs5c372_probe(struct i2c_client *client) ); /* REVISIT use client->irq to register alarm irq ... */ + if (rs5c372_can_wakeup_device) { + device_init_wakeup(&client->dev, true); + } + rs5c372->rtc = devm_rtc_device_register(&client->dev, rs5c372_driver.driver.name, &rs5c372_rtc_ops, THIS_MODULE); @@ -940,6 +953,10 @@ static int rs5c372_probe(struct i2c_client *client) if (err) goto exit; + /* the rs5c372 alarm only supports a minute accuracy */ + set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rs5c372->rtc->features); + clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rs5c372->rtc->features); + return 0; exit: -- 2.51.0 From aaa9613d88cfc960918632f6cdc33972cf14729b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 15 Apr 2025 23:16:40 +0200 Subject: [PATCH 189/517] ARM: 9404/1: arm32: fix boot hang with HAVE_LD_DEAD_CODE_DATA_ELIMINATION It was reported that some SoC (mvebu based for example) hang on kernel loading. A variant of the feature was present in OpenWrt from long ago and adding the additional entry with KEEP, fix the problem. Fixes: ed0f94102251 ("ARM: 9404/1: arm32: enable HAVE_LD_DEAD_CODE_DATA_ELIMINATION") Signed-off-by: Christian Marangi --- arch/arm/include/asm/vmlinux.lds.h | 10 +++++----- arch/arm/kernel/vmlinux.lds.S | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h index 14811b4f48ec..c69205878256 100644 --- a/arch/arm/include/asm/vmlinux.lds.h +++ b/arch/arm/include/asm/vmlinux.lds.h @@ -54,7 +54,7 @@ #define IDMAP_TEXT \ ALIGN_FUNCTION(); \ __idmap_text_start = .; \ - *(.idmap.text) \ + KEEP(*(.idmap.text)) \ __idmap_text_end = .; \ #define ARM_DISCARD \ @@ -114,12 +114,12 @@ . = ALIGN(8); \ .ARM.unwind_idx : { \ __start_unwind_idx = .; \ - *(.ARM.exidx*) \ + KEEP(*(.ARM.exidx*)) \ __stop_unwind_idx = .; \ } \ .ARM.unwind_tab : { \ __start_unwind_tab = .; \ - *(.ARM.extab*) \ + KEEP(*(.ARM.extab*)) \ __stop_unwind_tab = .; \ } @@ -131,7 +131,7 @@ __vectors_lma = .; \ OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \ .vectors { \ - OVERLAY_KEEP(*(.vectors)) \ + KEEP(*(.vectors)) \ } \ .vectors.bhb.loop8 { \ OVERLAY_KEEP(*(.vectors.bhb.loop8)) \ @@ -149,7 +149,7 @@ \ __stubs_lma = .; \ .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \ - *(.stubs) \ + KEEP(*(.stubs)) \ } \ ARM_LMA(__stubs, .stubs); \ . = __stubs_lma + SIZEOF(.stubs); \ diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index de373c6c2ae8..4d2ea49d6f84 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -104,13 +104,13 @@ SECTIONS } .init.tagtable : { __tagtable_begin = .; - *(.taglist.init) + KEEP(*(.taglist.init)) __tagtable_end = .; } #ifdef CONFIG_SMP_ON_UP .init.smpalt : { __smpalt_begin = .; - *(.alt.smp.init) + KEEP(*(.alt.smp.init)) __smpalt_end = .; } #endif -- 2.51.0 From 66801cda68c3e0f05d3962565caf52d4abb6c98b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:34 +0100 Subject: [PATCH 190/517] kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx [john@phrozen.org: added to my upstream queue 30.12.2016] lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed Signed-off-by: Felix Fietkau --- init/Kconfig | 11 +++++++++ kernel/kallsyms.c | 8 ++++++ kernel/vmcore_info.c | 2 ++ scripts/kallsyms.c | 54 ++++++++++++++++++++++++++--------------- scripts/link-vmlinux.sh | 4 +++ 5 files changed, 59 insertions(+), 20 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 219ccdb0af73..9b04e413be82 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1534,6 +1534,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW the unaligned access emulation. see arch/parisc/kernel/unaligned.c for reference +config KALLSYMS_UNCOMPRESSED + bool "Keep kallsyms uncompressed" + depends on KALLSYMS + help + Normally kallsyms contains compressed symbols (using a token table), + reducing the uncompressed kernel image size. Keeping the symbol table + uncompressed significantly improves the size of this part in compressed + kernel images. + + Say N unless you need compressed kernel images to be small. + config HAVE_PCSPKR_PLATFORM bool diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index a9a0ca605d4a..82c9b31f5bf3 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, * For every byte on the compressed symbol data, copy the table * entry for that byte. */ +#ifdef CONFIG_KALLSYMS_UNCOMPRESSED + memcpy(result, data + 1, len - 1); + result += len - 1; + len = 0; +#endif while (len) { tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; data++; @@ -101,6 +106,9 @@ static unsigned int kallsyms_expand_symbol(unsigned int off, */ static char kallsyms_get_symbol_type(unsigned int off) { +#ifdef CONFIG_KALLSYMS_UNCOMPRESSED + return kallsyms_names[off + 1]; +#endif /* * Get just the first code, look it up in the token table, * and return the first char from this token. diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c index 1fec61603ef3..9345ac6cb454 100644 --- a/kernel/vmcore_info.c +++ b/kernel/vmcore_info.c @@ -214,8 +214,10 @@ static int __init crash_save_vmcoreinfo_init(void) #ifdef CONFIG_KALLSYMS VMCOREINFO_SYMBOL(kallsyms_names); VMCOREINFO_SYMBOL(kallsyms_num_syms); +#ifndef CONFIG_KALLSYMS_UNCOMPRESSED VMCOREINFO_SYMBOL(kallsyms_token_table); VMCOREINFO_SYMBOL(kallsyms_token_index); +#endif VMCOREINFO_SYMBOL(kallsyms_offsets); VMCOREINFO_SYMBOL(kallsyms_relative_base); #endif /* CONFIG_KALLSYMS */ diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 03852da3d249..0c50cc494850 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -62,6 +62,7 @@ static struct addr_range percpu_range = { static struct sym_entry **table; static unsigned int table_size, table_cnt; static int all_symbols; +static int uncompressed; static int absolute_percpu; static int token_profit[0x10000]; @@ -412,13 +413,17 @@ static void write_src(void) for (k = 0; k < table[i]->len; k++) printf(", 0x%02x", table[i]->sym[k]); - /* - * Now that we wrote out the compressed symbol name, restore the - * original name and print it in the comment. - */ - expand_symbol(table[i]->sym, table[i]->len, buf); - strcpy((char *)table[i]->sym, buf); - printf("\t/* %s */\n", table[i]->sym); + if (!uncompressed) { + /* + * Now that we wrote out the compressed symbol name, restore the + * original name and print it in the comment. + */ + expand_symbol(table[i]->sym, table[i]->len, buf); + strcpy((char *)table[i]->sym, buf); + printf("\t/* %s */\n", table[i]->sym); + } else { + printf("\n"); + } } printf("\n"); @@ -429,20 +434,22 @@ static void write_src(void) free(markers); - output_label("kallsyms_token_table"); - off = 0; - for (i = 0; i < 256; i++) { - best_idx[i] = off; - expand_symbol(best_table[i], best_table_len[i], buf); - printf("\t.asciz\t\"%s\"\n", buf); - off += strlen(buf) + 1; - } - printf("\n"); + if (!uncompressed) { + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { + best_idx[i] = off; + expand_symbol(best_table[i], best_table_len[i], buf); + printf("\t.asciz\t\"%s\"\n", buf); + off += strlen(buf) + 1; + } + printf("\n"); - output_label("kallsyms_token_index"); - for (i = 0; i < 256; i++) - printf("\t.short\t%d\n", best_idx[i]); - printf("\n"); + output_label("kallsyms_token_index"); + for (i = 0; i < 256; i++) + printf("\t.short\t%d\n", best_idx[i]); + printf("\n"); + } output_label("kallsyms_offsets"); @@ -532,6 +539,9 @@ static unsigned char *find_token(unsigned char *str, int len, { int i; + if (uncompressed) + return NULL; + for (i = 0; i < len - 1; i++) { if (str[i] == token[0] && str[i+1] == token[1]) return &str[i]; @@ -604,6 +614,9 @@ static void optimize_result(void) { int i, best; + if (uncompressed) + return; + /* using the '\0' symbol last allows compress_symbols to use standard * fast string functions */ for (i = 255; i >= 0; i--) { @@ -763,6 +776,7 @@ int main(int argc, char **argv) static const struct option long_options[] = { {"all-symbols", no_argument, &all_symbols, 1}, {"absolute-percpu", no_argument, &absolute_percpu, 1}, + {"uncompressed", no_argument, &uncompressed, 1}, {}, }; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a9b3f34a78d2..8013f57047b1 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -144,6 +144,10 @@ kallsyms() kallsymopt="${kallsymopt} --absolute-percpu" fi + if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then + kallsymopt="${kallsymopt} --uncompressed" + fi + info KSYMS "${2}.S" scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S" -- 2.51.0 From 27f5413d1222b8bde41e5383d85ecf0c9b1db242 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:34 +0100 Subject: [PATCH 191/517] kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries [john@phrozen.org: felix will add this to his upstream queue] lede-commit 53827cdc824556cda910b23ce5030c363b8f1461 Signed-off-by: Felix Fietkau --- lib/vsprintf.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a69e71a1ca55..5026d8912563 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -983,8 +983,10 @@ char *symbol_string(char *buf, char *end, void *ptr, struct printf_spec spec, const char *fmt) { unsigned long value; -#ifdef CONFIG_KALLSYMS char sym[KSYM_SYMBOL_LEN]; +#ifndef CONFIG_KALLSYMS + struct module *mod; + int len; #endif if (fmt[1] == 'R') @@ -1005,8 +1007,14 @@ char *symbol_string(char *buf, char *end, void *ptr, return string_nocheck(buf, end, sym, spec); #else - return special_hex_number(buf, end, value, sizeof(void *)); + len = snprintf(sym, sizeof(sym), "0x%lx", value); + mod = __module_address(value); + if (mod) + snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", + mod->name, mod->mem[MOD_TEXT].base, + mod->mem[MOD_TEXT].size); #endif + return string(buf, end, sym, spec); } static const struct printf_spec default_str_spec = { -- 2.51.0 From 30746abd35d5550aed9f5b0152ebece730c5a889 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 3 Nov 2025 15:49:34 +0100 Subject: [PATCH 192/517] usr: sanitize deps_initramfs list If any filename in the intramfs dependency list contains a colon, that causes a kernel build error like this: /devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop. make[5]: *** [usr] Error 2 Fix it by removing such filenames from the deps_initramfs list. Signed-off-by: Gabor Juhos Signed-off-by: Felix Fietkau --- usr/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/usr/Makefile b/usr/Makefile index f1779496bca7..90398a751588 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -56,6 +56,8 @@ hostprogs := gen_init_cpio # The dependency list is generated by gen_initramfs.sh -l -include $(obj)/.initramfs_data.cpio.d +deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) + # do not try to update files included in initramfs $(deps_initramfs): ; -- 2.51.0 From 49d8ded1302b4decccc20ce90bc53db1b63a2107 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Fri, 27 Jun 2025 11:09:04 +0100 Subject: [PATCH 193/517] kernel/fork: Increase minimum number of allowed threads A modern Linux system creates much more than 20 threads at bootup. When I booted up OpenWrt in qemu the system sometimes failed to boot up when it wanted to create the 419th thread. The VM had 128MB RAM and the calculation in set_max_threads() calculated that max_threads should be set to 419. When the system booted up it tried to notify the user space about every device it created because CONFIG_UEVENT_HELPER was set and used. I counted 1299 calls to call_usermodehelper_setup(), all of them try to create a new thread and call the userspace hotplug script in it. This fixes bootup of Linux on systems with low memory. I saw the problem with qemu 10.0.2 using these commands: qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic Cc: stable@vger.kernel.org Signed-off-by: Hauke Mehrtens --- kernel/fork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fork.c b/kernel/fork.c index e5ec098a6f61..4e2c63a1e737 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -123,7 +123,7 @@ /* * Minimum number of threads to boot the kernel */ -#define MIN_THREADS 20 +#define MIN_THREADS 600 /* * Maximum number of threads -- 2.51.0 From 2efc136e2a89b64cb447127e0ebc0624a54e79f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= Date: Sat, 28 Mar 2020 12:11:50 +0100 Subject: [PATCH 194/517] generic: platform/mikrotik build bits (5.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds platform/mikrotik kernel build bits Signed-off-by: Thibaut VARÈNE --- drivers/platform/Kconfig | 2 ++ drivers/platform/Makefile | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 960fd6a82450..ca7df46dcfd7 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -18,3 +18,5 @@ source "drivers/platform/surface/Kconfig" source "drivers/platform/x86/Kconfig" source "drivers/platform/arm64/Kconfig" + +source "drivers/platform/mikrotik/Kconfig" diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 19ac54648586..b77585bdc5cf 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/ +obj-$(CONFIG_MIKROTIK) += mikrotik/ -- 2.51.0 From 1db3bd42bc37da847f5708ddaea12d9e1dc1c667 Mon Sep 17 00:00:00 2001 From: Mark Miller Date: Mon, 3 Nov 2025 15:49:35 +0100 Subject: [PATCH 195/517] mips: expose CONFIG_BOOT_RAW This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on certain Broadcom chipsets running CFE in order to load the kernel. Signed-off-by: Mark Miller Acked-by: Rob Landley --- arch/mips/Kconfig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5078ebf071ec..a330c7152049 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1055,9 +1055,6 @@ config FW_ARC config ARCH_MAY_HAVE_PC_FDC bool -config BOOT_RAW - bool - config CEVT_BCM1480 bool @@ -2990,6 +2987,18 @@ choice bool "Extend builtin kernel arguments with bootloader arguments" endchoice +config BOOT_RAW + bool "Enable the kernel to be executed from the load address" + default n + help + Allow the kernel to be executed from the load address for + bootloaders which cannot read the ELF format. This places + a jump to start_kernel at the load address. + + If unsure, say N. + + + endmenu config LOCKDEP_SUPPORT -- 2.51.0 From cab68d173bcc34e6e4d7cfec9c69bb102bd5a6a9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 22 Feb 2016 18:09:44 +0000 Subject: [PATCH 196/517] MIPS: Add barriers between dcache & icache flushes Index-based cache operations may be arbitrarily reordered by out of order CPUs. Thus code which writes back the dcache & then invalidates the icache using indexed cache ops must include a barrier between operating on the 2 caches in order to prevent the scenario in which: - icache invalidation occurs. - icache fetch occurs, due to speculation. - dcache writeback occurs. If the above were allowed to happen then the icache would contain stale data. Forcing the dcache writeback to complete before the icache invalidation avoids this. Signed-off-by: Paul Burton Cc: James Hogan --- arch/mips/mm/c-r4k.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 10413b6f6662..8e263048280f 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -403,6 +403,7 @@ static inline void local_r4k___flush_cache_all(void * args) default: r4k_blast_dcache(); + mb(); /* cache instructions may be reordered */ r4k_blast_icache(); break; } @@ -483,8 +484,10 @@ static inline void local_r4k_flush_cache_range(void * args) if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) r4k_blast_dcache(); /* If executable, blast stale lines from icache */ - if (exec) + if (exec) { + mb(); /* cache instructions may be reordered */ r4k_blast_icache(); + } } static void r4k_flush_cache_range(struct vm_area_struct *vma, @@ -586,8 +589,13 @@ static inline void local_r4k_flush_cache_page(void *args) if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { vaddr ? r4k_blast_dcache_page(addr) : r4k_blast_dcache_user_page(addr); - if (exec && !cpu_icache_snoops_remote_store) + if (exec) + mb(); /* cache instructions may be reordered */ + + if (exec && !cpu_icache_snoops_remote_store) { r4k_blast_scache_page(addr); + mb(); /* cache instructions may be reordered */ + } } if (exec) { if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { @@ -654,6 +662,7 @@ static inline void __local_r4k_flush_icache_range(unsigned long start, else blast_dcache_range(start, end); } + mb(); /* cache instructions may be reordered */ } if (type == R4K_INDEX || -- 2.51.0 From 554dfd27393451b9120c52c5712714b3c1adf213 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:36 +0100 Subject: [PATCH 197/517] mips: use -mno-branch-likely for kernel and userspace saves ~11k kernel size after lzma and ~12k squashfs size in the lede-commit: 41a039f46450ffae9483d6216422098669da2900 Signed-off-by: Felix Fietkau --- arch/mips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 5785a3d5ccfb..3e673b4a4a72 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # -cflags-y += -G 0 -mno-abicalls -fno-pic -pipe +cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely cflags-y += -msoft-float -Wa,-msoft-float LDFLAGS_vmlinux += -G 0 -static -n -nostdlib KBUILD_AFLAGS_MODULE += -mlong-calls -- 2.51.0 From 7c5fa3df92251694f8253c39f0ee00b486676db5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:36 +0100 Subject: [PATCH 198/517] kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2 This provides a good tradeoff across at least 24Kc-74Kc, while also producing smaller code. Signed-off-by: Felix Fietkau --- arch/mips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 3e673b4a4a72..2a770f13a0cc 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -153,7 +153,7 @@ cflags-$(CONFIG_CPU_R4300) += $(call cc-option,-march=r4300,-march=mips3) -Wa,-- cflags-$(CONFIG_CPU_R4X00) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap cflags-$(CONFIG_CPU_TX49XX) += $(call cc-option,-march=r4600,-march=mips3) -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap -cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap -- 2.51.0 From ace85c5c8e52425cb032edeba73b212530ee01f3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:36 +0100 Subject: [PATCH 199/517] fix errors in unresolved weak symbols on arm lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f Signed-off-by: Felix Fietkau --- arch/arm/kernel/module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index da488d92e7a0..2c4772fc494d 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -112,6 +112,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, return -ENOEXEC; } + if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && + ELF_ST_BIND(sym->st_info) == STB_WEAK) + continue; + loc = dstsec->sh_addr + rel->r_offset; switch (ELF32_R_TYPE(rel->r_info)) { -- 2.51.0 From 52f2fac4a7eb8fb01f41028391e9f5686c11ecb6 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 3 Nov 2025 15:49:37 +0100 Subject: [PATCH 200/517] MIPS: kexec: Accept command line parameters from userspace. Signed-off-by: Yousong Zhou --- arch/mips/kernel/machine_kexec.c | 140 ++++++++++++++++++++++++++--- arch/mips/kernel/machine_kexec.h | 20 +++++ arch/mips/kernel/relocate_kernel.S | 20 +++-- 3 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 arch/mips/kernel/machine_kexec.h diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 4e3579bbd620..528880faad34 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -10,14 +10,11 @@ #include #include +#include #include #include - -extern const unsigned char relocate_new_kernel[]; -extern const size_t relocate_new_kernel_size; - -extern unsigned long kexec_start_address; -extern unsigned long kexec_indirection_page; +#include +#include "machine_kexec.h" static unsigned long reboot_code_buffer; @@ -31,6 +28,101 @@ void (*_crash_smp_send_stop)(void) = NULL; void (*_machine_kexec_shutdown)(void) = NULL; void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; +static void machine_kexec_print_args(void) +{ + unsigned long argc = (int)kexec_args[0]; + int i; + + pr_info("kexec_args[0] (argc): %lu\n", argc); + pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); + pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); + pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); + + for (i = 0; i < argc; i++) { + pr_info("kexec_argv[%d] = %p, %s\n", + i, kexec_argv[i], kexec_argv[i]); + } +} + +static void machine_kexec_init_argv(struct kimage *image) +{ + void __user *buf = NULL; + size_t bufsz; + size_t size; + int i; + + bufsz = 0; + for (i = 0; i < image->nr_segments; i++) { + struct kexec_segment *seg; + + seg = &image->segment[i]; + if (seg->bufsz < 6) + continue; + + if (strncmp((char *) seg->buf, "kexec ", 6)) + continue; + + buf = seg->buf; + bufsz = seg->bufsz; + break; + } + + if (!buf) + return; + + size = KEXEC_COMMAND_LINE_SIZE; + size = min(size, bufsz); + if (size < bufsz) + pr_warn("kexec command line truncated to %zd bytes\n", size); + + /* Copy to kernel space */ + if (copy_from_user(kexec_argv_buf, buf, size)) + pr_warn("kexec command line copy to kernel space failed\n"); + + kexec_argv_buf[size - 1] = 0; +} + +static void machine_kexec_parse_argv(struct kimage *image) +{ + char *reboot_code_buffer; + int reloc_delta; + char *ptr; + int argc; + int i; + + ptr = kexec_argv_buf; + argc = 0; + + /* + * convert command line string to array of parameters + * (as bootloader does). + */ + while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { + if (*ptr == ' ') { + *ptr++ = '\0'; + continue; + } + + kexec_argv[argc++] = ptr; + ptr = strchr(ptr, ' '); + } + + if (!argc) + return; + + kexec_args[0] = argc; + kexec_args[1] = (unsigned long)kexec_argv; + kexec_args[2] = 0; + kexec_args[3] = 0; + + reboot_code_buffer = page_address(image->control_code_page); + reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; + + kexec_args[1] += reloc_delta; + for (i = 0; i < argc; i++) + kexec_argv[i] += reloc_delta; +} + static void kexec_image_info(const struct kimage *kimage) { unsigned long i; @@ -100,6 +192,18 @@ machine_kexec_prepare(struct kimage *kimage) #endif kexec_image_info(kimage); + /* + * Whenever arguments passed from kexec-tools, Init the arguments as + * the original ones to try avoiding booting failure. + */ + + kexec_args[0] = fw_arg0; + kexec_args[1] = fw_arg1; + kexec_args[2] = fw_arg2; + kexec_args[3] = fw_arg3; + + machine_kexec_init_argv(kimage); + machine_kexec_parse_argv(kimage); if (_machine_kexec_prepare) return _machine_kexec_prepare(kimage); @@ -162,7 +266,7 @@ machine_crash_shutdown(struct pt_regs *regs) void kexec_nonboot_cpu_jump(void) { local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, - reboot_code_buffer + relocate_new_kernel_size); + reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); relocated_kexec_smp_wait(NULL); } @@ -200,7 +304,7 @@ void kexec_reboot(void) * machine_kexec() CPU. */ local_flush_icache_range(reboot_code_buffer, - reboot_code_buffer + relocate_new_kernel_size); + reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); do_kexec = (void *)reboot_code_buffer; do_kexec(); @@ -213,10 +317,12 @@ machine_kexec(struct kimage *image) unsigned long *ptr; reboot_code_buffer = - (unsigned long)page_address(image->control_code_page); + (unsigned long)page_address(image->control_code_page); + pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); kexec_start_address = (unsigned long) phys_to_virt(image->start); + pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); if (image->type == KEXEC_TYPE_DEFAULT) { kexec_indirection_page = @@ -224,9 +330,19 @@ machine_kexec(struct kimage *image) } else { kexec_indirection_page = (unsigned long)&image->head; } + pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + + pr_info("Where is memcpy: %p\n", memcpy); + pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", + (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); + pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, + (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); + memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, + KEXEC_RELOCATE_NEW_KERNEL_SIZE); - memcpy((void*)reboot_code_buffer, relocate_new_kernel, - relocate_new_kernel_size); + pr_info("Before _print_args().\n"); + machine_kexec_print_args(); + pr_info("Before eval loop.\n"); /* * The generic kexec code builds a page list with physical @@ -257,7 +373,7 @@ machine_kexec(struct kimage *image) #ifdef CONFIG_SMP /* All secondary cpus now may jump to kexec_wait cycle */ relocated_kexec_smp_wait = reboot_code_buffer + - (void *)(kexec_smp_wait - relocate_new_kernel); + (void *)(kexec_smp_wait - kexec_relocate_new_kernel); smp_wmb(); atomic_set(&kexec_ready_to_reboot, 1); #endif diff --git a/arch/mips/kernel/machine_kexec.h b/arch/mips/kernel/machine_kexec.h new file mode 100644 index 000000000000..ae0961e29820 --- /dev/null +++ b/arch/mips/kernel/machine_kexec.h @@ -0,0 +1,20 @@ +#ifndef _MACHINE_KEXEC_H +#define _MACHINE_KEXEC_H + +#ifndef __ASSEMBLY__ +extern const unsigned char kexec_relocate_new_kernel[]; +extern unsigned long kexec_relocate_new_kernel_end; +extern unsigned long kexec_start_address; +extern unsigned long kexec_indirection_page; + +extern char kexec_argv_buf[]; +extern char *kexec_argv[]; + +#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) +#endif /* !__ASSEMBLY__ */ + +#define KEXEC_COMMAND_LINE_SIZE 256 +#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) +#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) + +#endif diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index de894a0211d7..a43c683cfd2b 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -10,10 +10,11 @@ #include #include #include +#include "machine_kexec.h" #include -LEAF(relocate_new_kernel) +LEAF(kexec_relocate_new_kernel) PTR_L a0, arg0 PTR_L a1, arg1 PTR_L a2, arg2 @@ -97,7 +98,7 @@ done: #endif /* jump to kexec_start_address */ j s1 - END(relocate_new_kernel) + END(kexec_relocate_new_kernel) #ifdef CONFIG_SMP /* @@ -176,8 +177,15 @@ EXPORT(kexec_indirection_page) PTR_WD 0 .size kexec_indirection_page, PTRSIZE -relocate_new_kernel_end: +kexec_argv_buf: + EXPORT(kexec_argv_buf) + .skip KEXEC_COMMAND_LINE_SIZE + .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE -EXPORT(relocate_new_kernel_size) - PTR_WD relocate_new_kernel_end - relocate_new_kernel - .size relocate_new_kernel_size, PTRSIZE +kexec_argv: + EXPORT(kexec_argv) + .skip KEXEC_ARGV_SIZE + .size kexec_argv, KEXEC_ARGV_SIZE + +kexec_relocate_new_kernel_end: + EXPORT(kexec_relocate_new_kernel_end) -- 2.51.0 From 5c80cdad5775fcd000f09a0bc2895dd3c6140644 Mon Sep 17 00:00:00 2001 From: Evgeniy Didin Date: Fri, 15 Mar 2019 18:53:38 +0300 Subject: [PATCH 201/517] arc add OWRTDTB section This change allows OpenWRT to patch resulting kernel binary with external .dtb. That allows us to re-use exactky the same vmlinux on different boards given its ARC core configurations match (at least cache line sizes etc). ""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external .dtb right after it, keeping the string in place. Signed-off-by: Eugeniy Paltsev Signed-off-by: Alexey Brodkin Signed-off-by: Evgeniy Didin --- arch/arc/kernel/head.S | 10 ++++++++++ arch/arc/kernel/setup.c | 4 +++- arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S index 8d541f53fae3..c37f130c4bcc 100644 --- a/arch/arc/kernel/head.S +++ b/arch/arc/kernel/head.S @@ -88,6 +88,16 @@ DSP_EARLY_INIT .endm + ; Here "patch-dtb" will embed external .dtb + ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string + ; and pastes .dtb right after it, hense the string precedes + ; __image_dtb symbol. + .section .owrt, "aw",@progbits + .ascii "OWRTDTB:" +ENTRY(__image_dtb) + .fill 0x4000 +END(__image_dtb) + .section .init.text, "ax",@progbits ;---------------------------------------------------------------- diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 7b6a9beba9db..0d07dfea5c00 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -450,6 +450,8 @@ static inline bool uboot_arg_invalid(unsigned long addr) /* We always pass 0 as magic from U-boot */ #define UBOOT_MAGIC_VALUE 0 +extern struct boot_param_header __image_dtb; + void __init handle_uboot_args(void) { bool use_embedded_dtb = true; @@ -488,7 +490,7 @@ void __init handle_uboot_args(void) ignore_uboot_args: if (use_embedded_dtb) { - machine_desc = setup_machine_fdt(__dtb_start); + machine_desc = setup_machine_fdt(&__image_dtb); if (!machine_desc) panic("Embedded DT invalid\n"); } diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index 61a1b2b96e1d..eef52a1711dd 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S @@ -27,6 +27,19 @@ SECTIONS . = CONFIG_LINUX_LINK_BASE; + /* + * In OpenWRT we want to patch built binary embedding .dtb of choice. + * This is implemented with "patch-dtb" utility which searches for + * "OWRTDTB:" string in first 16k of image and if it is found + * copies .dtb right after mentioned string. + * + * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it. + */ + .owrt : { + *(.owrt) + . = ALIGN(PAGE_SIZE); + } + _int_vec_base_lds = .; .vector : { *(.vector) -- 2.51.0 From f935ead65589a7cd7b0ad26c3927095d6431cc61 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Mon, 3 Nov 2025 15:49:37 +0100 Subject: [PATCH 202/517] arc: enable unaligned access in kernel mode This enables misaligned access handling even in kernel mode. Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses here and there and to cope with that without fixing stuff in the drivers we're just gracefully handling it on ARC. Signed-off-by: Alexey Brodkin --- arch/arc/kernel/unaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c index d2f5ceaaed1b..691db93b7808 100644 --- a/arch/arc/kernel/unaligned.c +++ b/arch/arc/kernel/unaligned.c @@ -203,7 +203,7 @@ int misaligned_fixup(unsigned long address, struct pt_regs *regs, char buf[TASK_COMM_LEN]; /* handle user mode only and only if enabled by sysadmin */ - if (!user_mode(regs) || !unaligned_enabled) + if (!unaligned_enabled) return 1; if (no_unaligned_warning) { -- 2.51.0 From 1bcfd87046f51fc0cee1585efd6503f2ab964de2 Mon Sep 17 00:00:00 2001 From: Pawel Dembicki Date: Fri, 24 May 2019 17:56:19 +0200 Subject: [PATCH 203/517] powerpc: Enable kernel XZ compression option on PPC_85xx Enable kernel XZ compression option on PPC_85xx. Tested with simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor). Suggested-by: Christian Lamparter Signed-off-by: Pawel Dembicki --- arch/powerpc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c7b420d6787c..3ac7c2b165bf 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -254,7 +254,7 @@ config PPC select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE select HAVE_KERNEL_LZO if DEFAULT_UIMAGE - select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x + select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES -- 2.51.0 From 1d71b6137b632023a25f974e578be3d2c522c4d7 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Wed, 13 Mar 2024 20:28:37 +0800 Subject: [PATCH 204/517] mips: kernel: fix detect_memory_region() function 1. Do not use memcmp() on unallocated memory, as the new introduced fortify dynamic object size check[1] will report unexpected result. 2. Use a fixed pattern instead of a random function pointer as the magic value. 3. Flip magic value and double check it. 4. Enable this feature only for 32-bit CPUs. Currently, only ath79 and ralink CPUs are using it. [1] 439a1bcac648 ("fortify: Use __builtin_dynamic_object_size() when available") Signed-off-by: Shiji Yang --- arch/mips/include/asm/bootinfo.h | 2 ++ arch/mips/kernel/setup.c | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/bootinfo.h b/arch/mips/include/asm/bootinfo.h index 2128ba903391..8516c11916a4 100644 --- a/arch/mips/include/asm/bootinfo.h +++ b/arch/mips/include/asm/bootinfo.h @@ -93,7 +93,9 @@ const char *get_system_type(void); extern unsigned long mips_machtype; +#ifndef CONFIG_64BIT extern void detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max); +#endif extern void prom_init(void); extern void prom_free_prom_memory(void); diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 12a1a4ffb602..3a3bc1b7e62e 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -86,21 +86,27 @@ static struct resource bss_resource = { .name = "Kernel bss", }; unsigned long __kaslr_offset __ro_after_init; EXPORT_SYMBOL(__kaslr_offset); -static void *detect_magic __initdata = detect_memory_region; - #ifdef CONFIG_MIPS_AUTO_PFN_OFFSET unsigned long ARCH_PFN_OFFSET; EXPORT_SYMBOL(ARCH_PFN_OFFSET); #endif +#ifndef CONFIG_64BIT +static u32 detect_magic __initdata; +#define MIPS_MEM_TEST_PATTERN 0xaa5555aa + void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_addr_t sz_max) { - void *dm = &detect_magic; + void *dm = (void *)KSEG1ADDR(&detect_magic); phys_addr_t size; for (size = sz_min; size < sz_max; size <<= 1) { - if (!memcmp(dm, dm + size, sizeof(detect_magic))) - break; + __raw_writel(MIPS_MEM_TEST_PATTERN, dm); + if (__raw_readl(dm) == __raw_readl(dm + size)) { + __raw_writel(~MIPS_MEM_TEST_PATTERN, dm); + if (__raw_readl(dm) == __raw_readl(dm + size)) + break; + } } pr_debug("Memory: %lluMB of RAM detected at 0x%llx (min: %lluMB, max: %lluMB)\n", @@ -111,6 +117,7 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add memblock_add(start, size); } +#endif /* CONFIG_64BIT */ /* * Manage initrd -- 2.51.0 From ee65cfab6741cd60ae4734b50f82919a58205ae2 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 11:47:35 +0200 Subject: [PATCH 205/517] mtd: mtdsplit support --- drivers/mtd/Kconfig | 19 ++++ drivers/mtd/Makefile | 2 + drivers/mtd/mtdpart.c | 170 ++++++++++++++++++++++++++++----- include/linux/mtd/mtd.h | 25 +++++ include/linux/mtd/partitions.h | 7 ++ 5 files changed, 198 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 796a2eccbef0..f9ed93c4cf0f 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -12,6 +12,25 @@ menuconfig MTD if MTD +menu "OpenWrt specific MTD options" + +config MTD_ROOTFS_ROOT_DEV + bool "Automatically set 'rootfs' partition to be root filesystem" + default y + +config MTD_SPLIT_FIRMWARE + bool "Automatically split firmware partition for kernel+rootfs" + default y + +config MTD_SPLIT_FIRMWARE_NAME + string "Firmware partition name" + depends on MTD_SPLIT_FIRMWARE + default "firmware" + +source "drivers/mtd/mtdsplit/Kconfig" + +endmenu + config MTD_TESTS tristate "MTD tests support (DANGEROUS)" depends on m diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 593d0593a038..b14b7fe0f597 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o obj-y += parsers/ +obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ + # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o obj-$(CONFIG_MTD_BLOCK) += mtdblock.o diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6811a714349d..10ae49b9702a 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include #include "mtdcore.h" +#include "mtdsplit/mtdsplit.h" /* * MTD methods which simply translate the effective address and pass through @@ -242,6 +244,147 @@ static int mtd_add_partition_attrs(struct mtd_info *new) return ret; } +static DEFINE_SPINLOCK(part_parser_lock); +static LIST_HEAD(part_parsers); + +static struct mtd_part_parser *mtd_part_parser_get(const char *name) +{ + struct mtd_part_parser *p, *ret = NULL; + + spin_lock(&part_parser_lock); + + list_for_each_entry(p, &part_parsers, list) + if (!strcmp(p->name, name) && try_module_get(p->owner)) { + ret = p; + break; + } + + spin_unlock(&part_parser_lock); + + return ret; +} + +static inline void mtd_part_parser_put(const struct mtd_part_parser *p) +{ + module_put(p->owner); +} + +static struct mtd_part_parser * +get_partition_parser_by_type(enum mtd_parser_type type, + struct mtd_part_parser *start) +{ + struct mtd_part_parser *p, *ret = NULL; + + spin_lock(&part_parser_lock); + + p = list_prepare_entry(start, &part_parsers, list); + if (start) + mtd_part_parser_put(start); + + list_for_each_entry_continue(p, &part_parsers, list) { + if (p->type == type && try_module_get(p->owner)) { + ret = p; + break; + } + } + + spin_unlock(&part_parser_lock); + + return ret; +} + +static int parse_mtd_partitions_by_type(struct mtd_info *master, + enum mtd_parser_type type, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_part_parser *prev = NULL; + int ret = 0; + + while (1) { + struct mtd_part_parser *parser; + + parser = get_partition_parser_by_type(type, prev); + if (!parser) + break; + + ret = (*parser->parse_fn)(master, pparts, data); + + if (ret > 0) { + mtd_part_parser_put(parser); + printk(KERN_NOTICE + "%d %s partitions found on MTD device %s\n", + ret, parser->name, master->name); + break; + } + + prev = parser; + } + + return ret; +} + +static int +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type) +{ + struct mtd_partition *parts; + int nr_parts; + int i; + + nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts, + NULL); + if (nr_parts <= 0) + return nr_parts; + + if (WARN_ON(!parts)) + return 0; + + for (i = 0; i < nr_parts; i++) { + /* adjust partition offsets */ + parts[i].offset += child->part.offset; + + mtd_add_partition(child->parent, + parts[i].name, + parts[i].offset, + parts[i].size); + } + + kfree(parts); + + return nr_parts; +} + +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME +#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME +#else +#define SPLIT_FIRMWARE_NAME "unused" +#endif + +static void split_firmware(struct mtd_info *master, struct mtd_info *part) +{ + run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); +} + +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part) +{ + static int rootfs_found = 0; + + if (rootfs_found) + return; + + if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) || + !strcmp(part->name, "rootfs")) { + run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); + + rootfs_found = 1; + } + + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) && + !strcmp(part->name, SPLIT_FIRMWARE_NAME) && + !of_find_property(mtd_get_of_node(part), "compatible", NULL)) + split_firmware(master, part); +} + int mtd_add_partition(struct mtd_info *parent, const char *name, long long offset, long long length) { @@ -280,6 +423,7 @@ int mtd_add_partition(struct mtd_info *parent, const char *name, if (ret) goto err_remove_part; + mtd_partition_split(parent, child); mtd_add_partition_attrs(child); return 0; @@ -423,6 +567,7 @@ int add_mtd_partitions(struct mtd_info *parent, goto err_del_partitions; } + mtd_partition_split(master, child); mtd_add_partition_attrs(child); /* Look for subpartitions */ @@ -443,31 +588,6 @@ int add_mtd_partitions(struct mtd_info *parent, return ret; } -static DEFINE_SPINLOCK(part_parser_lock); -static LIST_HEAD(part_parsers); - -static struct mtd_part_parser *mtd_part_parser_get(const char *name) -{ - struct mtd_part_parser *p, *ret = NULL; - - spin_lock(&part_parser_lock); - - list_for_each_entry(p, &part_parsers, list) - if (!strcmp(p->name, name) && try_module_get(p->owner)) { - ret = p; - break; - } - - spin_unlock(&part_parser_lock); - - return ret; -} - -static inline void mtd_part_parser_put(const struct mtd_part_parser *p) -{ - module_put(p->owner); -} - /* * Many partition parsers just expected the core to kfree() all their data in * one chunk. Do that by default. diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 8d10d9d2e830..ed22b5e4cfc6 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(struct mtd_info *mtd, req->len += mtd->erasesize - mod; } +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd_mod_by_eb(sz, mtd) == 0) + return sz; + + /* Round up to next erase block */ + return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; +} + +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) +{ + if (mtd_mod_by_eb(sz, mtd) == 0) + return sz; + + /* Round down to the start of the current erase block */ + return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; +} + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) { if (mtd->writesize_shift) @@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np); extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd) +{ + if (!mtd_is_partition(mtd)) + return 0; + + return mtd->part.offset; +} struct mtd_notifier { void (*add)(struct mtd_info *mtd); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index b74a539ec581..65ba0dbf961d 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -75,6 +75,12 @@ struct mtd_part_parser_data { * Functions dealing with the various ways of partitioning the space */ +enum mtd_parser_type { + MTD_PARSER_TYPE_DEVICE = 0, + MTD_PARSER_TYPE_ROOTFS, + MTD_PARSER_TYPE_FIRMWARE, +}; + struct mtd_part_parser { struct list_head list; struct module *owner; @@ -83,6 +89,7 @@ struct mtd_part_parser { int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, struct mtd_part_parser_data *); void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); + enum mtd_parser_type type; }; /* Container for passing around a set of parsed partitions */ -- 2.51.0 From b1bb268ee57b27be82e74377901ac602f9d049e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 31 Oct 2023 15:51:01 +0100 Subject: [PATCH 206/517] mtd: don't register NVMEM devices for partitions with custom drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes issue exposed by upstream commit f4cf4e5db331 ("Revert "nvmem: add new config option""). Signed-off-by: Rafał Miłecki --- drivers/mtd/mtdcore.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 724f917f91ba..0aa3f8e44fa1 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -549,6 +549,29 @@ static int mtd_nvmem_add(struct mtd_info *mtd) struct device_node *node = mtd_get_of_node(mtd); struct nvmem_config config = {}; + /* + * Do NOT register NVMEM device for any partition that is meant to be + * handled by a U-Boot env driver. That would result in associating two + * different NVMEM devices with the same OF node. + * + * An example of unwanted behaviour of above (forwardtrace): + * of_get_mac_addr_nvmem() + * of_nvmem_cell_get() + * __nvmem_device_get() + * + * We can't have __nvmem_device_get() return "mtdX" NVMEM device instead + * of U-Boot env NVMEM device. That would result in failing to find + * NVMEM cell. + * + * This issue seems to affect U-Boot env case only and will go away with + * switch to NVMEM layouts. + */ + if (of_device_is_compatible(node, "u-boot,env") || + of_device_is_compatible(node, "u-boot,env-redundant-bool") || + of_device_is_compatible(node, "u-boot,env-redundant-count") || + of_device_is_compatible(node, "brcm,env")) + return 0; + config.id = NVMEM_DEVID_NONE; config.dev = &mtd->dev; config.name = dev_name(&mtd->dev); -- 2.51.0 From afeb87fd61a00460b0302e447b98e086f03485a7 Mon Sep 17 00:00:00 2001 From: John Thomson Date: Fri, 25 Dec 2020 18:50:08 +1000 Subject: [PATCH 207/517] mtd: spi-nor: write support for minor aligned partitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not prevent writing to mtd partitions where a partition boundary sits on a minor erasesize boundary. This addresses a FIXME that has been present since the start of the linux git history: /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ Allow a uniform erase region spi-nor device to be configured to use the non-uniform erase regions code path for an erase with: CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y On supporting hardware (SECT_4K: majority of current SPI-NOR device) provide the facility for an erase to use the least number of SPI-NOR operations, as well as access to 4K erase without requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS Introduce erasesize_minor to the mtd struct, the smallest erasesize supported by the device On existing devices, this is useful where write support is wanted for data on a 4K partition, such as some u-boot-env partitions, or RouterBoot soft_config, while still netting the performance benefits of using 64K sectors Performance: time mtd erase firmware OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length Without this patch MTD_SPI_NOR_USE_4K_SECTORS=y |n real 2m 11.66s |0m 50.86s user 0m 0.00s |0m 0.00s sys 1m 56.20s |0m 50.80s With this patch MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y real 0m 51.68s |0m 50.85s |2m 12.89s user 0m 0.00s |0m 0.00s |0m 0.01s sys 0m 46.94s |0m 50.38s |2m 12.46s Signed-off-by: John Thomson Signed-off-by: Thibaut VARÈNE --- drivers/mtd/mtdcore.c | 10 ++++++++++ drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++---------- drivers/mtd/spi-nor/Kconfig | 10 ++++++++++ drivers/mtd/spi-nor/core.c | 11 +++++++++-- include/linux/mtd/mtd.h | 2 ++ 5 files changed, 56 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 0aa3f8e44fa1..6b98d581ceeb 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -199,6 +199,15 @@ static ssize_t mtd_erasesize_show(struct device *dev, } MTD_DEVICE_ATTR_RO(erasesize); +static ssize_t mtd_erasesize_minor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor); +} +MTD_DEVICE_ATTR_RO(erasesize_minor); + static ssize_t mtd_writesize_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -344,6 +353,7 @@ static struct attribute *mtd_attrs[] = { &dev_attr_flags.attr, &dev_attr_size.attr, &dev_attr_erasesize.attr, + &dev_attr_erasesize_minor.attr, &dev_attr_writesize.attr, &dev_attr_subpagesize.attr, &dev_attr_oobsize.attr, diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 10ae49b9702a..58eb32021874 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -47,6 +47,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, struct mtd_info *master = mtd_get_master(parent); int wr_alignment = (parent->flags & MTD_NO_ERASE) ? master->writesize : master->erasesize; + int wr_alignment_minor = 0; u64 parent_size = mtd_is_partition(parent) ? parent->part.size : parent->size; struct mtd_info *child; @@ -171,6 +172,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, } else { /* Single erase size */ child->erasesize = master->erasesize; + child->erasesize_minor = master->erasesize_minor; } /* @@ -178,26 +180,39 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, * exposes several regions with different erasesize. Adjust * wr_alignment accordingly. */ - if (!(child->flags & MTD_NO_ERASE)) + if (!(child->flags & MTD_NO_ERASE)) { wr_alignment = child->erasesize; + wr_alignment_minor = child->erasesize_minor; + } tmp = mtd_get_master_ofs(child, 0); remainder = do_div(tmp, wr_alignment); if ((child->flags & MTD_WRITEABLE) && remainder) { - /* Doesn't start on a boundary of major erase size */ - /* FIXME: Let it be writable if it is on a boundary of - * _minor_ erase size though */ - child->flags &= ~MTD_WRITEABLE; - printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", - part->name); + if (wr_alignment_minor) { + /* rely on minor being a factor of major erasesize */ + tmp = remainder; + remainder = do_div(tmp, wr_alignment_minor); + } + if (remainder) { + child->flags &= ~MTD_WRITEABLE; + printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", + part->name); + } } tmp = mtd_get_master_ofs(child, 0) + child->part.size; remainder = do_div(tmp, wr_alignment); if ((child->flags & MTD_WRITEABLE) && remainder) { - child->flags &= ~MTD_WRITEABLE; - printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", - part->name); + if (wr_alignment_minor) { + tmp = remainder; + remainder = do_div(tmp, wr_alignment_minor); + } + + if (remainder) { + child->flags &= ~MTD_WRITEABLE; + printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", + part->name); + } } child->size = child->part.size; diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 24cd25de2b8b..09df9f1a8127 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR if MTD_SPI_NOR +config MTD_SPI_NOR_USE_VARIABLE_ERASE + bool "Disable uniform_erase to allow use of all hardware supported erasesizes" + depends on !MTD_SPI_NOR_USE_4K_SECTORS + default n + help + Allow mixed use of all hardware supported erasesizes, + by forcing spi_nor to use the multiple eraseregions code path. + For example: A 68K erase will use one 64K erase, and one 4K erase + on supporting hardware. + config MTD_SPI_NOR_USE_4K_SECTORS bool "Use small 4096 B erase sectors" default y diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 9d6e85bf227b..8da860d84e6d 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1158,6 +1158,8 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) { + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE)) + return false; return !!nor->params->erase_map.uniform_region.erase_mask; } @@ -2516,6 +2518,7 @@ static int spi_nor_select_erase(struct spi_nor *nor) { struct spi_nor_erase_map *map = &nor->params->erase_map; const struct spi_nor_erase_type *erase = NULL; + const struct spi_nor_erase_type *erase_minor = NULL; struct mtd_info *mtd = &nor->mtd; int i; @@ -2542,8 +2545,9 @@ static int spi_nor_select_erase(struct spi_nor *nor) */ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { if (map->erase_type[i].size) { - erase = &map->erase_type[i]; - break; + if (!erase) + erase = &map->erase_type[i]; + erase_minor = &map->erase_type[i]; } } @@ -2551,6 +2555,9 @@ static int spi_nor_select_erase(struct spi_nor *nor) return -EINVAL; mtd->erasesize = erase->size; + if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) && + erase_minor && erase_minor->size < erase->size) + mtd->erasesize_minor = erase_minor->size; return 0; } diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index ed22b5e4cfc6..86f7efa43faa 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -245,6 +245,8 @@ struct mtd_info { * information below if they desire */ uint32_t erasesize; + /* "Minor" (smallest) erase size supported by the whole device */ + uint32_t erasesize_minor; /* Minimal writable flash unit size. In case of NOR flash it is 1 (even * though individual bits can be cleared), in case of NAND flash it is * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR -- 2.51.0 From c1e81cf689836ae1cc7a75f0d3b749cf98818a0e Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Sun, 3 Aug 2025 17:23:27 +0300 Subject: [PATCH 208/517] mtd: spinand: fix direct mapping creation sizes Continuous mode is only supported for data reads, thus writing requires only single flash page mapping. Signed-off-by: Mikhail Kshevetskiy --- drivers/mtd/nand/spi/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 8e4c825b9789..abae584de706 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1028,18 +1028,13 @@ static int spinand_create_dirmap(struct spinand_device *spinand, unsigned int plane) { struct nand_device *nand = spinand_to_nand(spinand); - struct spi_mem_dirmap_info info = { - .length = nanddev_page_size(nand) + - nanddev_per_page_oobsize(nand), - }; + struct spi_mem_dirmap_info info = { 0 }; struct spi_mem_dirmap_desc *desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); - /* The plane number is passed in MSB just above the column address */ info.offset = plane << fls(nand->memorg.pagesize); + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); info.op_tmpl = *spinand->op_templates.update_cache; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); @@ -1048,6 +1043,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; + if (spinand->cont_read_possible) + info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); @@ -1063,6 +1060,7 @@ static int spinand_create_dirmap(struct spinand_device *spinand, return 0; } + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); info.op_tmpl = *spinand->op_templates.update_cache; info.op_tmpl.data.ecc = true; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, @@ -1072,6 +1070,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc_ecc = desc; + if (spinand->cont_read_possible) + info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; info.op_tmpl.data.ecc = true; desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, -- 2.51.0 From f2aa382fe9e8fd76760cbd59e6463011f116ca30 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Sun, 3 Aug 2025 19:06:40 +0300 Subject: [PATCH 209/517] mtd: spinand: try a regular dirmap if creating a dirmap for continuous reading fails Continuous reading may result in multiple flash pages reading in one operation. Typically only one flash page has read/written (a little bit more than 2-4 Kb), but continuous reading requires the spi controller to read up to 512 Kb in one operation without toggling CS in beetween. Roughly speaking spi controllers can be divided on 2 categories: * spi controllers without dirmap acceleration support * spi controllers with dirmap acceleration support Firt of them will have issues with continuous reading if restriction on the transfer length is implemented in the adjust_op_size() handler. Second group often supports acceleration of single page only reading. Thus enabling of continuous reading can break flash reading. This patch tries to create dirmap for continuous reading first and fallback to regular reading if spi controller refuses to create it. Signed-off-by: Mikhail Kshevetskiy --- drivers/mtd/nand/spi/core.c | 43 ++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index abae584de706..cb96b9cd2a73 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1024,6 +1024,39 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs) return ret; } +static struct spi_mem_dirmap_desc *spinand_create_rdesc( + struct spinand_device *spinand, + struct spi_mem_dirmap_info *info) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct spi_mem_dirmap_desc *desc = NULL; + + if (spinand->cont_read_possible) { + /* + * spi controller may return an error if info->length is + * too large + */ + info->length = nanddev_eraseblock_size(nand); + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, info); + } + + if (IS_ERR_OR_NULL(desc)) { + /* + * continuous reading is not supported by flash or + * its spi controller, use regular reading + */ + spinand->cont_read_possible = false; + + info->length = nanddev_page_size(nand) + + nanddev_per_page_oobsize(nand); + desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, + spinand->spimem, info); + } + + return desc; +} + static int spinand_create_dirmap(struct spinand_device *spinand, unsigned int plane) { @@ -1043,11 +1076,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc = desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); + desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -1070,12 +1100,9 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].wdesc_ecc = desc; - if (spinand->cont_read_possible) - info.length = nanddev_eraseblock_size(nand); info.op_tmpl = *spinand->op_templates.read_cache; info.op_tmpl.data.ecc = true; - desc = devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); + desc = spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); -- 2.51.0 From e713688e842578fcfa97303206ae0b1f7c3da4bc Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Sun, 3 Aug 2025 17:54:17 +0300 Subject: [PATCH 210/517] mtd: spinand: repeat reading in regular mode if continuous reading fails Continuous reading may result in multiple flash pages reading in one operation. Unfortunately, not all spinand controllers support such large reading. They will read less data. Unfortunately, the operation can't be continued. In this case: * disable continuous reading on this (not good enough) spi controller * repeat reading in regular mode. Signed-off-by: Mikhail Kshevetskiy --- drivers/mtd/nand/spi/core.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index cb96b9cd2a73..f3787a63a355 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -427,8 +427,16 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, * Dirmap accesses are allowed to toggle the CS. * Toggling the CS during a continuous read is forbidden. */ - if (nbytes && req->continuous) - return -EIO; + if (nbytes && req->continuous) { + /* + * Spi controller with broken support of continuous + * reading was detected. Disable future use of + * continuous reading and return -EAGAIN to retry + * reading within regular mode. + */ + spinand->cont_read_possible = false; + return -EAGAIN; + } } if (req->datalen) @@ -841,10 +849,19 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, old_stats = mtd->ecc_stats; - if (spinand_use_cont_read(mtd, from, ops)) + if (spinand_use_cont_read(mtd, from, ops)) { ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips); - else + if (ret == -EAGAIN && !spinand->cont_read_possible) { + /* + * Spi controller with broken support of continuous + * reading was detected (see spinand_read_from_cache_op()), + * repeat reading in regular mode. + */ + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); + } + } else { ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); + } if (ops->stats) { ops->stats->uncorrectable_errors += -- 2.51.0 From 59fce38e6f0e95196bc9523cf5447c5aa1f597bc Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 1 May 2025 18:19:16 +0200 Subject: [PATCH 211/517] spi: spi-qpic-snand: validate user/chip specific ECC properties The driver only supports 512 bytes ECC step size and 4 bit ECC strength at the moment, however it does not reject unsupported step/strength configurations. Due to this, whenever the driver is used with a flash chip which needs stronger ECC protection, the following warning is shown in the kernel log: [ 0.574648] spi-nand spi0.0: GigaDevice SPI NAND was found. [ 0.635748] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128 [ 0.649079] nand: WARNING: (null): the ECC used on your system is too weak compared to the one required by the NAND chip Although the message indicates that something is wrong, but it often gets unnoticed, which can cause serious problems. For example when the user writes something into the flash chip despite the warning, the written data may won't be readable by the bootloader or by the boot ROM. In the worst case, when the attached SPI NAND chip is the boot device, the board may not be able to boot anymore. Also, it is not even possible to create a backup of the flash, because reading its content results in bogus data. For example, dumping the first page of the flash gives this: # hexdump -C -n 2048 /dev/mtd0 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000040 0f 0f 0f 0f 0f 0f 0f 0d 0f 0f 0f 0f 0f 0f 0f 0f |................| 00000050 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 000001c0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| 000001d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000200 0f 0f 0f 0f f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.....[..........| 00000210 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 000002f0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 1f 0f 0f |................| 00000300 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 000003c0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f ff 0f 0f 0f |................| 000003d0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000400 0f 0f 0f 0f 0f 0f 0f 0f e9 74 c9 06 f5 5b ff ff |.........t...[..| 00000410 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 000005d0 0f 0f 0f 0f ff 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| 000005e0 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000600 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f c6 be 0f c3 |................| 00000610 e9 74 c9 06 f5 5b ff ff 0f 0f 0f 0f 0f 0f 0f 0f |.t...[..........| 00000620 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000770 0f 0f 0f 0f 8f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| 00000780 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000800 # Doing the same by using the downstream kernel results in different output: # hexdump -C -n 2048 /dev/mtd0 00000000 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f |................| * 00000800 # This patch adds some sanity checks to the code to prevent using the driver with unsupported ECC step/strength configurations. After the change, probing of the driver fails in such cases: [ 0.655038] spi-nand spi0.0: GigaDevice SPI NAND was found. [ 0.659159] spi-nand spi0.0: 256 MiB, block size: 128 KiB, page size: 2048, OOB size: 128 [ 0.669138] qcom_snand 79b0000.spi: only 4 bits ECC strength is supported [ 0.677476] nand: No suitable ECC configuration [ 0.689909] spi-nand spi0.0: probe with driver spi-nand failed with error -95 This helps to avoid the aforementioned hassles until support for 8 bit ECC strength gets implemented. Fixes: 7304d1909080 ("spi: spi-qpic: add driver for QCOM SPI NAND flash Interface") Signed-off-by: Gabor Juhos --- drivers/spi/spi-qpic-snand.c | 42 +++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 98d32d269d55..3fa50db3b824 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -249,9 +249,11 @@ static const struct mtd_ooblayout_ops qcom_spi_ooblayout = { static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) { struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand); + struct nand_ecc_props *reqs = &nand->ecc.requirements; + struct nand_ecc_props *user = &nand->ecc.user_conf; struct nand_ecc_props *conf = &nand->ecc.ctx.conf; struct mtd_info *mtd = nanddev_to_mtd(nand); - int cwperpage, bad_block_byte; + int cwperpage, bad_block_byte, ret; struct qpic_ecc *ecc_cfg; cwperpage = mtd->writesize / NANDC_STEP_SIZE; @@ -260,11 +262,39 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL); if (!ecc_cfg) return -ENOMEM; + + if (user->step_size && user->strength) { + ecc_cfg->step_size = user->step_size; + ecc_cfg->strength = user->strength; + } else if (reqs->step_size && reqs->strength) { + ecc_cfg->step_size = reqs->step_size; + ecc_cfg->strength = reqs->strength; + } else { + /* use defaults */ + ecc_cfg->step_size = NANDC_STEP_SIZE; + ecc_cfg->strength = 4; + } + + if (ecc_cfg->step_size != NANDC_STEP_SIZE) { + dev_err(snandc->dev, + "only %u bytes ECC step size is supported\n", + NANDC_STEP_SIZE); + ret = -EOPNOTSUPP; + goto err_free_ecc_cfg; + } + + if (ecc_cfg->strength != 4) { + dev_err(snandc->dev, + "only 4 bits ECC strength is supported\n"); + ret = -EOPNOTSUPP; + goto err_free_ecc_cfg; + } + snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!snandc->qspi->oob_buf) { - kfree(ecc_cfg); - return -ENOMEM; + ret = -ENOMEM; + goto err_free_ecc_cfg; } memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize); @@ -279,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; ecc_cfg->steps = 4; - ecc_cfg->strength = 4; - ecc_cfg->step_size = 512; ecc_cfg->cw_data = 516; ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes; bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1; @@ -338,6 +366,10 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) ecc_cfg->strength, ecc_cfg->step_size); return 0; + +err_free_ecc_cfg: + kfree(ecc_cfg); + return ret; } static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand) -- 2.51.0 From de42aad3a7d57d9e1d896b8e613a62c35cdf4201 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 2 May 2025 21:31:16 +0200 Subject: [PATCH 212/517] mtd: nand: qpic-common: add defines for ECC_MODE values Add defines for the values of the ECC_MODE field of the NAND_DEV0_ECC_CFG register and change both the 'qcom-nandc' and 'spi-qpic-snand' drivers to use those instead of magic numbers. No functional changes. This is in preparation for adding 8 bit ECC strength support for the 'spi-qpic-snand' driver. Signed-off-by: Gabor Juhos --- drivers/mtd/nand/raw/qcom_nandc.c | 6 +++--- drivers/spi/spi-qpic-snand.c | 2 +- include/linux/mtd/nand-qpic-common.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index c3b26fee55a8..efceee833abc 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); int cwperpage, bad_block_byte, ret; bool wide_bus; - int ecc_mode = 1; + int ecc_mode = ECC_MODE_8BIT; /* controller only supports 512 bytes data steps */ ecc->size = NANDC_STEP_SIZE; @@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) if (ecc->strength >= 8) { /* 8 bit ECC defaults to BCH ECC on all platforms */ host->bch_enabled = true; - ecc_mode = 1; + ecc_mode = ECC_MODE_8BIT; if (wide_bus) { host->ecc_bytes_hw = 14; @@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip) if (nandc->props->ecc_modes & ECC_BCH_4BIT) { /* BCH */ host->bch_enabled = true; - ecc_mode = 0; + ecc_mode = ECC_MODE_4BIT; if (wide_bus) { host->ecc_bytes_hw = 8; diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 3fa50db3b824..d1b32453d33b 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -349,7 +349,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) FIELD_PREP(ECC_SW_RESET, 0) | FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | - FIELD_PREP(ECC_MODE_MASK, 0) | + FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) | FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; diff --git a/include/linux/mtd/nand-qpic-common.h b/include/linux/mtd/nand-qpic-common.h index 7760154de581..00c718a22a6f 100644 --- a/include/linux/mtd/nand-qpic-common.h +++ b/include/linux/mtd/nand-qpic-common.h @@ -101,6 +101,8 @@ #define ECC_SW_RESET BIT(1) #define ECC_MODE 4 #define ECC_MODE_MASK GENMASK(5, 4) +#define ECC_MODE_4BIT 0 +#define ECC_MODE_8BIT 1 #define ECC_PARITY_SIZE_BYTES_BCH 8 #define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8) #define ECC_NUM_DATA_BYTES 16 -- 2.51.0 From 52969428d8075f5f312e7e6ac566fc4fa7b3bd6c Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Fri, 2 May 2025 21:31:17 +0200 Subject: [PATCH 213/517] spi: spi-qpic-snand: add support for 8 bits ECC strength Even though the hardware supports 8 bits ECC strength, but that is not handled in the driver yet. This change adds the missing bits in order to allow using the driver with chips which require 8 bits ECC strength. No functional changes intended with regard to the existing 4 bits ECC strength support. Tested on an IPQ9574 platform using a GigaDevice GD5F2GM7REYIG chip. Signed-off-by: Gabor Juhos --- drivers/spi/spi-qpic-snand.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index d1b32453d33b..79e815062db7 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -283,9 +283,22 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) goto err_free_ecc_cfg; } - if (ecc_cfg->strength != 4) { + switch (ecc_cfg->strength) { + case 4: + ecc_cfg->ecc_mode = ECC_MODE_4BIT; + ecc_cfg->ecc_bytes_hw = 7; + ecc_cfg->spare_bytes = 4; + break; + + case 8: + ecc_cfg->ecc_mode = ECC_MODE_8BIT; + ecc_cfg->ecc_bytes_hw = 13; + ecc_cfg->spare_bytes = 2; + break; + + default: dev_err(snandc->dev, - "only 4 bits ECC strength is supported\n"); + "only 4 or 8 bits ECC strength is supported\n"); ret = -EOPNOTSUPP; goto err_free_ecc_cfg; } @@ -302,8 +315,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) nand->ecc.ctx.priv = ecc_cfg; snandc->qspi->mtd = mtd; - ecc_cfg->ecc_bytes_hw = 7; - ecc_cfg->spare_bytes = 4; ecc_cfg->bbm_size = 1; ecc_cfg->bch_enabled = true; ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size; @@ -349,7 +360,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand) FIELD_PREP(ECC_SW_RESET, 0) | FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) | FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) | - FIELD_PREP(ECC_MODE_MASK, ECC_MODE_4BIT) | + FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) | FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw); ecc_cfg->ecc_buf_cfg = 0x203 << NUM_STEPS; -- 2.51.0 From 8475879cf5aeed333f5a449a806f4e54afa7cf9d Mon Sep 17 00:00:00 2001 From: Chukun Pan Date: Tue, 10 Jun 2025 23:10:16 +0800 Subject: [PATCH 214/517] mtd: spi-nand: macronix: disable continuous read for MX35LFxGE4AD In on-die ECC mode, enabling continuous read will cause ubi_io_read error. [ 7.852000] ubi0 warning: ubi_io_read: error -5 while reading ... So disable it first. Tested on GL.iNet GL-MT3000 with MX35LF2GE4AD flash. Fixes: 11813857864f ("mtd: spi-nand: macronix: Continuous read support") Signed-off-by: Chukun Pan --- drivers/mtd/nand/spi/macronix.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index d277c3220fdc..49ee3fd4581f 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -167,8 +167,7 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - macronix_ecc_get_status), - SPINAND_CONT_READ(macronix_set_cont_read)), + macronix_ecc_get_status)), SPINAND_INFO("MX35LF4GE4AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03), NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1), @@ -178,8 +177,7 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - macronix_ecc_get_status), - SPINAND_CONT_READ(macronix_set_cont_read)), + macronix_ecc_get_status)), SPINAND_INFO("MX35LF1G24AD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), -- 2.51.0 From df45909871c0bf05bc62ee888a5d45230be19f27 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:41 +0100 Subject: [PATCH 215/517] add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable) [john@phrozen.org: used by ixp and others] lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00 Signed-off-by: Felix Fietkau --- drivers/mtd/parsers/redboot.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/parsers/redboot.c b/drivers/mtd/parsers/redboot.c index 3b55b676ca6b..979427ffef9e 100644 --- a/drivers/mtd/parsers/redboot.c +++ b/drivers/mtd/parsers/redboot.c @@ -278,14 +278,21 @@ static int parse_redboot_partitions(struct mtd_info *master, #endif names += strlen(names) + 1; -#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { - i++; - parts[i].offset = parts[i - 1].size + parts[i - 1].offset; - parts[i].size = fl->next->img->flash_base - parts[i].offset; - parts[i].name = nullname; - } + if (!strcmp(parts[i].name, "rootfs")) { + parts[i].size = fl->next->img->flash_base; + parts[i].size &= ~(master->erasesize - 1); + parts[i].size -= parts[i].offset; +#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + nrparts--; + } else { + i++; + parts[i].offset = parts[i-1].size + parts[i-1].offset; + parts[i].size = fl->next->img->flash_base - parts[i].offset; + parts[i].name = nullname; #endif + } + } tmp_fl = fl; fl = fl->next; kfree(tmp_fl); -- 2.51.0 From 683715c54bf280f2544981603e8a8ea167738833 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 3 Nov 2025 15:49:41 +0100 Subject: [PATCH 216/517] Add myloader partition table parser [john@phozen.org: shoud be upstreamable] lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8 Signed-off-by: Florian Fainelli [adjust for kernel 5.4, add myloader.c to patch] Signed-off-by: Adrian Schmutzler --- drivers/mtd/parsers/Kconfig | 16 +++ drivers/mtd/parsers/Makefile | 1 + drivers/mtd/parsers/myloader.c | 181 +++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/mtd/parsers/myloader.c diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index da03ab6efe04..879d193f83f7 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -62,6 +62,22 @@ config MTD_CMDLINE_PARTS If unsure, say 'N'. +config MTD_MYLOADER_PARTS + tristate "MyLoader partition parsing" + depends on ADM5120 || ATH79 + help + MyLoader is a bootloader which allows the user to define partitions + in flash devices, by putting a table in the second erase block + on the device, similar to a partition table. This table gives the + offsets and lengths of the user defined partitions. + + If you need code which can detect and parse these tables, and + register MTD 'partitions' corresponding to each image detected, + enable this option. + + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. + config MTD_OF_PARTS tristate "OpenFirmware (device tree) partitioning parser" default y diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index 9b00c62b837a..e3d3ade33a48 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o obj-$(CONFIG_MTD_BRCM_U_BOOT) += brcm_u-boot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o +obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o ofpart-y += ofpart_core.o ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o diff --git a/drivers/mtd/parsers/myloader.c b/drivers/mtd/parsers/myloader.c new file mode 100644 index 000000000000..50ed8b197ed2 --- /dev/null +++ b/drivers/mtd/parsers/myloader.c @@ -0,0 +1,181 @@ +/* + * Parse MyLoader-style flash partition tables and produce a Linux partition + * array to match. + * + * Copyright (C) 2007-2009 Gabor Juhos + * + * This file was based on drivers/mtd/redboot.c + * Author: Red Hat, Inc. - David Woodhouse + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BLOCK_LEN_MIN 0x10000 +#define PART_NAME_LEN 32 + +struct part_data { + struct mylo_partition_table tab; + char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; +}; + +static int myloader_parse_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct part_data *buf; + struct mylo_partition_table *tab; + struct mylo_partition *part; + struct mtd_partition *mtd_parts; + struct mtd_partition *mtd_part; + int num_parts; + int ret, i; + size_t retlen; + char *names; + unsigned long offset; + unsigned long blocklen; + + buf = vmalloc(sizeof(*buf)); + if (!buf) { + return -ENOMEM; + goto out; + } + tab = &buf->tab; + + blocklen = master->erasesize; + if (blocklen < BLOCK_LEN_MIN) + blocklen = BLOCK_LEN_MIN; + + offset = blocklen; + + /* Find the partition table */ + for (i = 0; i < 4; i++, offset += blocklen) { + printk(KERN_DEBUG "%s: searching for MyLoader partition table" + " at offset 0x%lx\n", master->name, offset); + + ret = mtd_read(master, offset, sizeof(*buf), &retlen, + (void *)buf); + if (ret) + goto out_free_buf; + + if (retlen != sizeof(*buf)) { + ret = -EIO; + goto out_free_buf; + } + + /* Check for Partition Table magic number */ + if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) + break; + + } + + if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { + printk(KERN_DEBUG "%s: no MyLoader partition table found\n", + master->name); + ret = 0; + goto out_free_buf; + } + + /* The MyLoader and the Partition Table is always present */ + num_parts = 2; + + /* Detect number of used partitions */ + for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { + part = &tab->partitions[i]; + + if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) + continue; + + num_parts++; + } + + mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + + num_parts * PART_NAME_LEN), GFP_KERNEL); + + if (!mtd_parts) { + ret = -ENOMEM; + goto out_free_buf; + } + + mtd_part = mtd_parts; + names = (char *)&mtd_parts[num_parts]; + + strncpy(names, "myloader", PART_NAME_LEN); + mtd_part->name = names; + mtd_part->offset = 0; + mtd_part->size = offset; + mtd_part->mask_flags = MTD_WRITEABLE; + mtd_part++; + names += PART_NAME_LEN; + + strncpy(names, "partition_table", PART_NAME_LEN); + mtd_part->name = names; + mtd_part->offset = offset; + mtd_part->size = blocklen; + mtd_part->mask_flags = MTD_WRITEABLE; + mtd_part++; + names += PART_NAME_LEN; + + for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { + part = &tab->partitions[i]; + + if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) + continue; + + if ((buf->names[i][0]) && (buf->names[i][0] != '\xff')) + strncpy(names, buf->names[i], PART_NAME_LEN); + else + snprintf(names, PART_NAME_LEN, "partition%d", i); + + mtd_part->offset = le32_to_cpu(part->addr); + mtd_part->size = le32_to_cpu(part->size); + mtd_part->name = names; + mtd_part++; + names += PART_NAME_LEN; + } + + *pparts = mtd_parts; + ret = num_parts; + + out_free_buf: + vfree(buf); + out: + return ret; +} + +static struct mtd_part_parser myloader_mtd_parser = { + .owner = THIS_MODULE, + .parse_fn = myloader_parse_partitions, + .name = "MyLoader", +}; + +static int __init myloader_mtd_parser_init(void) +{ + register_mtd_parser(&myloader_mtd_parser); + + return 0; +} + +static void __exit myloader_mtd_parser_exit(void) +{ + deregister_mtd_parser(&myloader_mtd_parser); +} + +module_init(myloader_mtd_parser_init); +module_exit(myloader_mtd_parser_exit); + +MODULE_AUTHOR("Gabor Juhos "); +MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); +MODULE_LICENSE("GPL v2"); -- 2.51.0 From bd16a24ae191e56a7073eceb9961fa21e017a00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 3 Nov 2025 15:49:42 +0100 Subject: [PATCH 217/517] mtd: bcm47xxpart: check for bad blocks when calculating offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki --- drivers/mtd/parsers/parser_trx.c | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/parsers/parser_trx.c b/drivers/mtd/parsers/parser_trx.c index 4814cf218e17..a1aed25d433f 100644 --- a/drivers/mtd/parsers/parser_trx.c +++ b/drivers/mtd/parsers/parser_trx.c @@ -25,6 +25,33 @@ struct trx_header { uint32_t offset[3]; } __packed; +/* + * Calculate real end offset (address) for a given amount of data. It checks + * all blocks skipping bad ones. + */ +static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes) +{ + size_t real_offset = 0; + + if (mtd_block_isbad(mtd, real_offset)) + pr_warn("Base offset shouldn't be at bad block"); + + while (bytes >= mtd->erasesize) { + bytes -= mtd->erasesize; + real_offset += mtd->erasesize; + while (mtd_block_isbad(mtd, real_offset)) { + real_offset += mtd->erasesize; + + if (real_offset >= mtd->size) + return real_offset - mtd->erasesize; + } + } + + real_offset += bytes; + + return real_offset; +} + static const char *parser_trx_data_part_name(struct mtd_info *master, size_t offset) { @@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_info *mtd, if (trx.offset[2]) { part = &parts[curr_part++]; part->name = "loader"; - part->offset = trx.offset[i]; + part->offset = parser_trx_real_offset(mtd, trx.offset[i]); i++; } if (trx.offset[i]) { part = &parts[curr_part++]; part->name = "linux"; - part->offset = trx.offset[i]; + part->offset = parser_trx_real_offset(mtd, trx.offset[i]); i++; } if (trx.offset[i]) { part = &parts[curr_part++]; - part->name = parser_trx_data_part_name(mtd, trx.offset[i]); - part->offset = trx.offset[i]; + part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + part->name = parser_trx_data_part_name(mtd, part->offset); i++; } -- 2.51.0 From cf018b2b9b3a91fe6a8f81ebc86aed81c9feb202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 3 Nov 2025 15:49:42 +0100 Subject: [PATCH 218/517] mtd: bcm47xxpart: detect T_Meter partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can be found on many Netgear devices. It consists of many 0x30 blocks starting with 4D 54. Signed-off-by: Rafał Miłecki --- drivers/mtd/parsers/bcm47xxpart.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/parsers/bcm47xxpart.c b/drivers/mtd/parsers/bcm47xxpart.c index 49c8e7f27f21..b4a5391afce7 100644 --- a/drivers/mtd/parsers/bcm47xxpart.c +++ b/drivers/mtd/parsers/bcm47xxpart.c @@ -35,6 +35,7 @@ #define NVRAM_HEADER 0x48534C46 /* FLSH */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ +#define T_METER_MAGIC 0x4D540000 /* MT */ #define ML_MAGIC1 0x39685a42 #define ML_MAGIC2 0x26594131 #define TRX_MAGIC 0x30524448 @@ -179,6 +180,15 @@ static int bcm47xxpart_parse(struct mtd_info *master, continue; } + /* T_Meter */ + if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && + (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && + (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { + bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, + MTD_WRITEABLE); + continue; + } + /* TRX */ if (buf[0x000 / 4] == TRX_MAGIC) { struct trx_header *trx; -- 2.51.0 From b7841b2dd346ac51024fd841247b87267a41eaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= Date: Tue, 24 Mar 2020 11:45:07 +0100 Subject: [PATCH 219/517] generic: routerboot partition build bits (5.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds routerbootpart kernel build bits Signed-off-by: Thibaut VARÈNE --- drivers/mtd/parsers/Kconfig | 9 +++++++++ drivers/mtd/parsers/Makefile | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index 879d193f83f7..87dde317f9dd 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -231,3 +231,12 @@ config MTD_SERCOMM_PARTS partition map. This partition table contains real partition offsets, which may differ from device to device depending on the number and location of bad blocks on NAND. + +config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" + depends on MTD && OF + help + MikroTik RouterBoot is implemented as a multi segment system on the + flash, some of which are fixed and some of which are located at + variable offsets. This parser handles both cases via properly + formatted DTS. diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile index e3d3ade33a48..e6b06b56b046 100644 --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o +obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o -- 2.51.0 From 539d84630ee1e7d03afccbf4d62527fa34d0e592 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 7 Oct 2024 23:36:14 +0100 Subject: [PATCH 220/517] block: allow setting partition of_node Allow partition parsers to set the Device Tree node for a partition by introducing of_put_partition() and extending struct parsed_partitions accordingly. As the partition information is preallocated independently of the actual number of partitions the additional pointer takes about 2 kiB of allocated memory which is worth avoiding in case CONFIG_OF is not set. This is achieved by only adding the corresponding field to the struct in case CONFIG_OF is set using #ifdef'ery. Signed-off-by: Daniel Golle --- block/partitions/check.h | 16 +++++++++++++++- block/partitions/core.c | 14 +++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/block/partitions/check.h b/block/partitions/check.h index e5c1c61eb353..0b326086b1b6 100644 --- a/block/partitions/check.h +++ b/block/partitions/check.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include #include +#include #include "../blk.h" /* @@ -16,6 +17,9 @@ struct parsed_partitions { int flags; bool has_info; struct partition_meta_info info; +#ifdef CONFIG_OF + struct device_node *np; +#endif } *parts; int next; int limit; @@ -34,18 +38,28 @@ static inline void put_dev_sector(Sector p) } static inline void -put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) +of_put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size, + struct device_node *np) { if (n < p->limit) { char tmp[1 + BDEVNAME_SIZE + 10 + 1]; p->parts[n].from = from; p->parts[n].size = size; +#ifdef CONFIG_OF + p->parts[n].np = np; +#endif snprintf(tmp, sizeof(tmp), " %s%d", p->name, n); strlcat(p->pp_buf, tmp, PAGE_SIZE); } } +static inline void +put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) +{ + of_put_partition(p, n, from, size, NULL); +} + /* detection routines go here in alphabetical order: */ int adfspart_check_ADFS(struct parsed_partitions *state); int adfspart_check_CUMANA(struct parsed_partitions *state); diff --git a/block/partitions/core.c b/block/partitions/core.c index cdad05f97647..f5b5360dd518 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "check.h" @@ -290,7 +291,8 @@ static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); */ static struct block_device *add_partition(struct gendisk *disk, int partno, sector_t start, sector_t len, int flags, - struct partition_meta_info *info) + struct partition_meta_info *info, + struct device_node *np) { dev_t devt = MKDEV(0, 0); struct device *ddev = disk_to_dev(disk); @@ -339,6 +341,7 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, pdev->class = &block_class; pdev->type = &part_type; pdev->parent = ddev; + device_set_node(pdev, of_fwnode_handle(np)); /* in consecutive minor range? */ if (bdev_partno(bdev) < disk->minors) { @@ -445,7 +448,7 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, } part = add_partition(disk, partno, start, length, - ADDPART_FLAG_NONE, NULL); + ADDPART_FLAG_NONE, NULL, NULL); ret = PTR_ERR_OR_ZERO(part); out: mutex_unlock(&disk->open_mutex); @@ -559,8 +562,13 @@ static bool blk_add_partition(struct gendisk *disk, size = get_capacity(disk) - from; } +#ifdef CONFIG_OF part = add_partition(disk, p, from, size, state->parts[p].flags, - &state->parts[p].info); + &state->parts[p].info, state->parts[p].np); +#else + part = add_partition(disk, p, from, size, state->parts[p].flags, + &state->parts[p].info, NULL); +#endif if (IS_ERR(part)) { if (PTR_ERR(part) != -ENXIO) { printk(KERN_ERR " %s: p%d could not be added: %pe\n", -- 2.51.0 From f63140ada721fe7cd8818daf12912032df2dff53 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 7 Oct 2024 23:43:32 +0100 Subject: [PATCH 221/517] block: partitions: of: assign Device Tree node to partition Assign partition of_node so other drivers are able to identify a partition by its Device Tree node. Signed-off-by: Daniel Golle --- block/partitions/of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/partitions/of.c b/block/partitions/of.c index 4e760fdffb3f..8b82f9f39686 100644 --- a/block/partitions/of.c +++ b/block/partitions/of.c @@ -48,7 +48,7 @@ static void add_of_partition(struct parsed_partitions *state, int slot, u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE; u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE; - put_partition(state, slot, offset, size); + of_put_partition(state, slot, offset, size, np); if (of_property_read_bool(np, "read-only")) state->parts[slot].flags |= ADDPART_FLAG_READONLY; -- 2.51.0 From 15a3c6b896f516d704bf3b54a4f3f2837e738481 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 7 Oct 2024 23:22:53 +0100 Subject: [PATCH 222/517] partitions/efi: apply Linux code style Fix (mostly white space related) coding style issues in block/partitions/efi.c by use of clang-format. Signed-off-by: Daniel Golle --- block/partitions/efi.c | 235 +++++++++++++++++++++-------------------- 1 file changed, 121 insertions(+), 114 deletions(-) diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 7acba66eed48..4e31f6c09f70 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -95,15 +95,13 @@ * the partition tables happens after init too. */ static int force_gpt; -static int __init -force_gpt_fn(char *str) +static int __init force_gpt_fn(char *str) { force_gpt = 1; return 1; } __setup("gpt", force_gpt_fn); - /** * efi_crc32() - EFI version of crc32 function * @buf: buffer to calculate crc32 of @@ -116,8 +114,7 @@ __setup("gpt", force_gpt_fn); * Note, the EFI Specification, v1.02, has a reference to * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). */ -static inline u32 -efi_crc32(const void *buf, unsigned long len) +static inline u32 efi_crc32(const void *buf, unsigned long len) { return (crc32(~0L, buf, len) ^ ~0L); } @@ -134,7 +131,8 @@ efi_crc32(const void *buf, unsigned long len) static u64 last_lba(struct gendisk *disk) { return div_u64(bdev_nr_bytes(disk->part0), - queue_logical_block_size(disk->queue)) - 1ULL; + queue_logical_block_size(disk->queue)) - + 1ULL; } static inline int pmbr_part_valid(gpt_mbr_record *part) @@ -195,7 +193,7 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) check_hybrid: for (i = 0; i < 4; i++) if ((mbr->partition_record[i].os_type != - EFI_PMBR_OSTYPE_EFI_GPT) && + EFI_PMBR_OSTYPE_EFI_GPT) && (mbr->partition_record[i].os_type != 0x00)) ret = GPT_MBR_HYBRID; @@ -213,10 +211,11 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) */ if (ret == GPT_MBR_PROTECTIVE) { sz = le32_to_cpu(mbr->partition_record[part].size_in_lba); - if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) - pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n", - sz, min_t(uint32_t, - total_sectors - 1, 0xFFFFFFFF)); + if (sz != (uint32_t)total_sectors - 1 && sz != 0xFFFFFFFF) + pr_debug( + "GPT: mbr size in lba (%u) different than whole disk (%u).\n", + sz, + min_t(uint32_t, total_sectors - 1, 0xFFFFFFFF)); } done: return ret; @@ -232,15 +231,14 @@ static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) * Description: Reads @count bytes from @state->disk into @buffer. * Returns number of bytes read on success, 0 on error. */ -static size_t read_lba(struct parsed_partitions *state, - u64 lba, u8 *buffer, size_t count) +static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer, + size_t count) { size_t totalreadcount = 0; - sector_t n = lba * - (queue_logical_block_size(state->disk->queue) / 512); + sector_t n = lba * (queue_logical_block_size(state->disk->queue) / 512); if (!buffer || lba > last_lba(state->disk)) - return 0; + return 0; while (count) { int copied = 512; @@ -253,7 +251,7 @@ static size_t read_lba(struct parsed_partitions *state, memcpy(buffer, data, copied); put_dev_sector(sect); buffer += copied; - totalreadcount +=copied; + totalreadcount += copied; count -= copied; } return totalreadcount; @@ -278,17 +276,17 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, return NULL; count = (size_t)le32_to_cpu(gpt->num_partition_entries) * - le32_to_cpu(gpt->sizeof_partition_entry); + le32_to_cpu(gpt->sizeof_partition_entry); if (!count) return NULL; pte = kmalloc(count, GFP_KERNEL); if (!pte) return NULL; - if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), - (u8 *) pte, count) < count) { + if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), (u8 *)pte, + count) < count) { kfree(pte); - pte=NULL; + pte = NULL; return NULL; } return pte; @@ -313,9 +311,9 @@ static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state, if (!gpt) return NULL; - if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) { + if (read_lba(state, lba, (u8 *)gpt, ssz) < ssz) { kfree(gpt); - gpt=NULL; + gpt = NULL; return NULL; } @@ -354,8 +352,9 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, /* Check the GUID Partition Table header size is too big */ if (le32_to_cpu((*gpt)->header_size) > - queue_logical_block_size(state->disk->queue)) { - pr_debug("GUID Partition Table Header size is too large: %u > %u\n", + queue_logical_block_size(state->disk->queue)) { + pr_debug( + "GUID Partition Table Header size is too large: %u > %u\n", le32_to_cpu((*gpt)->header_size), queue_logical_block_size(state->disk->queue)); goto fail; @@ -363,16 +362,17 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, /* Check the GUID Partition Table header size is too small */ if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) { - pr_debug("GUID Partition Table Header size is too small: %u < %zu\n", - le32_to_cpu((*gpt)->header_size), - sizeof(gpt_header)); + pr_debug( + "GUID Partition Table Header size is too small: %u < %zu\n", + le32_to_cpu((*gpt)->header_size), sizeof(gpt_header)); goto fail; } /* Check the GUID Partition Table CRC */ origcrc = le32_to_cpu((*gpt)->header_crc32); (*gpt)->header_crc32 = 0; - crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); + crc = efi_crc32((const unsigned char *)(*gpt), + le32_to_cpu((*gpt)->header_size)); if (crc != origcrc) { pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", @@ -396,20 +396,25 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, lastlba = last_lba(state->disk); if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), + (unsigned long long)le64_to_cpu( + (*gpt)->first_usable_lba), (unsigned long long)lastlba); goto fail; } if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), + (unsigned long long)le64_to_cpu( + (*gpt)->last_usable_lba), (unsigned long long)lastlba); goto fail; } - if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { + if (le64_to_cpu((*gpt)->last_usable_lba) < + le64_to_cpu((*gpt)->first_usable_lba)) { pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), - (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba)); + (unsigned long long)le64_to_cpu( + (*gpt)->last_usable_lba), + (unsigned long long)le64_to_cpu( + (*gpt)->first_usable_lba)); goto fail; } /* Check that sizeof_partition_entry has the correct value */ @@ -420,10 +425,11 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, /* Sanity check partition table size */ pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) * - le32_to_cpu((*gpt)->sizeof_partition_entry); + le32_to_cpu((*gpt)->sizeof_partition_entry); if (pt_size > KMALLOC_MAX_SIZE) { - pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n", - (unsigned long long)pt_size, KMALLOC_MAX_SIZE); + pr_debug( + "GUID Partition Table is too large: %llu > %lu bytes\n", + (unsigned long long)pt_size, KMALLOC_MAX_SIZE); goto fail; } @@ -431,7 +437,7 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, goto fail; /* Check the GUID Partition Entry Array CRC */ - crc = efi_crc32((const unsigned char *) (*ptes), pt_size); + crc = efi_crc32((const unsigned char *)(*ptes), pt_size); if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { pr_debug("GUID Partition Entry Array CRC check failed.\n"); @@ -441,10 +447,10 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, /* We're done, all's well */ return 1; - fail_ptes: +fail_ptes: kfree(*ptes); *ptes = NULL; - fail: +fail: kfree(*gpt); *gpt = NULL; return 0; @@ -457,12 +463,11 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba, * * Description: returns 1 if valid, 0 on error. */ -static inline int -is_pte_valid(const gpt_entry *pte, const u64 lastlba) +static inline int is_pte_valid(const gpt_entry *pte, const u64 lastlba) { if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || - le64_to_cpu(pte->starting_lba) > lastlba || - le64_to_cpu(pte->ending_lba) > lastlba) + le64_to_cpu(pte->starting_lba) > lastlba || + le64_to_cpu(pte->ending_lba) > lastlba) return 0; return 1; } @@ -477,8 +482,7 @@ is_pte_valid(const gpt_entry *pte, const u64 lastlba) * and prints warnings on discrepancies. * */ -static void -compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) +static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) { int error_found = 0; if (!pgpt || !agpt) @@ -486,31 +490,32 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n"); pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->my_lba), - (unsigned long long)le64_to_cpu(agpt->alternate_lba)); + (unsigned long long)le64_to_cpu(pgpt->my_lba), + (unsigned long long)le64_to_cpu(agpt->alternate_lba)); error_found++; } if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n"); pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->alternate_lba), - (unsigned long long)le64_to_cpu(agpt->my_lba)); + (unsigned long long)le64_to_cpu(pgpt->alternate_lba), + (unsigned long long)le64_to_cpu(agpt->my_lba)); error_found++; } if (le64_to_cpu(pgpt->first_usable_lba) != - le64_to_cpu(agpt->first_usable_lba)) { + le64_to_cpu(agpt->first_usable_lba)) { pr_warn("GPT:first_usable_lbas don't match.\n"); pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), - (unsigned long long)le64_to_cpu(agpt->first_usable_lba)); + (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), + (unsigned long long)le64_to_cpu( + agpt->first_usable_lba)); error_found++; } if (le64_to_cpu(pgpt->last_usable_lba) != - le64_to_cpu(agpt->last_usable_lba)) { + le64_to_cpu(agpt->last_usable_lba)) { pr_warn("GPT:last_usable_lbas don't match.\n"); pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), - (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); + (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), + (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); error_found++; } if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { @@ -518,27 +523,27 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) error_found++; } if (le32_to_cpu(pgpt->num_partition_entries) != - le32_to_cpu(agpt->num_partition_entries)) { + le32_to_cpu(agpt->num_partition_entries)) { pr_warn("GPT:num_partition_entries don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->num_partition_entries), - le32_to_cpu(agpt->num_partition_entries)); + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->num_partition_entries), + le32_to_cpu(agpt->num_partition_entries)); error_found++; } if (le32_to_cpu(pgpt->sizeof_partition_entry) != - le32_to_cpu(agpt->sizeof_partition_entry)) { + le32_to_cpu(agpt->sizeof_partition_entry)) { pr_warn("GPT:sizeof_partition_entry values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->sizeof_partition_entry), - le32_to_cpu(agpt->sizeof_partition_entry)); + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->sizeof_partition_entry), + le32_to_cpu(agpt->sizeof_partition_entry)); error_found++; } if (le32_to_cpu(pgpt->partition_entry_array_crc32) != - le32_to_cpu(agpt->partition_entry_array_crc32)) { + le32_to_cpu(agpt->partition_entry_array_crc32)) { pr_warn("GPT:partition_entry_array_crc32 values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->partition_entry_array_crc32), - le32_to_cpu(agpt->partition_entry_array_crc32)); + "0x%x != 0x%x\n", + le32_to_cpu(pgpt->partition_entry_array_crc32), + le32_to_cpu(agpt->partition_entry_array_crc32)); error_found++; } if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { @@ -594,7 +599,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, return 0; lastlba = last_lba(state->disk); - if (!force_gpt) { + if (!force_gpt) { /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL); if (!legacymbr) @@ -608,18 +613,17 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, goto fail; pr_debug("Device has a %s MBR\n", - good_pmbr == GPT_MBR_PROTECTIVE ? - "protective" : "hybrid"); + good_pmbr == GPT_MBR_PROTECTIVE ? "protective" : + "hybrid"); } - good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, - &pgpt, &pptes); - if (good_pgpt) - good_agpt = is_gpt_valid(state, - le64_to_cpu(pgpt->alternate_lba), - &agpt, &aptes); - if (!good_agpt && force_gpt) - good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); + good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, + &pptes); + if (good_pgpt) + good_agpt = is_gpt_valid( + state, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); + if (!good_agpt && force_gpt) + good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); if (!good_agpt && force_gpt && fops->alternative_gpt_sector) { sector_t agpt_sector; @@ -627,43 +631,42 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, err = fops->alternative_gpt_sector(disk, &agpt_sector); if (!err) - good_agpt = is_gpt_valid(state, agpt_sector, - &agpt, &aptes); + good_agpt = + is_gpt_valid(state, agpt_sector, &agpt, &aptes); } - /* The obviously unsuccessful case */ - if (!good_pgpt && !good_agpt) - goto fail; + /* The obviously unsuccessful case */ + if (!good_pgpt && !good_agpt) + goto fail; - compare_gpts(pgpt, agpt, lastlba); + compare_gpts(pgpt, agpt, lastlba); - /* The good cases */ - if (good_pgpt) { - *gpt = pgpt; - *ptes = pptes; - kfree(agpt); - kfree(aptes); + /* The good cases */ + if (good_pgpt) { + *gpt = pgpt; + *ptes = pptes; + kfree(agpt); + kfree(aptes); if (!good_agpt) - pr_warn("Alternate GPT is invalid, using primary GPT.\n"); - return 1; - } - else if (good_agpt) { - *gpt = agpt; - *ptes = aptes; - kfree(pgpt); - kfree(pptes); + pr_warn("Alternate GPT is invalid, using primary GPT.\n"); + return 1; + } else if (good_agpt) { + *gpt = agpt; + *ptes = aptes; + kfree(pgpt); + kfree(pptes); pr_warn("Primary GPT is invalid, using alternate GPT.\n"); - return 1; - } - - fail: - kfree(pgpt); - kfree(agpt); - kfree(pptes); - kfree(aptes); - *gpt = NULL; - *ptes = NULL; - return 0; + return 1; + } + +fail: + kfree(pgpt); + kfree(agpt); + kfree(pptes); + kfree(aptes); + *gpt = NULL; + *ptes = NULL; + return 0; } /** @@ -725,7 +728,9 @@ int efi_partition(struct parsed_partitions *state) pr_debug("GUID Partition Table is valid! Yea!\n"); - for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { + for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && + i < state->limit - 1; + i++) { struct partition_meta_info *info; unsigned label_max; u64 start = le64_to_cpu(ptes[i].starting_lba); @@ -735,10 +740,11 @@ int efi_partition(struct parsed_partitions *state) if (!is_pte_valid(&ptes[i], last_lba(state->disk))) continue; - put_partition(state, i+1, start * ssz, size * ssz); + put_partition(state, i + 1, start * ssz, size * ssz); /* If this is a RAID volume, tell md */ - if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID)) + if (!efi_guidcmp(ptes[i].partition_type_guid, + PARTITION_LINUX_RAID_GUID)) state->parts[i + 1].flags = ADDPART_FLAG_RAID; info = &state->parts[i + 1].info; @@ -747,7 +753,8 @@ int efi_partition(struct parsed_partitions *state) /* Naively convert UTF16-LE to 7 bits. */ label_max = min(ARRAY_SIZE(info->volname) - 1, ARRAY_SIZE(ptes[i].partition_name)); - utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname); + utf16_le_to_7bit(ptes[i].partition_name, label_max, + info->volname); state->parts[i + 1].has_info = true; } kfree(ptes); -- 2.51.0 From fb79f53b4383405a574e9d12a6101ea4ff10e3d2 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 8 Oct 2024 00:25:12 +0100 Subject: [PATCH 223/517] partitions/efi: allow assigning partition Device Tree node Signed-off-by: Daniel Golle --- block/partitions/efi.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 4e31f6c09f70..ac2c7d3c4993 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #include "check.h" #include "efi.h" @@ -694,6 +695,34 @@ static void utf16_le_to_7bit(const __le16 *in, unsigned int size, u8 *out) } } +static struct device_node *find_partition_of_node(struct device_node *partitions_np, + gpt_entry *ptes) +{ + char volname[64], partuuid[UUID_STRING_LEN + 1]; + const char *uuid, *name; + + if (!partitions_np || + !of_device_is_compatible(partitions_np, "gpt-partitions")) + return NULL; + + efi_guid_to_str(&ptes->unique_partition_guid, partuuid); + utf16_le_to_7bit(ptes->partition_name, ARRAY_SIZE(volname) - 1, volname); + + for_each_available_child_of_node_scoped(partitions_np, np) { + if (!of_property_read_string(np, "uuid", &uuid) && + strncmp(uuid, partuuid, ARRAY_SIZE(partuuid))) + continue; + + if (!of_property_read_string(np, "partname", &name) && + strncmp(name, volname, ARRAY_SIZE(volname))) + continue; + + return np; + } + + return NULL; +} + /** * efi_partition - scan for GPT partitions * @state: disk parsed partitions @@ -719,6 +748,8 @@ int efi_partition(struct parsed_partitions *state) gpt_entry *ptes = NULL; u32 i; unsigned ssz = queue_logical_block_size(state->disk->queue) / 512; + struct device *ddev = disk_to_dev(state->disk); + struct device_node *partitions_np = of_node_get(ddev->of_node); if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { kfree(gpt); @@ -740,7 +771,8 @@ int efi_partition(struct parsed_partitions *state) if (!is_pte_valid(&ptes[i], last_lba(state->disk))) continue; - put_partition(state, i + 1, start * ssz, size * ssz); + of_put_partition(state, i + 1, start * ssz, size * ssz, + find_partition_of_node(partitions_np, &ptes[i])); /* If this is a RAID volume, tell md */ if (!efi_guidcmp(ptes[i].partition_type_guid, -- 2.51.0 From d4f29e2f7c6db41a6ea7112427078c805d8bd3e3 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 15 May 2024 08:19:51 +0100 Subject: [PATCH 224/517] block: add support for notifications Add notifier block to notify other subsystems about the addition or removal of block devices. Signed-off-by: Daniel Golle --- block/Kconfig | 6 +++ block/Makefile | 1 + block/blk-notify.c | 107 +++++++++++++++++++++++++++++++++++++++++ include/linux/blkdev.h | 8 +++ 4 files changed, 122 insertions(+) create mode 100644 block/blk-notify.c diff --git a/block/Kconfig b/block/Kconfig index 5b623b876d3b..67cd4f92378a 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -209,6 +209,12 @@ config BLK_INLINE_ENCRYPTION_FALLBACK by falling back to the kernel crypto API when inline encryption hardware is not present. +config BLOCK_NOTIFIERS + bool "Enable support for notifications in block layer" + help + Enable this option to provide notifiers for other subsystems + upon addition or removal of block devices. + source "block/partitions/Kconfig" config BLK_MQ_PCI diff --git a/block/Makefile b/block/Makefile index ddfd21c1a9ff..a131fa7d6b26 100644 --- a/block/Makefile +++ b/block/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_BLK_INLINE_ENCRYPTION) += blk-crypto.o blk-crypto-profile.o \ blk-crypto-sysfs.o obj-$(CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK) += blk-crypto-fallback.o obj-$(CONFIG_BLOCK_HOLDER_DEPRECATED) += holder.o +obj-$(CONFIG_BLOCK_NOTIFIERS) += blk-notify.o diff --git a/block/blk-notify.c b/block/blk-notify.c new file mode 100644 index 000000000000..880e48a3f765 --- /dev/null +++ b/block/blk-notify.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Notifiers for addition and removal of block devices + * + * Copyright (c) 2024 Daniel Golle + */ + +#include +#include +#include +#include + +#include "blk.h" + +struct blk_device_list { + struct device *dev; + struct list_head list; +}; + +static RAW_NOTIFIER_HEAD(blk_notifier_list); +static DEFINE_MUTEX(blk_notifier_lock); +static LIST_HEAD(blk_devices); + +struct blk_notify_event { + struct delayed_work work; + struct device *dev; +}; + +void blk_register_notify(struct notifier_block *nb) +{ + struct blk_device_list *existing_blkdev; + + mutex_lock(&blk_notifier_lock); + raw_notifier_chain_register(&blk_notifier_list, nb); + + list_for_each_entry(existing_blkdev, &blk_devices, list) + nb->notifier_call(nb, BLK_DEVICE_ADD, existing_blkdev->dev); + + mutex_unlock(&blk_notifier_lock); +} +EXPORT_SYMBOL_GPL(blk_register_notify); + +void blk_unregister_notify(struct notifier_block *nb) +{ + mutex_lock(&blk_notifier_lock); + raw_notifier_chain_unregister(&blk_notifier_list, nb); + mutex_unlock(&blk_notifier_lock); +} +EXPORT_SYMBOL_GPL(blk_unregister_notify); + +static void blk_notify_work(struct work_struct *work) +{ + struct blk_notify_event *ev = + container_of(work, struct blk_notify_event, work.work); + + raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_ADD, ev->dev); + kfree(ev); +} + +static int blk_call_notifier_add(struct device *dev) +{ + struct blk_device_list *new_blkdev; + struct blk_notify_event *ev; + + new_blkdev = kmalloc(sizeof (*new_blkdev), GFP_KERNEL); + if (!new_blkdev) + return -ENOMEM; + + ev = kmalloc(sizeof(*ev), GFP_KERNEL); + INIT_DEFERRABLE_WORK(&ev->work, blk_notify_work); + ev->dev = dev; + new_blkdev->dev = dev; + mutex_lock(&blk_notifier_lock); + list_add_tail(&new_blkdev->list, &blk_devices); + schedule_delayed_work(&ev->work, msecs_to_jiffies(500)); + mutex_unlock(&blk_notifier_lock); + + return 0; +} + +static void blk_call_notifier_remove(struct device *dev) +{ + struct blk_device_list *old_blkdev, *tmp; + + mutex_lock(&blk_notifier_lock); + list_for_each_entry_safe(old_blkdev, tmp, &blk_devices, list) { + if (old_blkdev->dev != dev) + continue; + + list_del(&old_blkdev->list); + kfree(old_blkdev); + } + raw_notifier_call_chain(&blk_notifier_list, BLK_DEVICE_REMOVE, dev); + mutex_unlock(&blk_notifier_lock); +} + +static struct class_interface blk_notifications_bus_interface __refdata = { + .class = &block_class, + .add_dev = &blk_call_notifier_add, + .remove_dev = &blk_call_notifier_remove, +}; + +static int __init blk_notifications_init(void) +{ + return class_interface_register(&blk_notifications_bus_interface); +} +device_initcall(blk_notifications_init); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index fa9d324b7069..822b8daec45d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1753,4 +1753,12 @@ static inline bool bdev_can_atomic_write(struct block_device *bdev) #define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { } + +#ifdef CONFIG_BLOCK_NOTIFIERS +#define BLK_DEVICE_ADD 1 +#define BLK_DEVICE_REMOVE 2 +extern void blk_register_notify(struct notifier_block *nb); +extern void blk_unregister_notify(struct notifier_block *nb); +#endif + #endif /* _LINUX_BLKDEV_H */ -- 2.51.0 From 80ab21df365232ab1db9e4734a474940f24b741e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 21 Mar 2024 19:33:49 +0000 Subject: [PATCH 225/517] block: add new genhd flag GENHD_FL_NVMEM Add new flag to destinguish block devices which may act as an NVMEM provider. Signed-off-by: Daniel Golle --- include/linux/blkdev.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 822b8daec45d..8213eb3670fe 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -82,11 +82,13 @@ struct partition_meta_info { * ``GENHD_FL_NO_PART``: partition support is disabled. The kernel will not * scan for partitions from add_disk, and users can't add partitions manually. * + * ``GENHD_FL_NVMEM``: the block device should be considered as NVMEM provider. */ enum { GENHD_FL_REMOVABLE = 1 << 0, GENHD_FL_HIDDEN = 1 << 1, GENHD_FL_NO_PART = 1 << 2, + GENHD_FL_NVMEM = 1 << 3, }; enum { -- 2.51.0 From 505eb071cbc1260ffb37d27dd638d2154af1cea8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 15 May 2024 18:18:37 +0300 Subject: [PATCH 226/517] nvmem: implement block NVMEM provider On embedded devices using an eMMC it is common that one or more partitions on the eMMC are used to store MAC addresses and Wi-Fi calibration EEPROM data. Allow referencing any block device or partition in Device Tree to allow e.g. Ethernet and Wi-Fi drivers accessing them via the NVMEM layer. Signed-off-by: Daniel Golle --- drivers/nvmem/Kconfig | 11 +++ drivers/nvmem/Makefile | 2 + drivers/nvmem/block.c | 198 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 drivers/nvmem/block.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index d2c384f58028..40b5fd1bfde4 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -40,6 +40,17 @@ config NVMEM_APPLE_EFUSES This driver can also be built as a module. If so, the module will be called nvmem-apple-efuses. +config NVMEM_BLOCK + tristate "Block device NVMEM provider" + depends on BLOCK + depends on OF + depends on NVMEM + select BLOCK_NOTIFIERS + help + Allow block devices (or partitions) to act as NVMEM prodivers, + typically used with eMMC to store MAC addresses or Wi-Fi + calibration data on embedded devices. + config NVMEM_BCM_OCOTP tristate "Broadcom On-Chip OTP Controller support" depends on ARCH_BCM_IPROC || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index cdd01fbf1313..68fcf845f417 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o nvmem-apple-efuses-y := apple-efuses.o obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o nvmem-bcm-ocotp-y := bcm-ocotp.o +obj-$(CONFIG_NVMEM_BLOCK) += nvmem-block.o +nvmem-block-y := block.o obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o nvmem_brcm_nvram-y := brcm_nvram.o obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o diff --git a/drivers/nvmem/block.c b/drivers/nvmem/block.c new file mode 100644 index 000000000000..dc9e43f98616 --- /dev/null +++ b/drivers/nvmem/block.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * block device NVMEM provider + * + * Copyright (c) 2024 Daniel Golle + * + * Useful on devices using a partition on an eMMC for MAC addresses or + * Wi-Fi calibration EEPROM data. + */ + +#include +#include +#include +#include +#include + +/* List of all NVMEM devices */ +static LIST_HEAD(nvmem_devices); +static DEFINE_MUTEX(devices_mutex); + +struct blk_nvmem { + struct nvmem_device *nvmem; + struct device *dev; + struct list_head list; +}; + +static int blk_nvmem_reg_read(void *priv, unsigned int from, + void *val, size_t bytes) +{ + blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES; + unsigned long offs = from & ~PAGE_MASK, to_read; + pgoff_t f_index = from >> PAGE_SHIFT; + struct blk_nvmem *bnv = priv; + size_t bytes_left = bytes; + struct file *bdev_file; + struct folio *folio; + void *p; + int ret = 0; + + bdev_file = bdev_file_open_by_dev(bnv->dev->devt, mode, priv, NULL); + if (!bdev_file) + return -ENODEV; + + if (IS_ERR(bdev_file)) + return PTR_ERR(bdev_file); + + while (bytes_left) { + folio = read_mapping_folio(bdev_file->f_mapping, f_index++, NULL); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); + goto err_release_bdev; + } + to_read = min_t(unsigned long, bytes_left, PAGE_SIZE - offs); + p = folio_address(folio) + offset_in_folio(folio, offs); + memcpy(val, p, to_read); + offs = 0; + bytes_left -= to_read; + val += to_read; + folio_put(folio); + } + +err_release_bdev: + fput(bdev_file); + + return ret; +} + +static int blk_nvmem_register(struct device *dev) +{ + struct block_device *bdev = dev_to_bdev(dev); + struct device_node *np = dev_of_node(dev); + struct nvmem_config config = {}; + struct blk_nvmem *bnv; + + /* skip devices which do not have a device tree node */ + if (!np) + return 0; + + /* skip devices without an nvmem layout defined */ + if (!of_get_child_by_name(np, "nvmem-layout")) + return 0; + + /* + * skip devices which don't have GENHD_FL_NVMEM set + * + * This flag is used for mtdblock and ubiblock devices because + * both, MTD and UBI already implement their own NVMEM provider. + * To avoid registering multiple NVMEM providers for the same + * device node, don't register the block NVMEM provider for them. + */ + if (!(bdev->bd_disk->flags & GENHD_FL_NVMEM)) + return 0; + + /* + * skip block device too large to be represented as NVMEM devices + * which are using an 'int' as address + */ + if (bdev_nr_bytes(bdev) > INT_MAX) + return -EFBIG; + + bnv = kzalloc(sizeof(struct blk_nvmem), GFP_KERNEL); + if (!bnv) + return -ENOMEM; + + config.id = NVMEM_DEVID_NONE; + config.dev = &bdev->bd_device; + config.name = dev_name(&bdev->bd_device); + config.owner = THIS_MODULE; + config.priv = bnv; + config.reg_read = blk_nvmem_reg_read; + config.size = bdev_nr_bytes(bdev); + config.word_size = 1; + config.stride = 1; + config.read_only = true; + config.root_only = true; + config.ignore_wp = true; + config.of_node = to_of_node(dev->fwnode); + + bnv->dev = &bdev->bd_device; + bnv->nvmem = nvmem_register(&config); + if (IS_ERR(bnv->nvmem)) { + dev_err_probe(&bdev->bd_device, PTR_ERR(bnv->nvmem), + "Failed to register NVMEM device\n"); + + kfree(bnv); + return PTR_ERR(bnv->nvmem); + } + + mutex_lock(&devices_mutex); + list_add_tail(&bnv->list, &nvmem_devices); + mutex_unlock(&devices_mutex); + + return 0; +} + +static void blk_nvmem_unregister(struct device *dev) +{ + struct blk_nvmem *bnv_c, *bnv = NULL; + + mutex_lock(&devices_mutex); + list_for_each_entry(bnv_c, &nvmem_devices, list) { + if (bnv_c->dev == dev) { + bnv = bnv_c; + break; + } + } + + if (!bnv) { + mutex_unlock(&devices_mutex); + return; + } + + list_del(&bnv->list); + mutex_unlock(&devices_mutex); + nvmem_unregister(bnv->nvmem); + kfree(bnv); +} + +static int blk_nvmem_handler(struct notifier_block *this, unsigned long code, void *obj) +{ + struct device *dev = (struct device *)obj; + + switch (code) { + case BLK_DEVICE_ADD: + return blk_nvmem_register(dev); + break; + case BLK_DEVICE_REMOVE: + blk_nvmem_unregister(dev); + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct notifier_block blk_nvmem_notifier = { + .notifier_call = blk_nvmem_handler, +}; + +static int __init blk_nvmem_init(void) +{ + blk_register_notify(&blk_nvmem_notifier); + + return 0; +} + +static void __exit blk_nvmem_exit(void) +{ + blk_unregister_notify(&blk_nvmem_notifier); +} + +module_init(blk_nvmem_init); +module_exit(blk_nvmem_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_DESCRIPTION("block device NVMEM provider"); -- 2.51.0 From a157318671df5bf489e72723f2b02b462415855f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 20 Jul 2023 17:36:44 +0100 Subject: [PATCH 227/517] mmc: block: set GENHD_FL_NVMEM Set flag to consider MMC block devices as NVMEM providers. Signed-off-by: Daniel Golle --- drivers/mmc/core/block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 28882b75ba26..f56eb44ec450 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2644,6 +2644,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->major = MMC_BLOCK_MAJOR; md->disk->minors = perdev_minors; md->disk->first_minor = devidx * perdev_minors; + md->disk->flags = GENHD_FL_NVMEM; md->disk->fops = &mmc_bdops; md->disk->private_data = md; md->parent = parent; -- 2.51.0 From 601eabca6855ce5433b4753cf64b7de87cfbd935 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:45 +0100 Subject: [PATCH 228/517] kernel: disable cfi cmdset 0002 erase suspend on some platforms, erase suspend leads to data corruption and lockups when write ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh. rather than play whack-a-mole with a hard to reproduce issue on a variety of devices, simply disable erase suspend, as it will usually not produce any useful gain on the small filesystems used on embedded hardware. Signed-off-by: Felix Fietkau --- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 9f2223d3e8e1..cd513f719177 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -906,7 +906,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr return 0; case FL_ERASING: - if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || !(mode == FL_READY || mode == FL_POINT || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) goto sleep; -- 2.51.0 From 0aca8172b13a5bbbbd97f3d2ece4e916bbdb41d4 Mon Sep 17 00:00:00 2001 From: George Kashperko Date: Mon, 3 Nov 2025 15:49:45 +0100 Subject: [PATCH 229/517] Issue map read after Write Buffer Load command to ensure chip is ready to receive data. Signed-off-by: George Kashperko --- drivers/mtd/chips/cfi_cmdset_0002.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index cd513f719177..b589ddc4a3c9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2050,6 +2050,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, /* Write Buffer Load */ map_write(map, CMD(0x25), cmd_adr); + (void) map_read(map, cmd_adr); chip->state = FL_WRITING_TO_BUFFER; -- 2.51.0 From 1e60d2ebf7e0a305b8ba49ff8bdcad70ef15bd63 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:45 +0100 Subject: [PATCH 230/517] Disable software protection bits for Macronix flashes. Signed-off-by: Felix Fietkau --- drivers/mtd/spi-nor/macronix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index ea6be95e75a5..ac125b89e7ba 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -194,6 +194,7 @@ static int macronix_nor_late_init(struct spi_nor *nor) { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; + nor->flags |= SNOR_F_HAS_LOCK; return 0; } -- 2.51.0 From de1e4ccd801c181b0f1d543e91f63a1743d3a092 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Mon, 3 Nov 2025 15:49:46 +0100 Subject: [PATCH 231/517] kernel/mtd: add support for EON EN25Q128 Signed-off-by: Piotr Dymacz --- drivers/mtd/spi-nor/eon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi-nor/eon.c b/drivers/mtd/spi-nor/eon.c index c1ddf662f782..d43b68873cf1 100644 --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c @@ -17,6 +17,11 @@ static const struct flash_info eon_nor_parts[] = { .id = SNOR_ID(0x1c, 0x20, 0x17), .name = "en25p64", .size = SZ_8M, + }, { + .id = SNOR_ID(0x1c, 0x30, 0x18), + .name = "en25q128", + .size = SZ_16M, + .no_sfdp_flags = SECT_4K, }, { .id = SNOR_ID(0x1c, 0x30, 0x14), .name = "en25q80a", -- 2.51.0 From ebe89a767bbf9f8a9704db8a1364c28f6c8bf044 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 3 Nov 2025 15:49:46 +0100 Subject: [PATCH 232/517] kernel/mtd: add support for EON EN25QX128A Add support for EON EN25QX128A with no flags as it does support SFDP parsing. Signed-off-by: Christian Marangi --- drivers/mtd/spi-nor/eon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/spi-nor/eon.c b/drivers/mtd/spi-nor/eon.c index d43b68873cf1..a3b57a6871a3 100644 --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c @@ -22,6 +22,10 @@ static const struct flash_info eon_nor_parts[] = { .name = "en25q128", .size = SZ_16M, .no_sfdp_flags = SECT_4K, + }, { + .id = SNOR_ID(0x1c, 0x71, 0x18), + .name = "en25qx128a", + .size = SZ_16M, }, { .id = SNOR_ID(0x1c, 0x30, 0x14), .name = "en25q80a", -- 2.51.0 From 7eefc27020e72b4715c3a3e0570c8c3ea96710e3 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 6 Feb 2020 19:19:41 +0200 Subject: [PATCH 233/517] mtd: spi-nor: Add support for xt25f128b chip Add XT25F128B made by XTX Technology (Shenzhen) Limited. This chip supports dual and quad read and uniform 4K-byte erase. Verified on Teltonika RUT955 which comes with XT25F128B in recent versions of the device. Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/mtd/spi-nor/Makefile | 1 + drivers/mtd/spi-nor/core.c | 1 + drivers/mtd/spi-nor/core.h | 1 + drivers/mtd/spi-nor/xtx.c | 20 ++++++++++++++++++++ 4 files changed, 23 insertions(+) create mode 100644 drivers/mtd/spi-nor/xtx.c diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 5dd9c35f6b6f..1072cf609dac 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -14,6 +14,7 @@ spi-nor-objs += spansion.o spi-nor-objs += sst.o spi-nor-objs += winbond.o spi-nor-objs += xmc.o +spi-nor-objs += xtx.o spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 8da860d84e6d..5bb7da0ef34d 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1979,6 +1979,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = { &spi_nor_sst, &spi_nor_winbond, &spi_nor_xmc, + &spi_nor_xtx, }; static const struct flash_info spi_nor_generic_flash = { diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 1516b6d0dc37..c81829b01cfd 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -593,6 +593,7 @@ extern const struct spi_nor_manufacturer spi_nor_spansion; extern const struct spi_nor_manufacturer spi_nor_sst; extern const struct spi_nor_manufacturer spi_nor_winbond; extern const struct spi_nor_manufacturer spi_nor_xmc; +extern const struct spi_nor_manufacturer spi_nor_xtx; extern const struct attribute_group *spi_nor_sysfs_groups[]; diff --git a/drivers/mtd/spi-nor/xtx.c b/drivers/mtd/spi-nor/xtx.c new file mode 100644 index 000000000000..f16d08db483f --- /dev/null +++ b/drivers/mtd/spi-nor/xtx.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +#include "core.h" + +static const struct flash_info xtx_parts[] = { + /* XTX Technology (Shenzhen) Limited */ + { + .id = SNOR_ID(0x0B, 0x40, 0x18), + .name = "xt25f128b", + .size = SZ_16M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, +}; + +const struct spi_nor_manufacturer spi_nor_xtx = { + .name = "xtx", + .parts = xtx_parts, + .nparts = ARRAY_SIZE(xtx_parts), +}; -- 2.51.0 From be18324af44ad5c426c6168eb7d8b071d76937c9 Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Mon, 6 Jan 2020 13:07:56 +0100 Subject: [PATCH 234/517] mtd: spi-nor: add support for Gigadevice GD25D05 Signed-off-by: Koen Vandeputte --- drivers/mtd/spi-nor/gigadevice.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c index ef1edd0add70..2cf2db123751 100644 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c @@ -35,6 +35,12 @@ static const struct spi_nor_fixups gd25q256_fixups = { static const struct flash_info gigadevice_nor_parts[] = { { + .id = SNOR_ID(0xc8, 0x40, 0x10), + .name = "gd25q05", + .size = SZ_64K, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, { .id = SNOR_ID(0xc8, 0x40, 0x15), .name = "gd25q16", .size = SZ_2M, -- 2.51.0 From b044e7954a158d0fc0b2414e4e6a9f1a937bf08f Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Thu, 14 Jul 2022 08:38:07 +0200 Subject: [PATCH 235/517] spi-nor/gigadevic: add gd25q512 --- drivers/mtd/spi-nor/gigadevice.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c index 2cf2db123751..c4bf82b41914 100644 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c @@ -70,6 +70,13 @@ static const struct flash_info gigadevice_nor_parts[] = { .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6, .fixups = &gd25q256_fixups, .fixup_flags = SPI_NOR_4B_OPCODES, + }, { + .id = SNOR_ID(0xc8, 0x40, 0x20), + .name = "gd25q512", + .size = SZ_64M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + .fixup_flags = SPI_NOR_4B_OPCODES, }, { .id = SNOR_ID(0xc8, 0x60, 0x16), .name = "gd25lq32", -- 2.51.0 From 5c449e62a92715acb21fdf74e0ec3d3b7188ff8c Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 12:17:21 +0200 Subject: [PATCH 236/517] spi-nor/esmt.c: add esmt f25l16pa This fixes support for Dongwon T&I DW02-412H which uses F25L16PA(2S) flash. --- drivers/mtd/spi-nor/esmt.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/spi-nor/esmt.c b/drivers/mtd/spi-nor/esmt.c index 089fcd1aa794..3c546c5d5d9b 100644 --- a/drivers/mtd/spi-nor/esmt.c +++ b/drivers/mtd/spi-nor/esmt.c @@ -10,6 +10,12 @@ static const struct flash_info esmt_nor_parts[] = { { + .id = SNOR_ID(0x8c, 0x21, 0x15), + .name = "f25l16pa-2s", + .size = SZ_2M, + .flags = SPI_NOR_HAS_LOCK, + .no_sfdp_flags = SECT_4K, + }, { .id = SNOR_ID(0x8c, 0x20, 0x16), .name = "f25l32pa", .size = SZ_4M, -- 2.51.0 From 769f8546d57a69c758d67e0dcaf5f63b8aa163cb Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 12:19:01 +0200 Subject: [PATCH 237/517] spi-nor/xmc.c: add xm25qh128c The XMC XM25QH128C is a 16MB SPI NOR chip. The patch is verified on Ruijie RG-EW3200GX PRO. Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf --- drivers/mtd/spi-nor/xmc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi-nor/xmc.c b/drivers/mtd/spi-nor/xmc.c index d5a06054b0dd..8eb2d957c8ad 100644 --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c @@ -19,6 +19,11 @@ static const struct flash_info xmc_nor_parts[] = { .name = "XM25QH128A", .size = SZ_16M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, { + .id = SNOR_ID(0x20, 0x40, 0x18), + .name = "XM25QH128C", + .size = SZ_16M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, }; -- 2.51.0 From 5fcfdcd3d02f2707b544005c7f657ebb852d3e46 Mon Sep 17 00:00:00 2001 From: Daniel Danzberger Date: Wed, 3 Aug 2022 17:31:03 +0200 Subject: [PATCH 238/517] mtd: spinand: Add support for Etron EM73D044VCx Airoha is a new ARM platform based on Cortex-A53 which has recently been merged into linux-next. Due to BootROM limitations on this platform, the Cortex-A53 can't run in Aarch64 mode and code must be compiled for 32-Bit ARM. This support is based mostly on those linux-next commits backported for kernel 5.15. Patches: 1 - platform support = linux-next 2 - clock driver = linux-next 3 - gpio driver = linux-next 4 - linux,usable-memory-range dts support = linux-next 5 - mtd spinand driver 6 - spi driver 7 - pci driver (kconfig only, uses mediatek PCI) = linux-next Still missing: - Ethernet driver - Sysupgrade support A.t.m there exists one subtarget EN7523 with only one evaluation board. The initramfs can be run with the following commands from u-boot: - u-boot> setenv bootfile \ openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin u-boot> tftpboot u-boot> bootm 0x81800000 - Submitted-by: Daniel Danzberger --- drivers/mtd/nand/spi/Makefile | 4 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/etron.c | 98 +++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/nand/spi/etron.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 32a696055d9f..f725f0c67307 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o -spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o +spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o +spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index f3787a63a355..8e56ca65ac4f 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1159,6 +1159,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, + &etron_spinand_manufacturer, &fmsh_spinand_manufacturer, &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c new file mode 100644 index 000000000000..653092be5938 --- /dev/null +++ b/drivers/mtd/nand/spi/etron.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#define SPINAND_MFR_ETRON 0xd5 + + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + +static int etron_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + oobregion->offset = 72; + oobregion->length = 56; + + return 0; +} + +static int etron_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section) + return -ERANGE; + + oobregion->offset = 1; + oobregion->length = 71; + + return 0; +} + +static int etron_ecc_get_status(struct spinand_device *spinand, u8 status) +{ + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_HAS_BITFLIPS: + /* Between 1-7 bitflips were corrected */ + return 7; + + case STATUS_ECC_MASK: + /* Maximum bitflips were corrected */ + return 8; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + } + + return -EINVAL; +} + +static const struct mtd_ooblayout_ops etron_ooblayout = { + .ecc = etron_ooblayout_ecc, + .free = etron_ooblayout_free, +}; + +static const struct spinand_info etron_spinand_table[] = { + SPINAND_INFO("EM73D044VCx", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f), + // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)), +}; + +static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer etron_spinand_manufacturer = { + .id = SPINAND_MFR_ETRON, + .name = "Etron", + .chips = etron_spinand_table, + .nchips = ARRAY_SIZE(etron_spinand_table), + .ops = &etron_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index ba7b73c9675e..e5b6ac340383 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -263,6 +263,7 @@ struct spinand_manufacturer { extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; +extern const struct spinand_manufacturer etron_spinand_manufacturer; extern const struct spinand_manufacturer fmsh_spinand_manufacturer; extern const struct spinand_manufacturer foresee_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; -- 2.51.0 From 41816d01e19a9ff217b6851b822598895cc37a48 Mon Sep 17 00:00:00 2001 From: Joe Mullally Date: Mon, 3 Nov 2025 15:49:48 +0100 Subject: [PATCH 239/517] mtd/spi-nor/xmc: add support for XMC XM25QH64C The XMC XM25QH64C is a 8MB SPI NOR chip. The patch is verified on TL-WPA8631P v3. Datasheet available at https://www.xmcwh.com/uploads/442/XM25QH64C.pdf Signed-off-by: Joe Mullally --- drivers/mtd/spi-nor/xmc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi-nor/xmc.c b/drivers/mtd/spi-nor/xmc.c index 8eb2d957c8ad..d52756562489 100644 --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c @@ -14,6 +14,11 @@ static const struct flash_info xmc_nor_parts[] = { .name = "XM25QH64A", .size = SZ_8M, .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, { + .id = SNOR_ID(0x20, 0x40, 0x17), + .name = "XM25QH64C", + .size = SZ_8M, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, { .id = SNOR_ID(0x20, 0x70, 0x18), .name = "XM25QH128A", -- 2.51.0 From e361d0ef02084d0b709b8930a3aaf52a75df6ecc Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:49:48 +0100 Subject: [PATCH 240/517] ubi: auto-attach mtd device named "ubi" or "data" on boot Signed-off-by: Daniel Golle --- drivers/mtd/ubi/build.c | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index ef6a22f372f9..82247bfe0332 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1263,6 +1263,80 @@ static struct mtd_notifier ubi_mtd_notifier = { .remove = ubi_notify_remove, }; + +/* + * This function tries attaching mtd partitions named either "ubi" or "data" + * during boot. + */ +static void __init ubi_auto_attach(void) +{ + int err; + struct mtd_info *mtd; + struct device_node *np; + loff_t offset = 0; + size_t len; + char magic[4]; + + /* try attaching mtd device named "ubi" or "data" */ + mtd = open_mtd_device("ubi"); + if (IS_ERR(mtd)) + mtd = open_mtd_device("data"); + + if (IS_ERR(mtd)) + return; + + /* skip "linux,ubi" mtd as it has already been attached */ + np = mtd_get_of_node(mtd); + if (of_device_is_compatible(np, "linux,ubi")) + goto cleanup; + + /* get the first not bad block */ + if (mtd_can_have_bb(mtd)) + while (mtd_block_isbad(mtd, offset)) { + offset += mtd->erasesize; + + if (offset > mtd->size) { + pr_err("UBI error: Failed to find a non-bad " + "block on mtd%d\n", mtd->index); + goto cleanup; + } + } + + /* check if the read from flash was successful */ + err = mtd_read(mtd, offset, 4, &len, (void *) magic); + if ((err && !mtd_is_bitflip(err)) || len != 4) { + pr_err("UBI error: unable to read from mtd%d\n", mtd->index); + goto cleanup; + } + + /* check for a valid ubi magic */ + if (strncmp(magic, "UBI#", 4)) { + pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index); + goto cleanup; + } + + /* don't auto-add media types where UBI doesn't makes sense */ + if (mtd->type != MTD_NANDFLASH && + mtd->type != MTD_NORFLASH && + mtd->type != MTD_DATAFLASH && + mtd->type != MTD_MLCNANDFLASH) + goto cleanup; + + mutex_lock(&ubi_devices_mutex); + pr_notice("UBI: auto-attach mtd%d\n", mtd->index); + err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false, false); + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + pr_err("UBI error: cannot attach mtd%d\n", mtd->index); + goto cleanup; + } + + return; + +cleanup: + put_mtd_device(mtd); +} + static int __init ubi_init_attach(void) { int err, i, k; @@ -1314,6 +1388,12 @@ static int __init ubi_init_attach(void) } } + /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd + * parameter was given */ + if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && + !ubi_is_module() && !mtd_devs) + ubi_auto_attach(); + return 0; out_detach: -- 2.51.0 From cad4fa01f1219cb6fa41fd18dc398100e5963f23 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:49:48 +0100 Subject: [PATCH 241/517] ubi: auto-create ubiblock device for rootfs Signed-off-by: Daniel Golle --- drivers/mtd/ubi/block.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 60d0155be869..3d2f89cfbab0 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -575,10 +575,47 @@ match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int return true; } +#define UBIFS_NODE_MAGIC 0x06101831 +static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) +{ + int ret; + uint32_t magic_of, magic; + ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); + if (ret) + return 0; + magic = le32_to_cpu(magic_of); + return magic == UBIFS_NODE_MAGIC; +} + +static void ubiblock_create_auto_rootfs(struct ubi_volume_info *vi) +{ + int ret, is_ubifs; + struct ubi_volume_desc *desc; + + if (strcmp(vi->name, "rootfs") && + strcmp(vi->name, "fit")) + return; + + desc = ubi_open_volume(vi->ubi_num, vi->vol_id, UBI_READONLY); + if (IS_ERR(desc)) + return; + + is_ubifs = ubi_vol_is_ubifs(desc); + ubi_close_volume(desc); + if (is_ubifs) + return; + + ret = ubiblock_create(vi); + if (ret) + pr_err("UBI error: block: can't add '%s' volume, err=%d\n", + vi->name, ret); +} + static void ubiblock_create_from_param(struct ubi_volume_info *vi) { int i, ret = 0; + bool got_param = false; struct ubiblock_param *p; /* @@ -591,6 +628,7 @@ ubiblock_create_from_param(struct ubi_volume_info *vi) if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id)) continue; + got_param = true; ret = ubiblock_create(vi); if (ret) { pr_err( @@ -599,6 +637,10 @@ ubiblock_create_from_param(struct ubi_volume_info *vi) } break; } + + /* auto-attach "rootfs" volume if existing and non-ubifs */ + if (!got_param && IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV)) + ubiblock_create_auto_rootfs(vi); } static int ubiblock_notify(struct notifier_block *nb, -- 2.51.0 From 74dbb1605aced27216d2caa82680008159d34baf Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:49:49 +0100 Subject: [PATCH 242/517] try auto-mounting ubi0:rootfs in init/do_mounts.c Signed-off-by: Daniel Golle --- init/do_mounts.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index 6af29da8889e..cbb4237700aa 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -250,7 +250,30 @@ void __init mount_root_generic(char *name, char *pretty_name, int flags) out: put_page(page); } - + +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV +static int __init mount_ubi_rootfs(void) +{ + int flags = MS_SILENT; + int err, tried = 0; + + while (tried < 2) { + err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ + root_mount_data); + switch (err) { + case -EACCES: + flags |= MS_RDONLY; + tried++; + break; + default: + return err; + } + } + + return -EINVAL; +} +#endif + #ifdef CONFIG_ROOT_NFS #define NFSROOT_TIMEOUT_MIN 5 @@ -387,6 +410,11 @@ static inline void mount_block_root(char *root_device_name) void __init mount_root(char *root_device_name) { +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV + if (!mount_ubi_rootfs()) + return; +#endif + switch (ROOT_DEV) { case Root_NFS: mount_nfs_root(); -- 2.51.0 From 91bf41024ca9e5396631a8b1aadf12b6c3396d3b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:49:49 +0100 Subject: [PATCH 243/517] ubi: set ROOT_DEV to ubiblock "rootfs" if unset Signed-off-by: Daniel Golle --- drivers/mtd/ubi/block.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 3d2f89cfbab0..b45f9ca8866a 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "ubi-media.h" #include "ubi.h" @@ -431,6 +432,15 @@ int ubiblock_create(struct ubi_volume_info *vi) dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); mutex_unlock(&devices_mutex); + + if (!strcmp(vi->name, "rootfs") && + IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && + ROOT_DEV == 0) { + pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", + dev->ubi_num, dev->vol_id, vi->name); + ROOT_DEV = MKDEV(gd->major, gd->first_minor); + } + return 0; out_remove_minor: -- 2.51.0 From e756171aa3fa371557bab27c509acd4f23b1f2f8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 3 Nov 2025 15:49:49 +0100 Subject: [PATCH 244/517] mtd: add EOF marker support to the UBI layer Signed-off-by: Gabor Juhos --- drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++--- drivers/mtd/ubi/ubi.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index adc47b87b38a..7eae13888f1c 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id) #endif } +static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) +{ + return ech->padding1[0] == 'E' && + ech->padding1[1] == 'O' && + ech->padding1[2] == 'F'; +} + /** * scan_peb - scan and process UBI headers of a PEB. * @ubi: UBI device description object @@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; } - err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); - if (err < 0) - return err; + if (!ai->eof_found) { + err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); + if (err < 0) + return err; + + if (ec_hdr_has_eof(ech)) { + pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n", + pnum); + ai->eof_found = true; + } + } + + if (ai->eof_found) + err = UBI_IO_FF_BITFLIPS; + switch (err) { case 0: break; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 1c9e874e8ede..690f25ffddc2 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -778,6 +778,7 @@ struct ubi_attach_info { int mean_ec; uint64_t ec_sum; int ec_count; + bool eof_found; struct kmem_cache *aeb_slab_cache; struct ubi_ec_hdr *ech; struct ubi_vid_io_buf *vidb; -- 2.51.0 From 4604417d761220471f5000b78a352f879a81b611 Mon Sep 17 00:00:00 2001 From: Bernhard Frauendienst Date: Wed, 5 Sep 2018 01:32:51 +0200 Subject: [PATCH 245/517] dt-bindings: add bindings for mtd-concat devices Document virtual mtd-concat device bindings. Signed-off-by: Bernhard Frauendienst --- .../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt diff --git a/Documentation/devicetree/bindings/mtd/mtd-concat.txt b/Documentation/devicetree/bindings/mtd/mtd-concat.txt new file mode 100644 index 000000000000..2daf3157b163 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt @@ -0,0 +1,36 @@ +Virtual MTD concat device + +Requires properties: +- devices: list of phandles to mtd nodes that should be concatenated + +Example: + +&spi { + flash0: flash@0 { + ... + }; + flash1: flash@1 { + ... + }; +}; + +flash { + compatible = "mtd-concat"; + + devices = <&flash0 &flash1>; + + partitions { + compatible = "fixed-partitions"; + + partition@0 { + label = "boot"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + partition@40000 { + label = "firmware"; + reg = <0x0040000 0x1fc0000>; + }; + } +} -- 2.51.0 From f8d352e43303fc728b050bad1ec4f0684a348978 Mon Sep 17 00:00:00 2001 From: Bernhard Frauendienst Date: Sat, 25 Aug 2018 12:35:22 +0200 Subject: [PATCH 246/517] mtd: mtdconcat: add dt driver for concat devices Some mtd drivers like physmap variants have support for concatenating multiple mtd devices, but there is no generic way to define such a concat device from within the device tree. This is useful for some SoC boards that use multiple flash chips as memory banks of a single mtd device, with partitions spanning chip borders. This commit adds a driver for creating virtual mtd-concat devices. They must have a compatible = "mtd-concat" line, and define a list of devices to concat in the 'devices' property, for example: flash { compatible = "mtd-concat"; devices = <&flash0 &flash1>; partitions { ... }; }; The driver is added to the very end of the mtd Makefile to increase the likelyhood of all child devices already being loaded at the time of probing, preventing unnecessary deferred probes. Signed-off-by: Bernhard Frauendienst --- drivers/mtd/Kconfig | 2 + drivers/mtd/Makefile | 3 + drivers/mtd/composite/Kconfig | 12 +++ drivers/mtd/composite/Makefile | 6 ++ drivers/mtd/composite/virt_concat.c | 127 ++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 drivers/mtd/composite/Kconfig create mode 100644 drivers/mtd/composite/Makefile create mode 100644 drivers/mtd/composite/virt_concat.c diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index f9ed93c4cf0f..7e4a3fa1dfd0 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -241,4 +241,6 @@ source "drivers/mtd/ubi/Kconfig" source "drivers/mtd/hyperbus/Kconfig" +source "drivers/mtd/composite/Kconfig" + endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index b14b7fe0f597..fbea3736b488 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ + +# Composite drivers must be loaded last +obj-y += composite/ diff --git a/drivers/mtd/composite/Kconfig b/drivers/mtd/composite/Kconfig new file mode 100644 index 000000000000..0490fc0284bb --- /dev/null +++ b/drivers/mtd/composite/Kconfig @@ -0,0 +1,12 @@ +menu "Composite MTD device drivers" + depends on MTD!=n + +config MTD_VIRT_CONCAT + tristate "Virtual concat MTD device" + help + This driver allows creation of a virtual MTD concat device, which + concatenates multiple underlying MTD devices to a single device. + This is required by some SoC boards where multiple memory banks are + used as one device with partitions spanning across device boundaries. + +endmenu diff --git a/drivers/mtd/composite/Makefile b/drivers/mtd/composite/Makefile new file mode 100644 index 000000000000..8421a0a30606 --- /dev/null +++ b/drivers/mtd/composite/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# linux/drivers/mtd/composite/Makefile +# + +obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o diff --git a/drivers/mtd/composite/virt_concat.c b/drivers/mtd/composite/virt_concat.c new file mode 100644 index 000000000000..05b4b9a7539e --- /dev/null +++ b/drivers/mtd/composite/virt_concat.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Virtual concat MTD device driver + * + * Copyright (C) 2018 Bernhard Frauendienst + * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * struct of_virt_concat - platform device driver data. + * @cmtd the final mtd_concat device + * @num_devices the number of devices in @devices + * @devices points to an array of devices already loaded + */ +struct of_virt_concat { + struct mtd_info *cmtd; + int num_devices; + struct mtd_info **devices; +}; + +static void virt_concat_remove(struct platform_device *pdev) +{ + struct of_virt_concat *info; + int i; + + info = platform_get_drvdata(pdev); + if (!info) + return; + + // unset data for when this is called after a probe error + platform_set_drvdata(pdev, NULL); + + if (info->cmtd) { + mtd_device_unregister(info->cmtd); + mtd_concat_destroy(info->cmtd); + } + + if (info->devices) { + for (i = 0; i < info->num_devices; i++) + put_mtd_device(info->devices[i]); + } +} + +static int virt_concat_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct of_phandle_iterator it; + struct of_virt_concat *info; + struct mtd_info *mtd; + int err = 0, count; + + count = of_count_phandle_with_args(node, "devices", NULL); + if (count <= 0) + return -EINVAL; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->devices = devm_kcalloc(&pdev->dev, count, + sizeof(*(info->devices)), GFP_KERNEL); + if (!info->devices) { + err = -ENOMEM; + goto err_remove; + } + + platform_set_drvdata(pdev, info); + + of_for_each_phandle(&it, err, node, "devices", NULL, 0) { + mtd = of_get_mtd_device_by_node(it.node); + if (IS_ERR(mtd)) { + of_node_put(it.node); + err = -EPROBE_DEFER; + goto err_remove; + } + + info->devices[info->num_devices++] = mtd; + } + + info->cmtd = mtd_concat_create(info->devices, info->num_devices, + dev_name(&pdev->dev)); + if (!info->cmtd) { + err = -ENXIO; + goto err_remove; + } + + info->cmtd->dev.parent = &pdev->dev; + mtd_set_of_node(info->cmtd, node); + mtd_device_register(info->cmtd, NULL, 0); + + return 0; + +err_remove: + virt_concat_remove(pdev); + + return err; +} + +static const struct of_device_id virt_concat_of_match[] = { + { .compatible = "mtd-concat", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, virt_concat_of_match); + +static struct platform_driver virt_concat_driver = { + .probe = virt_concat_probe, + .remove = virt_concat_remove, + .driver = { + .name = "virt-mtdconcat", + .of_match_table = virt_concat_of_match, + }, +}; + +module_platform_driver(virt_concat_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Bernhard Frauendienst "); +MODULE_DESCRIPTION("Virtual concat MTD device driver"); -- 2.51.0 From 347c5537f56a96c67c3a22c4f3779c4b95dc11a5 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Mon, 27 Dec 2021 00:38:13 +0100 Subject: [PATCH 247/517] mtd: spi-nor: locking support for MX25L6405D Macronix MX25L6405D supports locking with four block-protection bits. Currently, the driver only sets three bits. If the bootloader does not sustain the flash chip in an unlocked state, the flash might be non-writeable. Add the corresponding flag to enable locking support with four bits in the status register. Tested on Nanostation M2 XM. Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for MX25L12805D") Signed-off-by: David Bauer Signed-off-by: Nick Hainke --- drivers/mtd/spi-nor/macronix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index ac125b89e7ba..d31b2590c849 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -66,6 +66,7 @@ static const struct flash_info macronix_nor_parts[] = { .id = SNOR_ID(0xc2, 0x20, 0x17), .name = "mx25l6405d", .size = SZ_8M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP, .no_sfdp_flags = SECT_4K, }, { .id = SNOR_ID(0xc2, 0x20, 0x18), -- 2.51.0 From 9fa9e3569e11cbb64b50a208ae98a4b2e09e00c4 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Mon, 27 Dec 2021 09:33:13 +0100 Subject: [PATCH 248/517] mtd: spi-nor: disable 16-bit-sr for macronix Macronix flash chips seem to consist of only one status register. These chips will not work with the "16-bit Write Status (01h) Command". Disable SNOR_F_HAS_16BIT_SR for all Macronix chips. Tested with MX25L6405D. Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on lock()/unlock()") Signed-off-by: David Bauer Signed-off-by: Nick Hainke --- drivers/mtd/spi-nor/macronix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index d31b2590c849..873c199616ee 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -195,6 +195,7 @@ static int macronix_nor_late_init(struct spi_nor *nor) { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; + nor->flags &= ~SNOR_F_HAS_16BIT_SR; nor->flags |= SNOR_F_HAS_LOCK; return 0; -- 2.51.0 From c57f1d7da4a3684160aad8280a29764983fc99e0 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 12:21:15 +0200 Subject: [PATCH 249/517] fs: add cdrom dependency --- fs/hfs/Kconfig | 1 + fs/hfsplus/Kconfig | 1 + fs/isofs/Kconfig | 1 + fs/udf/Kconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/fs/hfs/Kconfig b/fs/hfs/Kconfig index 5ea5cd8ecea9..8a0ca259dc58 100644 --- a/fs/hfs/Kconfig +++ b/fs/hfs/Kconfig @@ -2,6 +2,7 @@ config HFS_FS tristate "Apple Macintosh file system support" depends on BLOCK + select CDROM select BUFFER_HEAD select NLS select LEGACY_DIRECT_IO diff --git a/fs/hfsplus/Kconfig b/fs/hfsplus/Kconfig index 8ce4a33a9ac7..f3f07878dbbd 100644 --- a/fs/hfsplus/Kconfig +++ b/fs/hfsplus/Kconfig @@ -2,6 +2,7 @@ config HFSPLUS_FS tristate "Apple Extended HFS file system support" depends on BLOCK + select CDROM select BUFFER_HEAD select NLS select NLS_UTF8 diff --git a/fs/isofs/Kconfig b/fs/isofs/Kconfig index 51434f2a471b..9847d2e3aac2 100644 --- a/fs/isofs/Kconfig +++ b/fs/isofs/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config ISO9660_FS tristate "ISO 9660 CDROM file system support" + select CDROM select BUFFER_HEAD help This is the standard file system used on CD-ROMs. It was previously diff --git a/fs/udf/Kconfig b/fs/udf/Kconfig index 8f7ce30d47fd..0b015b1a455a 100644 --- a/fs/udf/Kconfig +++ b/fs/udf/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config UDF_FS tristate "UDF file system support" + select CDROM select BUFFER_HEAD select CRC_ITU_T select NLS -- 2.51.0 From 518d8e07b43f2428a02fef795710a7ddab3e7ae1 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 16 Nov 2022 12:49:52 +0000 Subject: [PATCH 250/517] block: add uImage.FIT subimage block driver Add a small block driver which exposes filesystem sub-images contained in U-Boot uImage.FIT images as block devices. The uImage.FIT image has to be stored directly on a block device or partition, MTD device or partition, or UBI volume. The driver is intended for systems using the U-Boot bootloader and uses the root device hint left by the bootloader (or the user) in the 'chosen' section of the device-tree. Example: /dts-v1/; / { chosen { rootdisk = <&mmc0_part3>; }; }; Signed-off-by: Daniel Golle --- MAINTAINERS | 6 + drivers/block/Kconfig | 12 + drivers/block/Makefile | 2 + drivers/block/fitblk.c | 660 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/fitblk.h | 10 + 5 files changed, 690 insertions(+) create mode 100644 drivers/block/fitblk.c create mode 100644 include/uapi/linux/fitblk.h diff --git a/MAINTAINERS b/MAINTAINERS index 7d694e7b4f42..dcb5c71bc204 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23668,6 +23668,12 @@ F: Documentation/filesystems/ubifs-authentication.rst F: Documentation/filesystems/ubifs.rst F: fs/ubifs/ +U-BOOT UIMAGE.FIT PARSER +M: Daniel Golle +L: linux-block@vger.kernel.org +S: Maintained +F: drivers/block/fitblk.c + UBLK USERSPACE BLOCK DRIVER M: Ming Lei L: linux-block@vger.kernel.org diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ed209f4f2798..c777065f70e4 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -363,6 +363,18 @@ config BLK_DEV_RUST_NULL If unsure, say N. +config UIMAGE_FIT_BLK + bool "uImage.FIT block driver" + help + This driver allows using filesystems contained in uImage.FIT images + by mapping them as block devices. + + It can currently not be built as a module due to libfdt symbols not + being exported. + + Say Y if you want to mount filesystems sub-images of a uImage.FIT + stored in a block device partition, mtdblock or ubiblock device. + config BLK_DEV_RBD tristate "Rados block device (RBD)" depends on INET && BLOCK diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 1105a2d4fdcb..2ba7b5ad8f6f 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -42,4 +42,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk/ obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o +obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o + swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/fitblk.c b/drivers/block/fitblk.c new file mode 100644 index 000000000000..b6d8e0fd25a0 --- /dev/null +++ b/drivers/block/fitblk.c @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * uImage.FIT virtual block device driver. + * + * Copyright (C) 2023 Daniel Golle + * Copyright (C) 2007 Nick Piggin + * Copyright (C) 2007 Novell Inc. + * + * Initially derived from drivers/block/brd.c which is in parts derived from + * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective + * owners. + * + * uImage.FIT headers extracted from Das U-Boot + * (C) Copyright 2008 Semihalf + * (C) Copyright 2000-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FIT_DEVICE_PREFIX "fit" + +/* maximum number of pages used for the uImage.FIT index structure */ +#define FIT_MAX_PAGES 1024 + +/* minimum free sectors to map as read-write "remainder" volume */ +#define MIN_FREE_SECT 16 + +/* maximum number of mapped loadables */ +#define MAX_FIT_LOADABLES 16 + +/* constants for uImage.FIT structrure traversal */ +#define FIT_IMAGES_PATH "/images" +#define FIT_CONFS_PATH "/configurations" + +/* hash/signature/key node */ +#define FIT_HASH_NODENAME "hash" +#define FIT_ALGO_PROP "algo" +#define FIT_VALUE_PROP "value" +#define FIT_IGNORE_PROP "uboot-ignore" +#define FIT_SIG_NODENAME "signature" +#define FIT_KEY_REQUIRED "required" +#define FIT_KEY_HINT "key-name-hint" + +/* cipher node */ +#define FIT_CIPHER_NODENAME "cipher" +#define FIT_ALGO_PROP "algo" + +/* image node */ +#define FIT_DATA_PROP "data" +#define FIT_DATA_POSITION_PROP "data-position" +#define FIT_DATA_OFFSET_PROP "data-offset" +#define FIT_DATA_SIZE_PROP "data-size" +#define FIT_TIMESTAMP_PROP "timestamp" +#define FIT_DESC_PROP "description" +#define FIT_ARCH_PROP "arch" +#define FIT_TYPE_PROP "type" +#define FIT_OS_PROP "os" +#define FIT_COMP_PROP "compression" +#define FIT_ENTRY_PROP "entry" +#define FIT_LOAD_PROP "load" + +/* configuration node */ +#define FIT_KERNEL_PROP "kernel" +#define FIT_FILESYSTEM_PROP "filesystem" +#define FIT_RAMDISK_PROP "ramdisk" +#define FIT_FDT_PROP "fdt" +#define FIT_LOADABLE_PROP "loadables" +#define FIT_DEFAULT_PROP "default" +#define FIT_SETUP_PROP "setup" +#define FIT_FPGA_PROP "fpga" +#define FIT_FIRMWARE_PROP "firmware" +#define FIT_STANDALONE_PROP "standalone" + +/* fitblk driver data */ +static const char *_fitblk_claim_ptr = "I belong to fitblk"; +static const char *ubootver; +struct device_node *rootdisk; +static struct platform_device *pdev; +static LIST_HEAD(fitblk_devices); +static DEFINE_MUTEX(devices_mutex); +refcount_t num_devs; + +struct fitblk { + struct platform_device *pdev; + struct file *bdev_file; + sector_t start_sect; + struct gendisk *disk; + struct work_struct remove_work; + struct list_head list; + bool dead; +}; + +static int fitblk_open(struct gendisk *disk, fmode_t mode) +{ + struct fitblk *fitblk = disk->private_data; + + if (fitblk->dead) + return -ENOENT; + + return 0; +} + +static void fitblk_release(struct gendisk *disk) +{ + return; +} + +static void fitblk_submit_bio(struct bio *orig_bio) +{ + struct bio *bio = orig_bio; + struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data; + + if (fitblk->dead) + return; + + /* mangle bio and re-submit */ + while (bio) { + bio->bi_iter.bi_sector += fitblk->start_sect; + bio->bi_bdev = file_bdev(fitblk->bdev_file); + bio = bio->bi_next; + } + submit_bio(orig_bio); +} + +static void fitblk_remove(struct fitblk *fitblk) +{ + blk_mark_disk_dead(fitblk->disk); + mutex_lock(&devices_mutex); + fitblk->dead = true; + list_del(&fitblk->list); + mutex_unlock(&devices_mutex); + + schedule_work(&fitblk->remove_work); +} + +static int fitblk_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct fitblk *fitblk = bdev->bd_disk->private_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (fitblk->dead) + return -ENOENT; + + switch (cmd) { + case FITBLK_RELEASE: + fitblk_remove(fitblk); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct block_device_operations fitblk_fops = { + .owner = THIS_MODULE, + .ioctl = fitblk_ioctl, + .open = fitblk_open, + .release = fitblk_release, + .submit_bio = fitblk_submit_bio, +}; + +static void fitblk_purge(struct work_struct *work) +{ + struct fitblk *fitblk = container_of(work, struct fitblk, remove_work); + + del_gendisk(fitblk->disk); + refcount_dec(&num_devs); + platform_device_del(fitblk->pdev); + platform_device_put(fitblk->pdev); + + if (refcount_dec_if_one(&num_devs)) { + sysfs_remove_link(&pdev->dev.kobj, "lower_dev"); + fput(fitblk->bdev_file); + } + + kfree(fitblk); +} + +static int add_fit_subimage_device(struct file *bdev_file, + unsigned int slot, sector_t start_sect, + sector_t nr_sect, bool readonly) +{ + struct block_device *bdev = file_bdev(bdev_file); + struct fitblk *fitblk; + struct gendisk *disk; + int err; + + mutex_lock(&devices_mutex); + if (!refcount_inc_not_zero(&num_devs)) + return -EBADF; + + fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL); + if (!fitblk) { + err = -ENOMEM; + goto out_unlock; + } + + fitblk->bdev_file = bdev_file; + fitblk->start_sect = start_sect; + INIT_WORK(&fitblk->remove_work, fitblk_purge); + + disk = blk_alloc_disk(&bdev->bd_disk->queue->limits, NUMA_NO_NODE); + if (!disk) { + err = -ENOMEM; + goto out_free_fitblk; + } + + disk->first_minor = 0; + disk->flags = bdev->bd_disk->flags | GENHD_FL_NO_PART; + disk->fops = &fitblk_fops; + disk->private_data = fitblk; + if (readonly) { + set_disk_ro(disk, 1); + snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot); + } else { + strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw"); + } + + set_capacity(disk, nr_sect); + disk->queue->queue_flags = bdev->bd_disk->queue->queue_flags; + + fitblk->disk = disk; + fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE); + if (!fitblk->pdev) { + err = -ENOMEM; + goto out_cleanup_disk; + } + + fitblk->pdev->dev.parent = &pdev->dev; + err = platform_device_add(fitblk->pdev); + if (err) + goto out_put_pdev; + + err = device_add_disk(&fitblk->pdev->dev, disk, NULL); + if (err) + goto out_del_pdev; + + if (!ROOT_DEV) + ROOT_DEV = disk->part0->bd_dev; + + list_add_tail(&fitblk->list, &fitblk_devices); + + mutex_unlock(&devices_mutex); + + return 0; + +out_del_pdev: + platform_device_del(fitblk->pdev); +out_put_pdev: + platform_device_put(fitblk->pdev); +out_cleanup_disk: + put_disk(disk); +out_free_fitblk: + kfree(fitblk); +out_unlock: + refcount_dec(&num_devs); + mutex_unlock(&devices_mutex); + return err; +} + +static void fitblk_mark_dead(struct block_device *bdev, bool surprise) +{ + struct list_head *n, *tmp; + struct fitblk *fitblk; + + mutex_lock(&devices_mutex); + list_for_each_safe(n, tmp, &fitblk_devices) { + fitblk = list_entry(n, struct fitblk, list); + if (file_bdev(fitblk->bdev_file) != bdev) + continue; + + fitblk->dead = true; + list_del(&fitblk->list); + /* removal needs to be deferred to avoid deadlock */ + schedule_work(&fitblk->remove_work); + } + mutex_unlock(&devices_mutex); +} + +static const struct blk_holder_ops fitblk_hops = { + .mark_dead = fitblk_mark_dead, +}; + +static int parse_fit_on_dev(struct device *dev) +{ + struct file *bdev_file; + struct block_device *bdev; + struct address_space *mapping; + struct folio *folio; + pgoff_t f_index = 0; + size_t bytes_left, bytes_to_copy; + void *pre_fit, *fit, *fit_c; + u64 dsize, dsectors, imgmaxsect = 0; + u32 size, image_pos, image_len; + const __be32 *image_offset_be, *image_len_be, *image_pos_be; + int ret = 0, node, images, config; + const char *image_name, *image_type, *image_description, + *config_default, *config_description, *config_loadables; + u32 image_name_len, image_type_len, image_description_len, + bootconf_len, config_default_len, config_description_len, + config_loadables_len; + sector_t start_sect, nr_sects; + struct device_node *np = NULL; + const char *bootconf_c; + const char *loadable; + char *bootconf = NULL, *bootconf_term; + bool found; + int loadables_rem_len, loadable_len; + u16 loadcnt; + unsigned int slot = 0; + + /* Exclusive open the block device to receive holder notifications */ + bdev_file = bdev_file_open_by_dev(dev->devt, + BLK_OPEN_READ | BLK_OPEN_RESTRICT_WRITES, + &_fitblk_claim_ptr, &fitblk_hops); + if (!bdev_file) + return -ENODEV; + + if (IS_ERR(bdev_file)) + return PTR_ERR(bdev_file); + + bdev = file_bdev(bdev_file); + mapping = bdev_file->f_mapping; + + /* map first page */ + folio = read_mapping_folio(mapping, f_index++, NULL); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); + goto out_blkdev; + } + pre_fit = folio_address(folio) + offset_in_folio(folio, 0); + + /* uImage.FIT is based on flattened device tree structure */ + if (fdt_check_header(pre_fit)) { + ret = -EINVAL; + folio_put(folio); + goto out_blkdev; + } + + size = fdt_totalsize(pre_fit); + + if (size > PAGE_SIZE * FIT_MAX_PAGES) { + ret = -EOPNOTSUPP; + folio_put(folio); + goto out_blkdev; + } + + /* acquire disk size */ + dsectors = bdev_nr_sectors(bdev); + dsize = dsectors << SECTOR_SHIFT; + + /* abort if FIT structure is larger than disk or partition size */ + if (size >= dsize) { + ret = -EFBIG; + folio_put(folio); + goto out_blkdev; + } + + fit = kmalloc(size, GFP_KERNEL); + if (!fit) { + ret = -ENOMEM; + folio_put(folio); + goto out_blkdev; + } + + bytes_left = size; + fit_c = fit; + while (bytes_left > 0) { + bytes_to_copy = min_t(size_t, bytes_left, + folio_size(folio) - offset_in_folio(folio, 0)); + memcpy(fit_c, pre_fit, bytes_to_copy); + fit_c += bytes_to_copy; + bytes_left -= bytes_to_copy; + if (bytes_left) { + folio_put(folio); + folio = read_mapping_folio(mapping, f_index++, NULL); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); + goto out_blkdev; + }; + pre_fit = folio_address(folio) + offset_in_folio(folio, 0); + } + } + folio_put(folio); + + /* set boot config node name U-Boot may have added to the device tree */ + np = of_find_node_by_path("/chosen"); + if (np) { + bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len); + if (bootconf_c && bootconf_len) + bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL); + } + + if (bootconf) { + bootconf_term = strchr(bootconf, '#'); + if (bootconf_term) + *bootconf_term = '\0'; + } + + /* find configuration path in uImage.FIT */ + config = fdt_path_offset(fit, FIT_CONFS_PATH); + if (config < 0) { + pr_err("FIT: Cannot find %s node: %d\n", + FIT_CONFS_PATH, config); + ret = -ENOENT; + goto out_bootconf; + } + + /* get default configuration node name */ + config_default = + fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len); + + /* make sure we got either default or selected boot config node name */ + if (!config_default && !bootconf) { + pr_err("FIT: Cannot find default configuration\n"); + ret = -ENOENT; + goto out_bootconf; + } + + /* find selected boot config node, fallback on default config node */ + node = fdt_subnode_offset(fit, config, bootconf ?: config_default); + if (node < 0) { + pr_err("FIT: Cannot find %s node: %d\n", + bootconf ?: config_default, node); + ret = -ENOENT; + goto out_bootconf; + } + + pr_info("FIT: Detected U-Boot %s\n", ubootver); + + /* get selected configuration data */ + config_description = + fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len); + config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP, + &config_loadables_len); + + pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n", + bootconf ? "Selected" : "Default", + bootconf ? bootconf_len : config_default_len, + bootconf ?: config_default, + config_description ? " (" : "", + config_description ? config_description_len : 0, + config_description ?: "", + config_description ? ")" : ""); + + if (!config_loadables || !config_loadables_len) { + pr_err("FIT: No loadables configured in \"%s\"\n", + bootconf ?: config_default); + ret = -ENOENT; + goto out_bootconf; + } + + /* get images path in uImage.FIT */ + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) { + pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images); + ret = -EINVAL; + goto out_bootconf; + } + + /* iterate over images in uImage.FIT */ + fdt_for_each_subnode(node, fit, images) { + image_name = fdt_get_name(fit, node, &image_name_len); + image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); + image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL); + image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL); + image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL); + + if (!image_name || !image_type || !image_len_be || + !image_name_len || !image_type_len) + continue; + + image_len = be32_to_cpu(*image_len_be); + if (!image_len) + continue; + + if (image_offset_be) + image_pos = be32_to_cpu(*image_offset_be) + size; + else if (image_pos_be) + image_pos = be32_to_cpu(*image_pos_be); + else + continue; + + image_description = fdt_getprop(fit, node, FIT_DESC_PROP, + &image_description_len); + + pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n", + image_type, image_pos, image_pos + image_len - 1, + image_name_len, image_name, image_description ? " (" : "", + image_description ? image_description_len : 0, + image_description ?: "", image_description ? ") " : ""); + + /* only 'filesystem' images should be mapped as partitions */ + if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len)) + continue; + + /* check if sub-image is part of configured loadables */ + found = false; + loadable = config_loadables; + loadables_rem_len = config_loadables_len; + for (loadcnt = 0; loadables_rem_len > 1 && + loadcnt < MAX_FIT_LOADABLES; ++loadcnt) { + loadable_len = + strnlen(loadable, loadables_rem_len - 1) + 1; + loadables_rem_len -= loadable_len; + if (!strncmp(image_name, loadable, loadable_len)) { + found = true; + break; + } + loadable += loadable_len; + } + if (!found) + continue; + + if (image_pos % (1 << PAGE_SHIFT)) { + dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n", + image_name_len, image_name); + continue; + } + + if (image_len % (1 << PAGE_SHIFT)) { + dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n", + image_name_len, image_name); + continue; + } + + start_sect = image_pos >> SECTOR_SHIFT; + nr_sects = image_len >> SECTOR_SHIFT; + imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects); + + if (start_sect + nr_sects > dsectors) { + dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n", + image_name_len, image_name); + continue; + } + + if (!slot) { + ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev"); + if (ret && ret != -EEXIST) + goto out_bootconf; + + ret = 0; + } + + add_fit_subimage_device(bdev_file, slot++, start_sect, nr_sects, true); + } + + if (!slot) + goto out_bootconf; + + dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n", + slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1, + (slot > 1)?"]":""); + + /* in case uImage.FIT is stored in a partition, map the remaining space */ + if (!bdev_read_only(bdev) && bdev_is_partition(bdev) && + (imgmaxsect + MIN_FREE_SECT) < dsectors) { + add_fit_subimage_device(bdev_file, slot++, imgmaxsect, + dsectors - imgmaxsect, false); + dev_info(dev, "mapped remaining space as /dev/fitrw\n"); + } + +out_bootconf: + kfree(bootconf); + kfree(fit); +out_blkdev: + if (!slot) + fput(bdev_file); + + return ret; +} + +static int fitblk_match_of_node(struct device *dev, const void *np) +{ + int ret; + + ret = device_match_of_node(dev, np); + if (ret) + return ret; + + /* + * To match ubiblock and mtdblock devices by their parent ubi + * or mtd device, also consider block device parent + */ + if (!dev->parent) + return 0; + + return device_match_of_node(dev->parent, np); +} + +static int fitblk_probe(struct platform_device *pdev) +{ + struct device *dev; + + dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node); + if (!dev) + return -EPROBE_DEFER; + + return parse_fit_on_dev(dev); +} + +static struct platform_driver fitblk_driver = { + .probe = fitblk_probe, + .driver = { + .name = "fitblk", + }, +}; + +static int __init fitblk_init(void) +{ + /* detect U-Boot firmware */ + ubootver = of_get_property(of_chosen, "u-boot,version", NULL); + if (!ubootver) + return 0; + + /* parse 'rootdisk' property phandle */ + rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0); + if (!rootdisk) + return 0; + + if (platform_driver_register(&fitblk_driver)) + return -ENODEV; + + refcount_set(&num_devs, 1); + pdev = platform_device_register_simple("fitblk", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} +device_initcall(fitblk_init); diff --git a/include/uapi/linux/fitblk.h b/include/uapi/linux/fitblk.h new file mode 100644 index 000000000000..a8f80a5e990a --- /dev/null +++ b/include/uapi/linux/fitblk.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_FITBLK_H +#define _UAPI_LINUX_FITBLK_H + +/* + * IOCTL commands --- we will commandeer 0x46 ('F') + */ +#define FITBLK_RELEASE 0x4600 + +#endif /* _UAPI_LINUX_FITBLK_H */ -- 2.51.0 From fa659019e6589fd4399c41dc7e4d4543fc7a54b3 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 12 Jun 2023 03:58:42 +0100 Subject: [PATCH 251/517] init: bypass device lookup for /dev/fit* rootfs Allow 'rootwait' as /dev/fit* can show up late if the underlaying device is probed late. Signed-off-by: Daniel Golle --- init/do_mounts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index cbb4237700aa..113708a9eb3d 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -465,7 +465,8 @@ static dev_t __init parse_root_device(char *root_device_name) int error; dev_t dev; - if (!strncmp(root_device_name, "mtd", 3) || + if (!strncmp(root_device_name, "fit", 3) || + !strncmp(root_device_name, "mtd", 3) || !strncmp(root_device_name, "ubi", 3)) return Root_Generic; if (strcmp(root_device_name, "/dev/nfs") == 0) -- 2.51.0 From 43633b0334e99dc60bb38af2f75632f17506046d Mon Sep 17 00:00:00 2001 From: "Alexandros C. Couloumbis" Date: Mon, 3 Nov 2025 15:49:52 +0100 Subject: [PATCH 252/517] fs: add jffs2/lzma support (not activated by default yet) lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2 Signed-off-by: Alexandros C. Couloumbis --- fs/jffs2/Kconfig | 9 + fs/jffs2/Makefile | 3 + fs/jffs2/compr.c | 6 + fs/jffs2/compr.h | 13 +- fs/jffs2/compr_lzma.c | 128 ++ fs/jffs2/super.c | 33 +- include/linux/lzma.h | 62 + include/linux/lzma/LzFind.h | 115 ++ include/linux/lzma/LzHash.h | 54 + include/linux/lzma/LzmaDec.h | 231 ++++ include/linux/lzma/LzmaEnc.h | 80 ++ include/linux/lzma/Types.h | 226 ++++ include/uapi/linux/jffs2.h | 1 + lib/Kconfig | 6 + lib/Makefile | 12 + lib/lzma/LzFind.c | 761 ++++++++++++ lib/lzma/LzmaDec.c | 999 +++++++++++++++ lib/lzma/LzmaEnc.c | 2271 ++++++++++++++++++++++++++++++++++ lib/lzma/Makefile | 7 + 19 files changed, 5011 insertions(+), 6 deletions(-) create mode 100644 fs/jffs2/compr_lzma.c create mode 100644 include/linux/lzma.h create mode 100644 include/linux/lzma/LzFind.h create mode 100644 include/linux/lzma/LzHash.h create mode 100644 include/linux/lzma/LzmaDec.h create mode 100644 include/linux/lzma/LzmaEnc.h create mode 100644 include/linux/lzma/Types.h create mode 100644 lib/lzma/LzFind.c create mode 100644 lib/lzma/LzmaDec.c create mode 100644 lib/lzma/LzmaEnc.c create mode 100644 lib/lzma/Makefile diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig index 560187d61562..9c7b1df2206d 100644 --- a/fs/jffs2/Kconfig +++ b/fs/jffs2/Kconfig @@ -136,6 +136,15 @@ config JFFS2_LZO This feature was added in July, 2007. Say 'N' if you need compatibility with older bootloaders or kernels. +config JFFS2_LZMA + bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS + select LZMA_COMPRESS + select LZMA_DECOMPRESS + depends on JFFS2_FS + default n + help + JFFS2 wrapper to the LZMA C SDK + config JFFS2_RTIME bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS depends on JFFS2_FS diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 5294969d5bf9..11a89b96e5f3 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o +jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o + +CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 764f19dec3f0..6b5e82b3f6c6 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -381,6 +381,9 @@ int __init jffs2_compressors_init(void) ret = jffs2_lzo_init(); if (ret) goto exit_dynrubin; + ret = jffs2_lzma_init(); + if (ret) + goto exit_lzo; /* Setting default compression mode */ @@ -402,6 +405,8 @@ int __init jffs2_compressors_init(void) #endif return 0; +exit_lzo: + jffs2_lzo_exit(); exit_dynrubin: jffs2_dynrubin_exit(); exit_runinmips: @@ -417,6 +422,7 @@ int __init jffs2_compressors_init(void) int jffs2_compressors_exit(void) { /* Unregistering compressors */ + jffs2_lzma_exit(); jffs2_lzo_exit(); jffs2_dynrubin_exit(); jffs2_rubinmips_exit(); diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 3716b6b7924c..00689727a1c5 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -29,9 +29,9 @@ #define JFFS2_DYNRUBIN_PRIORITY 20 #define JFFS2_LZARI_PRIORITY 30 #define JFFS2_RTIME_PRIORITY 50 -#define JFFS2_ZLIB_PRIORITY 60 -#define JFFS2_LZO_PRIORITY 80 - +#define JFFS2_LZMA_PRIORITY 70 +#define JFFS2_ZLIB_PRIORITY 80 +#define JFFS2_LZO_PRIORITY 90 #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ @@ -115,5 +115,12 @@ extern void jffs2_lzo_exit(void); static inline int jffs2_lzo_init(void) { return 0; } static inline void jffs2_lzo_exit(void) {} #endif +#ifdef CONFIG_JFFS2_LZMA +extern int jffs2_lzma_init(void); +extern void jffs2_lzma_exit(void); +#else +static inline int jffs2_lzma_init(void) { return 0; } +static inline void jffs2_lzma_exit(void) {} +#endif #endif /* __JFFS2_COMPR_H__ */ diff --git a/fs/jffs2/compr_lzma.c b/fs/jffs2/compr_lzma.c new file mode 100644 index 000000000000..ec0d9a6020de --- /dev/null +++ b/fs/jffs2/compr_lzma.c @@ -0,0 +1,128 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * JFFS2 wrapper to the LZMA C SDK + * + */ + +#include +#include "compr.h" + +#ifdef __KERNEL__ + static DEFINE_MUTEX(deflate_mutex); +#endif + +CLzmaEncHandle *p; +Byte propsEncoded[LZMA_PROPS_SIZE]; +SizeT propsSize = sizeof(propsEncoded); + +STATIC void lzma_free_workspace(void) +{ + LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); +} + +STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) +{ + if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) + { + PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); + return -ENOMEM; + } + + if (LzmaEnc_SetProps(p, props) != SZ_OK) + { + lzma_free_workspace(); + return -1; + } + + if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) + { + lzma_free_workspace(); + return -1; + } + + return 0; +} + +STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t *sourcelen, uint32_t *dstlen) +{ + SizeT compress_size = (SizeT)(*dstlen); + int ret; + + #ifdef __KERNEL__ + mutex_lock(&deflate_mutex); + #endif + + ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, + 0, NULL, &lzma_alloc, &lzma_alloc); + + #ifdef __KERNEL__ + mutex_unlock(&deflate_mutex); + #endif + + if (ret != SZ_OK) + return -1; + + *dstlen = (uint32_t)compress_size; + + return 0; +} + +STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, + uint32_t srclen, uint32_t destlen) +{ + int ret; + SizeT dl = (SizeT)destlen; + SizeT sl = (SizeT)srclen; + ELzmaStatus status; + + ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, + propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); + + if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) + return -1; + + return 0; +} + +static struct jffs2_compressor jffs2_lzma_comp = { + .priority = JFFS2_LZMA_PRIORITY, + .name = "lzma", + .compr = JFFS2_COMPR_LZMA, + .compress = &jffs2_lzma_compress, + .decompress = &jffs2_lzma_decompress, + .disabled = 0, +}; + +int INIT jffs2_lzma_init(void) +{ + int ret; + CLzmaEncProps props; + LzmaEncProps_Init(&props); + + props.dictSize = LZMA_BEST_DICT(0x2000); + props.level = LZMA_BEST_LEVEL; + props.lc = LZMA_BEST_LC; + props.lp = LZMA_BEST_LP; + props.pb = LZMA_BEST_PB; + props.fb = LZMA_BEST_FB; + + ret = lzma_alloc_workspace(&props); + if (ret < 0) + return ret; + + ret = jffs2_register_compressor(&jffs2_lzma_comp); + if (ret) + lzma_free_workspace(); + + return ret; +} + +void jffs2_lzma_exit(void) +{ + jffs2_unregister_compressor(&jffs2_lzma_comp); + lzma_free_workspace(); +} diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 4545f885c41e..ef4b26ff04c6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -376,14 +376,41 @@ static int __init init_jffs2_fs(void) BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); - pr_info("version 2.2." + pr_info("version 2.2" #ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" #endif #ifdef CONFIG_JFFS2_SUMMARY - " (SUMMARY) " + " (SUMMARY)" #endif - " © 2001-2006 Red Hat, Inc.\n"); +#ifdef CONFIG_JFFS2_ZLIB + " (ZLIB)" +#endif +#ifdef CONFIG_JFFS2_LZO + " (LZO)" +#endif +#ifdef CONFIG_JFFS2_LZMA + " (LZMA)" +#endif +#ifdef CONFIG_JFFS2_RTIME + " (RTIME)" +#endif +#ifdef CONFIG_JFFS2_RUBIN + " (RUBIN)" +#endif +#ifdef CONFIG_JFFS2_CMODE_NONE + " (CMODE_NONE)" +#endif +#ifdef CONFIG_JFFS2_CMODE_PRIORITY + " (CMODE_PRIORITY)" +#endif +#ifdef CONFIG_JFFS2_CMODE_SIZE + " (CMODE_SIZE)" +#endif +#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO + " (CMODE_FAVOURLZO)" +#endif + " (c) 2001-2006 Red Hat, Inc.\n"); jffs2_inode_cachep = kmem_cache_create("jffs2_i", sizeof(struct jffs2_inode_info), diff --git a/include/linux/lzma.h b/include/linux/lzma.h new file mode 100644 index 000000000000..492ad6c4405c --- /dev/null +++ b/include/linux/lzma.h @@ -0,0 +1,62 @@ +#ifndef __LZMA_H__ +#define __LZMA_H__ + +#ifdef __KERNEL__ + #include + #include + #include + #include + #include + #define LZMA_MALLOC vmalloc + #define LZMA_FREE vfree + #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) + #define INIT __init + #define STATIC static +#else + #include + #include + #include + #include + #include + #include + #include + #include + #ifndef PAGE_SIZE + extern int page_size; + #define PAGE_SIZE page_size + #endif + #define LZMA_MALLOC malloc + #define LZMA_FREE free + #define PRINT_ERROR(msg) fprintf(stderr, msg) + #define INIT + #define STATIC +#endif + +#include "lzma/LzmaDec.h" +#include "lzma/LzmaEnc.h" + +#define LZMA_BEST_LEVEL (9) +#define LZMA_BEST_LC (0) +#define LZMA_BEST_LP (0) +#define LZMA_BEST_PB (0) +#define LZMA_BEST_FB (273) + +#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) + +static void *p_lzma_malloc(void *p, size_t size) +{ + if (size == 0) + return NULL; + + return LZMA_MALLOC(size); +} + +static void p_lzma_free(void *p, void *address) +{ + if (address != NULL) + LZMA_FREE(address); +} + +static ISzAlloc lzma_alloc = { .Alloc = p_lzma_malloc, .Free = p_lzma_free }; + +#endif diff --git a/include/linux/lzma/LzFind.h b/include/linux/lzma/LzFind.h new file mode 100644 index 000000000000..010c4b92ba33 --- /dev/null +++ b/include/linux/lzma/LzFind.h @@ -0,0 +1,115 @@ +/* LzFind.h -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_H +#define __LZ_FIND_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + int streamEndWasReached; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + int directInput; + size_t directInputRem; + int btMode; + int bigHash; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + UInt32 numSons; + SRes result; + UInt32 crc[256]; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) +#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetIndexByte_Func GetIndexByte; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init(CMatchFinder *p); +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/linux/lzma/LzHash.h b/include/linux/lzma/LzHash.h new file mode 100644 index 000000000000..f3e89966cc70 --- /dev/null +++ b/include/linux/lzma/LzHash.h @@ -0,0 +1,54 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZ_HASH_H +#define __LZ_HASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ + hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ + hash4Value &= (kHash4Size - 1); } + +/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/include/linux/lzma/LzmaDec.h b/include/linux/lzma/LzmaDec.h new file mode 100644 index 000000000000..7927acd0d4eb --- /dev/null +++ b/include/linux/lzma/LzmaDec.h @@ -0,0 +1,231 @@ +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/linux/lzma/LzmaEnc.h b/include/linux/lzma/LzmaEnc.h new file mode 100644 index 000000000000..200d60eb83cd --- /dev/null +++ b/include/linux/lzma/LzmaEnc.h @@ -0,0 +1,80 @@ +/* LzmaEnc.h -- LZMA Encoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_ENC_H +#define __LZMA_ENC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (1 << 30) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc_* functions can return the following exit codes: +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - Write callback error. + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +/* ---------- One Call Interface ---------- */ + +/* LzmaEncode +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/linux/lzma/Types.h b/include/linux/lzma/Types.h new file mode 100644 index 000000000000..4751acde0722 --- /dev/null +++ b/include/linux/lzma/Types.h @@ -0,0 +1,226 @@ +/* Types.h -- Basic types +2009-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +EXTERN_C_END + +#endif diff --git a/include/uapi/linux/jffs2.h b/include/uapi/linux/jffs2.h index 637ee4a793cf..11aeaa4e8520 100644 --- a/include/uapi/linux/jffs2.h +++ b/include/uapi/linux/jffs2.h @@ -46,6 +46,7 @@ #define JFFS2_COMPR_DYNRUBIN 0x05 #define JFFS2_COMPR_ZLIB 0x06 #define JFFS2_COMPR_LZO 0x07 +#define JFFS2_COMPR_LZMA 0x08 /* Compatibility flags. */ #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ #define JFFS2_NODE_ACCURATE 0x2000 diff --git a/lib/Kconfig b/lib/Kconfig index b893c9288c14..e9088bd10a6c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -353,6 +353,12 @@ config ZSTD_DECOMPRESS source "lib/xz/Kconfig" +config LZMA_COMPRESS + tristate + +config LZMA_DECOMPRESS + tristate + # # These all provide a common interface (hence the apparent duplication with # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) diff --git a/lib/Makefile b/lib/Makefile index fc878e716825..460d99a479be 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -126,6 +126,16 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif +ifdef CONFIG_JFFS2_ZLIB + CONFIG_ZLIB_INFLATE:=y + CONFIG_ZLIB_DEFLATE:=y +endif + +ifdef CONFIG_JFFS2_LZMA + CONFIG_LZMA_DECOMPRESS:=y + CONFIG_LZMA_COMPRESS:=y +endif + obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) @@ -185,6 +195,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ +obj-$(CONFIG_LZMA_COMPRESS) += lzma/ +obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o diff --git a/lib/lzma/LzFind.c b/lib/lzma/LzFind.c new file mode 100644 index 000000000000..a02621a1f8f5 --- /dev/null +++ b/lib/lzma/LzFind.c @@ -0,0 +1,761 @@ +/* LzFind.c -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + +#include + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)3 << 30) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + if (!p->directInput) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (p->bufferBase == 0 || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != 0); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->directInputRem -= curSize; + p->streamPos += curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + p->result = p->stream->Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + UInt32 i; + p->bufferBase = 0; + p->directInput = 0; + p->hash = 0; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = i; + int j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hash); + p->hash = 0; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return 0; + return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc) +{ + UInt32 sizeReserv; + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + sizeReserv = historySize >> 1; + if (historySize > ((UInt32)2 << 30)) + sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = historySize + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + UInt32 prevSize = p->hashSizeSum + p->numSons; + UInt32 newSize; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); + newSize = p->hashSizeSum + p->numSons; + if (p->hash != 0 && prevSize == newSize) + return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->hash = AllocRefs(newSize, alloc); + if (p->hash != 0) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + if (limit2 < limit) + limit = limit2; + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + +void MatchFinder_Init(CMatchFinder *p) +{ + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) + p->hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); +} + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +{ + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_ReduceOffsets(p, subValue); +} + +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + +static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } +} + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, delta2, maxLen, offset; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + delta2 = p->pos - p->hash[hash2Value]; + curMatch = p->hash[kFix3HashSize + hashValue]; + + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + + + maxLen = 2; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[0] = maxLen; + distances[1] = delta2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value; + SKIP_HEADER(3) + HASH3_CALC; + curMatch = p->hash[kFix3HashSize + hashValue]; + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = p->pos; + p->hash[kFix4HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } +} diff --git a/lib/lzma/LzmaDec.c b/lib/lzma/LzmaDec.c new file mode 100644 index 000000000000..7bc3ce91a6a0 --- /dev/null +++ b/lib/lzma/LzmaDec.c @@ -0,0 +1,999 @@ +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/lib/lzma/LzmaEnc.c b/lib/lzma/LzmaEnc.c new file mode 100644 index 000000000000..b81f0863f7d8 --- /dev/null +++ b/lib/lzma/LzmaEnc.c @@ -0,0 +1,2271 @@ +/* LzmaEnc.c -- LZMA Encoder +2009-11-24 : Igor Pavlov : Public domain */ + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +/* disable MT */ +#define _7ZIP_ST + +#include "LzFind.h" +#ifndef _7ZIP_ST +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static int ttt = 0; +#endif + +#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) + +#define kBlockSize (9 << 10) +#define kUnpackBlockSize (1 << 18) +#define kMatchArraySize (1 << 21) +#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) + +#define kNumMaxDirectBits (31) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) + p->numThreads = + #ifndef _7ZIP_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +/* #define LZMA_LOG_BSR */ +/* Define it for Intel's CPU */ + + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 30 + +#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +UInt32 GetPosSlot1(UInt32 pos) +{ + UInt32 res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +static void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + int c = 2, slotFast; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + + for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + { + UInt32 k = (1 << ((slotFast >> 1) - 1)); + UInt32 j; + for (j = 0; j < k; j++, c++) + g_FastPos[c] = (Byte)slotFast; + } +} + +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef unsigned CState; + +typedef struct +{ + UInt32 price; + + CState state; + int prev1IsChar; + int prev2; + + UInt32 posPrev2; + UInt32 backPrev2; + + UInt32 posPrev; + UInt32 backPrev; + UInt32 backs[LZMA_NUM_REPS]; +} COptimal; + +#define kNumOpts (1 << 12) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) + +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + +typedef struct +{ + CLzmaProb choice; + CLzmaProb choice2; + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; + CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + +typedef struct +{ + CLenEnc p; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + UInt32 tableSize; + UInt32 counters[LZMA_NUM_PB_STATES_MAX]; +} CLenPriceEnc; + +typedef struct +{ + UInt32 range; + Byte cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + +typedef struct +{ + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; +} CSaveState; + +typedef struct +{ + IMatchFinder matchFinder; + void *matchFinderObj; + + #ifndef _7ZIP_ST + Bool mtMode; + CMatchFinderMt matchFinderMt; + #endif + + CMatchFinder matchFinderBase; + + #ifndef _7ZIP_ST + Byte pad[128]; + #endif + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + COptimal opt[kNumOpts]; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + UInt32 alignPrices[kAlignTableSize]; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + unsigned lclp; + + Bool fastMode; + + CRangeEnc rc; + + Bool writeEndMark; + UInt64 nowPos64; + UInt32 matchPriceCount; + Bool finished; + Bool multiThread; + + SRes result; + UInt32 dictSize; + UInt32 matchFinderCycles; + + int needInit; + + CSaveState saveState; +} CLzmaEnc; + +/*void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +}*/ + +/*void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +}*/ + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || + props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) + return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; + p->matchFinderCycles = props.mc; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + p->matchFinderBase.btMode = props.btMode; + { + UInt32 numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifndef _7ZIP_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + +static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsCharState(s) ((s) < 7) + +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = 0; + p->bufBase = 0; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) +static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) +{ + if (p->bufBase == 0) + { + p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); + if (p->bufBase == 0) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->low = 0; + p->range = 0xFFFFFFFF; + p->cacheSize = 1; + p->cache = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != p->outStream->Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + { + Byte temp = p->cache; + do + { + Byte *buf = p->buf; + *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + temp = 0xFF; + } + while (--p->cacheSize != 0); + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +{ + do + { + p->range >>= 1; + p->low += p->range & (0 - ((value >> --numBits) & 1)); + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } + } + while (numBits != 0); +} + +static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) +{ + UInt32 ttt = *prob; + UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; + if (symbol == 0) + { + p->range = newBound; + ttt += (kBitModelTotal - ttt) >> kNumMoveBits; + } + else + { + p->low += newBound; + p->range -= newBound; + ttt -= ttt >> kNumMoveBits; + } + *prob = (CLzmaProb)ttt; + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) +{ + symbol |= 0x100; + do + { + RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) +{ + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); +} + +static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +{ + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) + { + const int kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = i; + UInt32 bitCount = 0; + int j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + } +} + + +#define GET_PRICE(prob, symbol) \ + p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, symbol) \ + ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= 0x100; + do + { + price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); + return price; +} + +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); + return price; +} + + +static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0;) + { + UInt32 bit; + i--; + bit = (symbol >> i) & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + } +} + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = 0; i < numBitLevels; i++) + { + UInt32 bit = symbol & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + symbol >>= 1; + } +} + +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= (1 << numBitLevels); + while (symbol != 1) + { + price += GET_PRICEa(probs[symbol >> 1], symbol & 1); + symbol >>= 1; + } + return price; +} + +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) | bit; + } + return price; +} + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + p->choice = p->choice2 = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) + p->mid[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) +{ + if (symbol < kLenNumLowSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice, 0); + RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice, 1); + if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice2, 0); + RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice2, 1); + RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); + } + } +} + +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +{ + UInt32 a0 = GET_PRICE_0a(p->choice); + UInt32 a1 = GET_PRICE_1a(p->choice); + UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); + UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); + UInt32 i = 0; + for (i = 0; i < kLenNumLowSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); + } + for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); + } + for (; i < numSymbols; i++) + prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); +} + +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +{ + LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); + p->counters[posState] = p->tableSize; +} + +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +{ + UInt32 posState; + for (posState = 0; posState < numPosStates; posState++) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +{ + LenEnc_Encode(&p->p, rc, symbol, posState); + if (updatePrice) + if (--p->counters[posState] == 0) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + + + + +static void MovePos(CLzmaEnc *p, UInt32 num) +{ + #ifdef SHOW_STAT + ttt += num; + printf("\n MovePos %d", num); + #endif + if (num != 0) + { + p->additionalOffset += num; + p->matchFinder.Skip(p->matchFinderObj, num); + } +} + +static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) +{ + UInt32 lenRes = 0, numPairs; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT + printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); + ttt++; + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + } + #endif + if (numPairs > 0) + { + lenRes = p->matches[numPairs - 2]; + if (lenRes == p->numFastBytes) + { + const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + UInt32 distance = p->matches[numPairs - 1] + 1; + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *pby2 = pby - distance; + for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + } + } + } + p->additionalOffset++; + *numDistancePairsRes = numPairs; + return lenRes; +} + + +#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; +#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; +#define IsShortRep(p) ((p)->backPrev == 0) + +static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) +{ + return + GET_PRICE_0(p->isRepG0[state]) + + GET_PRICE_0(p->isRep0Long[state][posState]); +} + +static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) +{ + UInt32 price; + if (repIndex == 0) + { + price = GET_PRICE_0(p->isRepG0[state]); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(p->isRepG0[state]); + if (repIndex == 1) + price += GET_PRICE_0(p->isRepG1[state]); + else + { + price += GET_PRICE_1(p->isRepG1[state]); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + +static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) +{ + return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + + GetPureRepPrice(p, repIndex, state, posState); +} + +static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) +{ + UInt32 posMem = p->opt[cur].posPrev; + UInt32 backMem = p->opt[cur].backPrev; + p->optimumEndIndex = cur; + do + { + if (p->opt[cur].prev1IsChar) + { + MakeAsChar(&p->opt[posMem]) + p->opt[posMem].posPrev = posMem - 1; + if (p->opt[cur].prev2) + { + p->opt[posMem - 1].prev1IsChar = False; + p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; + p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; + } + } + { + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = p->opt[posPrev].backPrev; + posMem = p->opt[posPrev].posPrev; + + p->opt[posPrev].backPrev = backCur; + p->opt[posPrev].posPrev = cur; + cur = posPrev; + } + } + while (cur != 0); + *backRes = p->opt[0].backPrev; + p->optimumCurrentIndex = p->opt[0].posPrev; + return p->optimumCurrentIndex; +} + +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) + +static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; + UInt32 matchPrice, repMatchPrice, normalMatchPrice; + UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; + UInt32 *matches; + const Byte *data; + Byte curByte, matchByte; + if (p->optimumEndIndex != p->optimumCurrentIndex) + { + const COptimal *opt = &p->opt[p->optimumCurrentIndex]; + UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; + *backRes = opt->backPrev; + p->optimumCurrentIndex = opt->posPrev; + return lenRes; + } + p->optimumCurrentIndex = p->optimumEndIndex = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + *backRes = (UInt32)(-1); + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 lenTest; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - (reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + repLens[i] = lenTest; + if (lenTest > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= p->numFastBytes) + { + UInt32 lenRes; + *backRes = repMaxIndex; + lenRes = repLens[repMaxIndex]; + MovePos(p, lenRes - 1); + return lenRes; + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) + { + *backRes = (UInt32)-1; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsCharState(p->state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAsChar(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + if (matchByte == curByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAsShortRep(&p->opt[1]); + } + } + lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); + + if (lenEnd < 2) + { + *backRes = p->opt[1].backPrev; + return 1; + } + + p->opt[1].posPrev = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + p->opt[0].backs[i] = reps[i]; + + len = lenEnd; + do + p->opt[len--].price = kInfinityPrice; + while (len >= 2); + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; + COptimal *opt = &p->opt[repLen]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = i; + opt->prev1IsChar = False; + } + } + while (--repLen >= 2); + } + + normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= mainLen) + { + UInt32 offs = 0; + while (len > matches[offs]) + offs += 2; + for (; ; len++) + { + COptimal *opt; + UInt32 distance = matches[offs + 1]; + + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(len); + if (distance < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][distance]; + else + { + UInt32 slot; + GetPosSlot2(distance, slot); + curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; + } + opt = &p->opt[len]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = distance + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + + cur = 0; + + #ifdef SHOW_STAT2 + if (position >= 0) + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= lenEnd; i++) + printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + } + #endif + + for (;;) + { + UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; + UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; + Bool nextIsChar; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt; + COptimal *nextOpt; + + cur++; + if (cur == lenEnd) + return Backward(p, backRes, cur); + + newLen = ReadMatchDistances(p, &numPairs); + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLength = newLen; + return Backward(p, backRes, cur); + } + position++; + curOpt = &p->opt[cur]; + posPrev = curOpt->posPrev; + if (curOpt->prev1IsChar) + { + posPrev--; + if (curOpt->prev2) + { + state = p->opt[curOpt->posPrev2].state; + if (curOpt->backPrev2 < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + else + state = p->opt[posPrev].state; + state = kLiteralNextStates[state]; + } + else + state = p->opt[posPrev].state; + if (posPrev == cur - 1) + { + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + UInt32 pos; + const COptimal *prevOpt; + if (curOpt->prev1IsChar && curOpt->prev2) + { + posPrev = curOpt->posPrev2; + pos = curOpt->backPrev2; + state = kRepNextStates[state]; + } + else + { + pos = curOpt->backPrev; + if (pos < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + prevOpt = &p->opt[posPrev]; + if (pos < LZMA_NUM_REPS) + { + UInt32 i; + reps[0] = prevOpt->backs[pos]; + for (i = 1; i <= pos; i++) + reps[i] = prevOpt->backs[i - 1]; + for (; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i]; + } + else + { + UInt32 i; + reps[0] = (pos - LZMA_NUM_REPS); + for (i = 1; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i - 1]; + } + } + curOpt->state = (CState)state; + + curOpt->backs[0] = reps[0]; + curOpt->backs[1] = reps[1]; + curOpt->backs[2] = reps[2]; + curOpt->backs[3] = reps[3]; + + curPrice = curOpt->price; + nextIsChar = False; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + posState = (position & p->pbMask); + + curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + curAnd1Price += + (!IsCharState(state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + nextOpt = &p->opt[cur + 1]; + + if (curAnd1Price < nextOpt->price) + { + nextOpt->price = curAnd1Price; + nextOpt->posPrev = cur; + MakeAsChar(nextOpt); + nextIsChar = True; + } + + matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); + if (shortRepPrice <= nextOpt->price) + { + nextOpt->price = shortRepPrice; + nextOpt->posPrev = cur; + MakeAsShortRep(nextOpt); + nextIsChar = True; + } + } + numAvailFull = p->numAvail; + { + UInt32 temp = kNumOpts - 1 - cur; + if (temp < numAvailFull) + numAvailFull = temp; + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + if (!nextIsChar && matchByte != curByte) /* speed optimization */ + { + /* try Literal + rep0 */ + UInt32 temp; + UInt32 lenTest2; + const Byte *data2 = data - (reps[0] + 1); + UInt32 limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + + for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); + lenTest2 = temp - 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kLiteralNextStates[state]; + UInt32 posStateNext = (position + 1) & p->pbMask; + UInt32 nextRepMatchPrice = curAnd1Price + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = False; + } + } + } + } + + startLen = 2; /* speed optimization */ + { + UInt32 repIndex; + for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) + { + UInt32 lenTest; + UInt32 lenTestTemp; + UInt32 price; + const Byte *data2 = data - (reps[repIndex] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + while (lenEnd < cur + lenTest) + p->opt[++lenEnd].price = kInfinityPrice; + lenTestTemp = lenTest; + price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; + COptimal *opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = repIndex; + opt->prev1IsChar = False; + } + } + while (--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + /* if (_maxMode) */ + { + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kRepNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = + price + p->repLenEnc.prices[posState][lenTest - 2] + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (position + lenTest + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + lenTest + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = repIndex; + } + } + } + } + } + } + /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = newLen; + numPairs += 2; + } + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 offs, curBack, posSlot; + UInt32 lenTest; + while (lenEnd < cur + newLen) + p->opt[++lenEnd].price = kInfinityPrice; + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + curBack = matches[offs + 1]; + GetPosSlot2(curBack, posSlot); + for (lenTest = /*2*/ startLen; ; lenTest++) + { + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(lenTest); + COptimal *opt; + if (curBack < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; + else + curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; + + opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = curBack + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + + if (/*_maxMode && */lenTest == matches[offs]) + { + /* Try Match + Literal + Rep0 */ + const Byte *data2 = data - (curBack + 1); + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kMatchNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (posStateNext + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 offset = cur + lenTest + 1 + lenTest2; + UInt32 curAndLenPrice; + COptimal *opt; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = curBack + LZMA_NUM_REPS; + } + } + } + offs += 2; + if (offs == numPairs) + break; + curBack = matches[offs + 1]; + if (curBack >= kNumFullDistances) + GetPosSlot2(curBack, posSlot); + } + } + } + } +} + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + +static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; + const Byte *data; + const UInt32 *matches; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + *backRes = (UInt32)-1; + if (numAvail < 2) + return 1; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + repLen = repIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++); + if (len >= p->numFastBytes) + { + *backRes = i; + MovePos(p, len - 1); + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + + mainDist = 0; /* for GCC */ + if (mainLen >= 2) + { + mainDist = matches[numPairs - 1]; + while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) + { + if (!ChangePair(matches[numPairs - 3], mainDist)) + break; + numPairs -= 2; + mainLen = matches[numPairs - 2]; + mainDist = matches[numPairs - 1]; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2 && ( + (repLen + 1 >= mainLen) || + (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || + (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) + { + *backRes = repIndex; + MovePos(p, repLen - 1); + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); + if (p->longestMatchLength >= 2) + { + UInt32 newDistance = matches[p->numPairs - 1]; + if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || + (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || + (p->longestMatchLength > mainLen + 1) || + (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) + return 1; + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len, limit; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2; len < limit && data[len] == data2[len]; len++); + if (len >= limit) + return 1; + } + *backRes = mainDist + LZMA_NUM_REPS; + MovePos(p, mainLen - 2); + return mainLen; +} + +static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) +{ + UInt32 len; + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + len = LZMA_MATCH_LEN_MIN; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); + RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); +} + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + +static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + +static void FillAlignPrices(CLzmaEnc *p) +{ + UInt32 i; + for (i = 0; i < kAlignTableSize; i++) + p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + p->alignPriceCount = 0; +} + +static void FillDistancesPrices(CLzmaEnc *p) +{ + UInt32 tempPrices[kNumFullDistances]; + UInt32 i, lenToPosState; + for (i = kStartPosModelIndex; i < kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot1(i); + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); + } + + for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; + UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; + for (posSlot = 0; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); + for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + + { + UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; + UInt32 i; + for (i = 0; i < kStartPosModelIndex; i++) + distancesPrices[i] = posSlotPrices[i]; + for (; i < kNumFullDistances; i++) + distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; + } + } + p->matchPriceCount = 0; +} + +static void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) +{ + void *p; + p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); + if (p != 0) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + alloc->Free(alloc, p); +} + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + UInt32 numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); + p->state = kLiteralNextStates[p->state]; + curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + for (;;) + { + UInt32 pos, len, posState; + + if (p->fastMode) + len = GetOptimumFast(p, &pos); + else + len = GetOptimum(p, nowPos32, &pos); + + #ifdef SHOW_STAT2 + printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + #endif + + posState = nowPos32 & p->pbMask; + if (len == 1 && pos == (UInt32)-1) + { + Byte curByte; + CLzmaProb *probs; + const Byte *data; + + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + curByte = *data; + probs = LIT_PROBS(nowPos32, *(data - 1)); + if (IsCharState(p->state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); + p->state = kLiteralNextStates[p->state]; + } + else + { + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + if (pos < LZMA_NUM_REPS) + { + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); + if (pos == 0) + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); + RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); + } + else + { + UInt32 distance = p->reps[pos]; + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); + if (pos == 1) + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); + else + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); + if (pos == 3) + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = distance; + } + if (len == 1) + p->state = kShortRepNextStates[p->state]; + else + { + LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + p->state = kRepNextStates[p->state]; + } + } + else + { + UInt32 posSlot; + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + pos -= LZMA_NUM_REPS; + GetPosSlot(pos, posSlot); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); + + if (posSlot >= kStartPosModelIndex) + { + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - base; + + if (posSlot < kEndPosModelIndex) + RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); + else + { + RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + p->alignPriceCount++; + } + } + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = pos; + p->matchPriceCount++; + } + } + p->additionalOffset -= len; + nowPos32 += len; + if (p->additionalOffset == 0) + { + UInt32 processed; + if (!p->fastMode) + { + if (p->matchPriceCount >= (1 << 7)) + FillDistancesPrices(p); + if (p->alignPriceCount >= kAlignTableSize) + FillAlignPrices(p); + } + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + if (useLimits) + { + if (processed + kNumOpts + 300 >= maxUnpackSize || + RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) + break; + } + else if (processed >= (1 << 15)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 beforeSize = kNumOpts; + Bool btMode; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + btMode = (p->matchFinderBase.btMode != 0); + #ifndef _7ZIP_ST + p->mtMode = (p->multiThread && !p->fastMode && btMode); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + if (p->litProbs == 0 || p->saveState.litProbs == 0) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifndef _7ZIP_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); + p->matchFinderObj = &p->matchFinderMt; + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + return SZ_OK; +} + +static void LzmaEnc_Init(CLzmaEnc *p) +{ + UInt32 i; + p->state = 0; + for (i = 0 ; i < LZMA_NUM_REPS; i++) + p->reps[i] = 0; + + RangeEnc_Init(&p->rc); + + + for (i = 0; i < kNumStates; i++) + { + UInt32 j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + UInt32 num = 0x300 << (p->lp + p->lc); + for (i = 0; i < num; i++) + p->litProbs[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + UInt32 j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + p->posEncoders[i] = kProbInitValue; + } + + LenEnc_Init(&p->lenEnc.p); + LenEnc_Init(&p->repLenEnc.p); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + p->optimumEndIndex = 0; + p->optimumCurrentIndex = 0; + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = (1 << p->lp) - 1; +} + +static void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 i; + for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +/*SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +}*/ + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; + p->matchFinderBase.bufferBase = (Byte *)src; + p->matchFinderBase.directInputRem = srcLen; +} + +static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->needInit = 1; + + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + pp = pp; + #endif +} + +typedef struct +{ + ISeqOutStream funcTable; + Byte *data; + SizeT rem; + Bool overflow; +} CSeqOutStreamBuf; + +static size_t MyWrite(void *pp, const void *data, size_t size) +{ + CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +/*UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +}*/ + +/*const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +}*/ + +/* SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CSeqOutStreamBuf outStream; + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.funcTable; + + res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +}*/ + +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; + + #ifndef _7ZIP_ST + Byte allocaDummy[0x300]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, False, 0, 0); + if (res != SZ_OK || p->finished != 0) + break; + if (progress != 0) + { + res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + LzmaEnc_Finish(p); + return res; +} + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); + return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +} + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + int i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) + { + dictSize = (2 << i); + break; + } + if (dictSize <= ((UInt32)3 << i)) + { + dictSize = (3 << i); + break; + } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CSeqOutStreamBuf outStream; + + LzmaEnc_SetInputBuf(p, src, srcLen); + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + + p->rc.outStream = &outStream.funcTable; + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + res = LzmaEnc_Encode2(p, progress); + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (p == 0) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/lib/lzma/Makefile b/lib/lzma/Makefile new file mode 100644 index 000000000000..02e799c99381 --- /dev/null +++ b/lib/lzma/Makefile @@ -0,0 +1,7 @@ +lzma_compress-objs := LzFind.o LzmaEnc.o +lzma_decompress-objs := LzmaDec.o + +obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o +obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o + +EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h -- 2.51.0 From 0749420ddd81391f698d65098ee2e56e19f4cf16 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:52 +0100 Subject: [PATCH 253/517] fs: jffs2: EOF marker Signed-off-by: Felix Fietkau --- fs/jffs2/build.c | 10 ++++++++++ fs/jffs2/scan.c | 21 +++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 6ae9d6fefb86..d21a7ecec6ee 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) dbg_fsbuild("scanned flash completely\n"); jffs2_dbg_dump_block_lists_nolock(c); + if (c->flags & (1 << 7)) { + printk("%s(): unlocking the mtd device... ", __func__); + mtd_unlock(c->mtd, 0, c->mtd->size); + printk("done.\n"); + + printk("%s(): erasing all blocks after the end marker... ", __func__); + jffs2_erase_pending_blocks(c, -1); + printk("done.\n"); + } + dbg_fsbuild("pass 1 starting\n"); c->flags |= JFFS2_SB_FLAG_BUILDING; /* Now scan the directory tree, increasing nlink according to every dirent found. */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 62879c218d4b..cb928d2414ed 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) /* reset summary info for next eraseblock scan */ jffs2_sum_reset_collected(s); - ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), - buf_size, s); + if (c->flags & (1 << 7)) { + if (mtd_block_isbad(c->mtd, jeb->offset)) + ret = BLK_STATE_BADBLOCK; + else + ret = BLK_STATE_ALLFF; + } else + ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), + buf_size, s); if (ret < 0) goto out; @@ -569,6 +575,17 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo return err; } + if ((buf[0] == 0xde) && + (buf[1] == 0xad) && + (buf[2] == 0xc0) && + (buf[3] == 0xde)) { + /* end of filesystem. erase everything after this point */ + printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); + c->flags |= (1 << 7); + + return BLK_STATE_ALLFF; + } + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ ofs = 0; max_ofs = EMPTY_SCAN_SIZE(c->sector_size); -- 2.51.0 From a62f2a7232e826e000cc8364899b074427f3ca34 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:52 +0100 Subject: [PATCH 254/517] netfilter: add support for flushing conntrack via /proc lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314 Signed-off-by: Felix Fietkau --- net/netfilter/nf_conntrack_standalone.c | 58 ++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 3ea60ff7a6a4..39fd99016360 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #ifdef CONFIG_SYSCTL #include @@ -458,6 +459,58 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v) return 0; } +struct kill_request { + u16 family; + union nf_inet_addr addr; +}; + +static int kill_matching(struct nf_conn *i, void *data) +{ + struct kill_request *kr = data; + struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; + + if (!kr->family) + return 1; + + if (t1->src.l3num != kr->family) + return 0; + + return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || + nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || + nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || + nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); +} + +static int ct_file_write(struct file *file, char *buf, size_t count) +{ + struct seq_file *seq = file->private_data; + struct nf_ct_iter_data iter_data; + struct kill_request kr = { }; + + if (count == 0) + return 0; + + if (count >= INET6_ADDRSTRLEN) + count = INET6_ADDRSTRLEN - 1; + + if (strnchr(buf, count, ':')) { + kr.family = AF_INET6; + if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL)) + return -EINVAL; + } else if (strnchr(buf, count, '.')) { + kr.family = AF_INET; + if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL)) + return -EINVAL; + } + + iter_data.net = seq_file_net(seq); + iter_data.data = &kr; + nf_ct_iterate_cleanup_net(kill_matching, &iter_data); + + return 0; +} + static const struct seq_operations ct_cpu_seq_ops = { .start = ct_cpu_seq_start, .next = ct_cpu_seq_next, @@ -471,8 +524,9 @@ static int nf_conntrack_standalone_init_proc(struct net *net) kuid_t root_uid; kgid_t root_gid; - pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops, - sizeof(struct ct_iter_state)); + pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net, + &ct_seq_ops, &ct_file_write, + sizeof(struct ct_iter_state), NULL); if (!pde) goto out_nf_conntrack; -- 2.51.0 From 92d7c8f5e0513a7b12c993c38792ba7edc72dee9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:53 +0100 Subject: [PATCH 255/517] kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0 Signed-off-by: Felix Fietkau --- include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 + net/ipv4/netfilter/ip_tables.c | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter_ipv4/ip_tables.h b/include/uapi/linux/netfilter_ipv4/ip_tables.h index 1485df28b239..250350c37ef5 100644 --- a/include/uapi/linux/netfilter_ipv4/ip_tables.h +++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h @@ -89,6 +89,7 @@ struct ipt_ip { #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ +#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ /* Values for "inv" field in struct ipt_ip. */ #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 3d101613f27f..43ee82554011 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -48,6 +48,9 @@ ip_packet_match(const struct iphdr *ip, { unsigned long ret; + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + if (NF_INVF(ipinfo, IPT_INV_SRCIP, (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || NF_INVF(ipinfo, IPT_INV_DSTIP, @@ -78,6 +81,29 @@ ip_packet_match(const struct iphdr *ip, return true; } +static void +ip_checkdefault(struct ipt_ip *ip) +{ + static const char iface_mask[IFNAMSIZ] = {}; + + if (ip->invflags || ip->flags & IPT_F_FRAG) + return; + + if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) + return; + + if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) + return; + + if (ip->smsk.s_addr || ip->dmsk.s_addr) + return; + + if (ip->proto) + return; + + ip->flags |= IPT_F_NO_DEF_MATCH; +} + static bool ip_checkentry(const struct ipt_ip *ip) { @@ -523,6 +549,8 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; + ip_checkdefault(&e->ip); + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) return -ENOMEM; @@ -817,6 +845,7 @@ copy_entries_to_user(unsigned int total_size, const struct xt_table_info *private = table->private; int ret = 0; const void *loc_cpu_entry; + u8 flags; counters = alloc_counters(table); if (IS_ERR(counters)) @@ -844,6 +873,14 @@ copy_entries_to_user(unsigned int total_size, goto free_counters; } + flags = e->ip.flags & IPT_F_MASK; + if (copy_to_user(userptr + off + + offsetof(struct ipt_entry, ip.flags), + &flags, sizeof(flags)) != 0) { + ret = -EFAULT; + goto free_counters; + } + for (i = sizeof(struct ipt_entry); i < e->target_offset; i += m->u.match_size) { @@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, compat_uint_t origsize; const struct xt_entry_match *ematch; int ret = 0; + u8 flags = e->ip.flags & IPT_F_MASK; origsize = *size; ce = *dstptr; if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || copy_to_user(&ce->counters, &counters[i], - sizeof(counters[i])) != 0) + sizeof(counters[i])) != 0 || + copy_to_user(&ce->ip.flags, &flags, + sizeof(flags)) != 0) return -EFAULT; *dstptr += sizeof(struct compat_ipt_entry); -- 2.51.0 From 12cf7d07371762ca70888fb3b9511a3250211a88 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:53 +0100 Subject: [PATCH 256/517] netfilter: match bypass default table Signed-off-by: Felix Fietkau --- net/ipv4/netfilter/ip_tables.c | 69 ++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 43ee82554011..8325e81b9827 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -244,6 +244,33 @@ struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) return (void *)entry + entry->next_offset; } +static bool +ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) +{ + struct xt_entry_target *t; + struct xt_standard_target *st; + + if (e->target_offset != sizeof(struct ipt_entry)) + return false; + + if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) + return false; + + t = ipt_get_target(e); + if (t->u.kernel.target->target) + return false; + + st = (struct xt_standard_target *) t; + if (st->verdict == XT_RETURN) + return false; + + if (st->verdict >= 0) + return false; + + *verdict = (unsigned)(-st->verdict) - 1; + return true; +} + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int ipt_do_table(void *priv, @@ -265,27 +292,28 @@ ipt_do_table(void *priv, unsigned int addend; /* Initialization */ + WARN_ON(!(table->valid_hooks & (1 << hook))); + local_bh_disable(); + private = READ_ONCE(table->private); /* Address dependency. */ + cpu = smp_processor_id(); + table_base = private->entries; + + e = get_entry(table_base, private->hook_entry[hook]); + if (ipt_handle_default_rule(e, &verdict)) { + struct xt_counters *counter; + + counter = xt_get_this_cpu_counter(&e->counters); + ADD_COUNTER(*counter, skb->len, 1); + local_bh_enable(); + return verdict; + } + stackidx = 0; ip = ip_hdr(skb); indev = state->in ? state->in->name : nulldevname; outdev = state->out ? state->out->name : nulldevname; - /* We handle fragments by dealing with the first fragment as - * if it was a normal packet. All other fragments are treated - * normally, except that they will NEVER match rules that ask - * things we don't know, ie. tcp syn flag or ports). If the - * rule is also a fragment-specific rule, non-fragments won't - * match it. */ - acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; - acpar.thoff = ip_hdrlen(skb); - acpar.hotdrop = false; - acpar.state = state; - WARN_ON(!(table->valid_hooks & (1 << hook))); - local_bh_disable(); addend = xt_write_recseq_begin(); - private = READ_ONCE(table->private); /* Address dependency. */ - cpu = smp_processor_id(); - table_base = private->entries; jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; /* Switch to alternate jumpstack if we're being invoked via TEE. @@ -298,7 +326,16 @@ ipt_do_table(void *priv, if (static_key_false(&xt_tee_enabled)) jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); - e = get_entry(table_base, private->hook_entry[hook]); + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask + * things we don't know, ie. tcp syn flag or ports). If the + * rule is also a fragment-specific rule, non-fragments won't + * match it. */ + acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; + acpar.thoff = ip_hdrlen(skb); + acpar.hotdrop = false; + acpar.state = state; do { const struct xt_entry_target *t; -- 2.51.0 From 34ea6fee7df6d495f35ff6fd7045b334c50325ba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:53 +0100 Subject: [PATCH 257/517] netfilter: reduce match memory access Signed-off-by: Felix Fietkau --- net/ipv4/netfilter/ip_tables.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 8325e81b9827..d03e2121810b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -51,9 +51,9 @@ ip_packet_match(const struct iphdr *ip, if (ipinfo->flags & IPT_F_NO_DEF_MATCH) return true; - if (NF_INVF(ipinfo, IPT_INV_SRCIP, + if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr && (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || - NF_INVF(ipinfo, IPT_INV_DSTIP, + NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr && (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr)) return false; -- 2.51.0 From db287f2364f5f532223610146e83950c43e89a11 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:53 +0100 Subject: [PATCH 258/517] net: add an optimization for dealing with raw sockets lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6 Signed-off-by: Felix Fietkau --- include/uapi/linux/if_packet.h | 3 +++ net/packet/af_packet.c | 34 +++++++++++++++++++++++++++------- net/packet/internal.h | 1 + 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index 1d2718dd9647..a52deea9d653 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -33,6 +33,8 @@ struct sockaddr_ll { #define PACKET_KERNEL 7 /* To kernel space */ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ #define PACKET_FASTROUTE 6 /* Fastrouted frame */ +#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ + /* Packet socket options */ @@ -60,6 +62,7 @@ struct sockaddr_ll { #define PACKET_FANOUT_DATA 22 #define PACKET_IGNORE_OUTGOING 23 #define PACKET_VNET_HDR_SZ 24 +#define PACKET_RECV_TYPE 25 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e8589fede4d4..e2c5b44c0e60 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1911,6 +1911,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, { struct sock *sk; struct sockaddr_pkt *spkt; + struct packet_sock *po; /* * When we registered the protocol we saved the socket in the data @@ -1918,6 +1919,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, */ sk = pt->af_packet_priv; + po = pkt_sk(sk); /* * Yank back the headers [hope the device set this @@ -1930,7 +1932,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, * so that this procedure is noop. */ - if (skb->pkt_type == PACKET_LOOPBACK) + if (!(po->pkt_type & (1 << skb->pkt_type))) goto out; if (!net_eq(dev_net(dev), sock_net(sk))) @@ -2175,12 +2177,12 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, int skb_len = skb->len; unsigned int snaplen, res; - if (skb->pkt_type == PACKET_LOOPBACK) - goto drop; - sk = pt->af_packet_priv; po = pkt_sk(sk); + if (!(po->pkt_type & (1 << skb->pkt_type))) + goto drop; + if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; @@ -2304,12 +2306,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); - if (skb->pkt_type == PACKET_LOOPBACK) - goto drop; - sk = pt->af_packet_priv; po = pkt_sk(sk); + if (!(po->pkt_type & (1 << skb->pkt_type))) + goto drop; + if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; @@ -3429,6 +3431,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, mutex_init(&po->pg_vec_lock); po->rollover = NULL; po->prot_hook.func = packet_rcv; + po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); if (sock->type == SOCK_PACKET) po->prot_hook.func = packet_rcv_spkt; @@ -4096,6 +4099,16 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, packet_sock_flag_set(po, PACKET_SOCK_QDISC_BYPASS, val); return 0; } + case PACKET_RECV_TYPE: + { + unsigned int val; + if (optlen != sizeof(val)) + return -EINVAL; + if (copy_from_sockptr(&val, optval, sizeof(val))) + return -EFAULT; + po->pkt_type = val & ~BIT(PACKET_LOOPBACK); + return 0; + } default: return -ENOPROTOOPT; } @@ -4158,6 +4171,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, case PACKET_COPY_THRESH: val = READ_ONCE(pkt_sk(sk)->copy_thresh); break; + case PACKET_RECV_TYPE: + if (len > sizeof(unsigned int)) + len = sizeof(unsigned int); + val = po->pkt_type; + + data = &val; + break; case PACKET_VERSION: val = po->tp_version; break; diff --git a/net/packet/internal.h b/net/packet/internal.h index d5d70712007a..891df18a6947 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -131,6 +131,7 @@ struct packet_sock { struct net_device __rcu *cached_dev; struct packet_type prot_hook ____cacheline_aligned_in_smp; atomic_t tp_drops ____cacheline_aligned_in_smp; + unsigned int pkt_type; }; #define pkt_sk(ptr) container_of_const(ptr, struct packet_sock, sk) -- 2.51.0 From d187d050110d76efe46d7d7eb669a335ec25e330 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 22 Aug 2024 18:02:17 +0200 Subject: [PATCH 259/517] net: bridge: fix switchdev host mdb entry updates When a mdb entry is removed, the bridge switchdev code can issue a switchdev_port_obj_del call for a port that was not offloaded. This leads to an imbalance in switchdev_port_obj_add/del calls, since br_switchdev_mdb_replay has not been called for the port before. This can lead to potential multicast forwarding issues and messages such as: mt7915e 0000:01:00.0 wl1-ap0: Failed to del Host Multicast Database entry (object id=3) with error: -ENOENT (-2). Fix this issue by checking the port offload status when iterating over lower devs. Signed-off-by: Felix Fietkau --- net/bridge/br_switchdev.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index f10bd6a233dc..6dffac613768 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -571,10 +571,18 @@ static void br_switchdev_host_mdb(struct net_device *dev, struct net_bridge_mdb_entry *mp, int type) { struct net_device *lower_dev; + struct net_bridge_port *port; struct list_head *iter; - netdev_for_each_lower_dev(dev, lower_dev, iter) + rcu_read_lock(); + netdev_for_each_lower_dev(dev, lower_dev, iter) { + port = br_port_get_rcu(lower_dev); + if (!port || !port->offload_count) + continue; + br_switchdev_host_mdb_one(dev, lower_dev, mp, type); + } + rcu_read_unlock(); } static int -- 2.51.0 From ee69dd931652725a53e666564b5e9f405be3a770 Mon Sep 17 00:00:00 2001 From: "Leon M. Busch-George" Date: Sun, 20 Oct 2024 18:20:14 +0200 Subject: [PATCH 260/517] net: bridge: switchdev: Don't drop packets between ports with no hwdom nbp_switchdev_allowed_egress uses hwdom to determine whether or not a packet has already been forwarded to a hardware domain. For net_bridge_ports that aren't set up to use forward offloading, hwdom is set to 0. When both ingress and egress port have no hwdom, 'cb->src_hwdom != p->hwdom' indicates that the packet is already known in the target domain - which it isn't - and the packet is wrongly dropped. The error was found on a bridge containing a wifi device and a VLAN tagging device (e.g. eth0.12). With VLAN filtering, this shouldn't happen. This patch adds a check for p->hwdom != 0 before comparing hardware domains to restore forwarding between ports with hwdom = 0. fwd_hwdoms are only set for ports with offloading enabled, which also implies a valid hwdom, so the check '!test_bit(p->hwdom, &cb->fwd_hwdoms)' doesn't fail in this way (yet - fingers crossed..) and it is left in place. Co-developed-by: Felix Fietkau Signed-off-by: Felix Fietkau Signed-off-by: Leon M. Busch-George --- net/bridge/br_switchdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 6dffac613768..98ef0642dda4 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -70,7 +70,7 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, struct br_input_skb_cb *cb = BR_INPUT_SKB_CB(skb); return !test_bit(p->hwdom, &cb->fwd_hwdoms) && - (!skb->offload_fwd_mark || cb->src_hwdom != p->hwdom); + (!skb->offload_fwd_mark || !p->hwdom || cb->src_hwdom != p->hwdom); } /* Flags that can be offloaded to hardware */ -- 2.51.0 From c2a69cffa26902e6c10ea558dd5d6dc305f1dd48 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 Jul 2025 12:37:45 +0200 Subject: [PATCH 261/517] net: pppoe: implement GRO support Only handles packets where the pppoe header length field matches the exact packet length. Significantly improves rx throughput. When running NAT traffic through a MediaTek MT7621 devices from a host behind PPPoE to a host directly connected via ethernet, the TCP throughput that the device is able to handle improves from ~130 Mbit/s to ~630 Mbit/s, using fraglist GRO. Signed-off-by: Felix Fietkau --- drivers/net/ppp/pppoe.c | 160 +++++++++++++++++++++++++++++++++++++++- net/ipv4/af_inet.c | 2 + net/ipv6/ip6_offload.c | 2 + 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 68e631718ab0..3d145fb7a6ab 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -77,6 +77,7 @@ #include #include #include +#include #include @@ -435,7 +436,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->len < len) goto drop; - if (pskb_trim_rcsum(skb, len)) + if (!skb_is_gso(skb) && pskb_trim_rcsum(skb, len)) goto drop; ph = pppoe_hdr(skb); @@ -1173,6 +1174,161 @@ static struct pernet_operations pppoe_net_ops = { .size = sizeof(struct pppoe_net), }; +static u16 +compare_pppoe_header(struct pppoe_hdr *phdr, struct pppoe_hdr *phdr2) +{ + return (__force __u16)((phdr->sid ^ phdr2->sid) | + (phdr->tag[0].tag_type ^ phdr2->tag[0].tag_type)); +} + +static __be16 pppoe_hdr_proto(struct pppoe_hdr *phdr) +{ + switch (phdr->tag[0].tag_type) { + case cpu_to_be16(PPP_IP): + return cpu_to_be16(ETH_P_IP); + case cpu_to_be16(PPP_IPV6): + return cpu_to_be16(ETH_P_IPV6); + default: + return 0; + } + +} + +static struct sk_buff *pppoe_gro_receive(struct list_head *head, + struct sk_buff *skb) +{ + const struct packet_offload *ptype; + unsigned int hlen, off_pppoe; + struct sk_buff *pp = NULL; + struct pppoe_hdr *phdr; + struct sk_buff *p; + int flush = 1; + __be16 type; + + off_pppoe = skb_gro_offset(skb); + hlen = off_pppoe + sizeof(*phdr); + phdr = skb_gro_header(skb, hlen + 2, off_pppoe); + if (unlikely(!phdr)) + goto out; + + /* ignore packets with padding or invalid length */ + if (skb_gro_len(skb) != be16_to_cpu(phdr->length) + hlen) + goto out; + + type = pppoe_hdr_proto(phdr); + if (!type) + goto out; + + ptype = gro_find_receive_by_type(type); + if (!ptype) + goto out; + + flush = 0; + + list_for_each_entry(p, head, list) { + struct pppoe_hdr *phdr2; + + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + phdr2 = (struct pppoe_hdr *)(p->data + off_pppoe); + if (compare_pppoe_header(phdr, phdr2)) + NAPI_GRO_CB(p)->same_flow = 0; + } + + skb_gro_pull(skb, sizeof(*phdr) + 2); + skb_gro_postpull_rcsum(skb, phdr, sizeof(*phdr) + 2); + + pp = indirect_call_gro_receive_inet(ptype->callbacks.gro_receive, + ipv6_gro_receive, inet_gro_receive, + head, skb); + +out: + skb_gro_flush_final(skb, pp, flush); + + return pp; +} + +static int pppoe_gro_complete(struct sk_buff *skb, int nhoff) +{ + struct pppoe_hdr *phdr = (struct pppoe_hdr *)(skb->data + nhoff); + __be16 type = pppoe_hdr_proto(phdr); + struct packet_offload *ptype; + int len, err; + + ptype = gro_find_complete_by_type(type); + if (!ptype) + return -ENOENT; + + err = INDIRECT_CALL_INET(ptype->callbacks.gro_complete, + ipv6_gro_complete, inet_gro_complete, + skb, nhoff + sizeof(*phdr) + 2); + if (err) + return err; + + len = skb->len - (nhoff + sizeof(*phdr)); + phdr->length = cpu_to_be16(len); + + return 0; +} + +static struct sk_buff *pppoe_gso_segment(struct sk_buff *skb, + netdev_features_t features) +{ + unsigned int pppoe_hlen = sizeof(struct pppoe_hdr) + 2; + struct sk_buff *segs = ERR_PTR(-EINVAL); + u16 mac_offset = skb->mac_header; + struct packet_offload *ptype; + u16 mac_len = skb->mac_len; + struct pppoe_hdr *phdr; + __be16 orig_type, type; + int len, nhoff; + + skb_reset_network_header(skb); + nhoff = skb_network_header(skb) - skb_mac_header(skb); + + if (unlikely(!pskb_may_pull(skb, pppoe_hlen))) + goto out; + + phdr = (struct pppoe_hdr *)skb_network_header(skb); + type = pppoe_hdr_proto(phdr); + ptype = gro_find_complete_by_type(type); + if (!ptype) + goto out; + + orig_type = skb->protocol; + __skb_pull(skb, pppoe_hlen); + segs = ptype->callbacks.gso_segment(skb, features); + if (IS_ERR_OR_NULL(segs)) { + skb_gso_error_unwind(skb, orig_type, pppoe_hlen, mac_offset, + mac_len); + goto out; + } + + skb = segs; + do { + phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff); + len = skb->len - (nhoff + sizeof(*phdr)); + phdr->length = cpu_to_be16(len); + skb->network_header = (u8 *)phdr - skb->head; + skb->protocol = orig_type; + skb_reset_mac_len(skb); + } while ((skb = skb->next)); + +out: + return segs; +} + +static struct packet_offload pppoe_packet_offload __read_mostly = { + .type = cpu_to_be16(ETH_P_PPP_SES), + .priority = 20, + .callbacks = { + .gro_receive = pppoe_gro_receive, + .gro_complete = pppoe_gro_complete, + .gso_segment = pppoe_gso_segment, + }, +}; + static int __init pppoe_init(void) { int err; @@ -1189,6 +1345,7 @@ static int __init pppoe_init(void) if (err) goto out_unregister_pppoe_proto; + dev_add_offload(&pppoe_packet_offload); dev_add_pack(&pppoes_ptype); dev_add_pack(&pppoed_ptype); register_netdevice_notifier(&pppoe_notifier); @@ -1208,6 +1365,7 @@ static void __exit pppoe_exit(void) unregister_netdevice_notifier(&pppoe_notifier); dev_remove_pack(&pppoed_ptype); dev_remove_pack(&pppoes_ptype); + dev_remove_offload(&pppoe_packet_offload); unregister_pppox_proto(PX_PROTO_OE); proto_unregister(&pppoe_sk_proto); unregister_pernet_device(&pppoe_net_ops); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8095e82de808..a1a7d91c42f6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1546,6 +1546,7 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb) return pp; } +EXPORT_INDIRECT_CALLABLE(inet_gro_receive); static struct sk_buff *ipip_gro_receive(struct list_head *head, struct sk_buff *skb) @@ -1631,6 +1632,7 @@ int inet_gro_complete(struct sk_buff *skb, int nhoff) out: return err; } +EXPORT_INDIRECT_CALLABLE(inet_gro_complete); static int ipip_gro_complete(struct sk_buff *skb, int nhoff) { diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index fce91183797a..9e3640b018a4 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -306,6 +306,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head, return pp; } +EXPORT_INDIRECT_CALLABLE(ipv6_gro_receive); static struct sk_buff *sit_ip6ip6_gro_receive(struct list_head *head, struct sk_buff *skb) @@ -388,6 +389,7 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff) out: return err; } +EXPORT_INDIRECT_CALLABLE(ipv6_gro_complete); static int sit_gro_complete(struct sk_buff *skb, int nhoff) { -- 2.51.0 From 2e462085b5c2cff943dd6a5620e0f541be7acaeb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:49:54 +0100 Subject: [PATCH 262/517] kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd Signed-off-by: Felix Fietkau --- include/linux/skbuff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 314328ab0b84..eb7b94939f46 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3209,7 +3209,7 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len) * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) */ #ifndef NET_SKB_PAD -#define NET_SKB_PAD max(32, L1_CACHE_BYTES) +#define NET_SKB_PAD max(64, L1_CACHE_BYTES) #endif int ___pskb_trim(struct sk_buff *skb, unsigned int len); -- 2.51.0 From 7c39dc46af4ecff37c87b8ed7e9061f44e1401ce Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 3 Nov 2025 15:49:55 +0100 Subject: [PATCH 263/517] Add support for MAP-E FMRs (mesh mode) MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication between MAP CEs (mesh mode) without the need to forward such data to a border relay. This is similar to how 6rd works but for IPv4 over IPv6. Signed-off-by: Steven Barth --- include/net/ip6_tunnel.h | 13 ++ include/uapi/linux/if_tunnel.h | 13 ++ net/ipv6/ip6_tunnel.c | 281 ++++++++++++++++++++++++++++++++- 3 files changed, 299 insertions(+), 8 deletions(-) diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h index 399592405c72..79b066a4d13b 100644 --- a/include/net/ip6_tunnel.h +++ b/include/net/ip6_tunnel.h @@ -18,6 +18,18 @@ /* determine capability on a per-packet basis */ #define IP6_TNL_F_CAP_PER_PACKET 0x40000 +/* IPv6 tunnel FMR */ +struct __ip6_tnl_fmr { + struct __ip6_tnl_fmr *next; /* next fmr in list */ + struct in6_addr ip6_prefix; + struct in_addr ip4_prefix; + + __u8 ip6_prefix_len; + __u8 ip4_prefix_len; + __u8 ea_len; + __u8 offset; +}; + struct __ip6_tnl_parm { char name[IFNAMSIZ]; /* name of tunnel device */ int link; /* ifindex of underlying L2 interface */ @@ -29,6 +41,7 @@ struct __ip6_tnl_parm { __u32 flags; /* tunnel flags */ struct in6_addr laddr; /* local tunnel end-point address */ struct in6_addr raddr; /* remote tunnel end-point address */ + struct __ip6_tnl_fmr *fmrs; /* FMRs */ IP_TUNNEL_DECLARE_FLAGS(i_flags); IP_TUNNEL_DECLARE_FLAGS(o_flags); diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h index e1a246dd8c62..fda447945078 100644 --- a/include/uapi/linux/if_tunnel.h +++ b/include/uapi/linux/if_tunnel.h @@ -77,10 +77,23 @@ enum { IFLA_IPTUN_ENCAP_DPORT, IFLA_IPTUN_COLLECT_METADATA, IFLA_IPTUN_FWMARK, + IFLA_IPTUN_FMRS, __IFLA_IPTUN_MAX, }; #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +enum { + IFLA_IPTUN_FMR_UNSPEC, + IFLA_IPTUN_FMR_IP6_PREFIX, + IFLA_IPTUN_FMR_IP4_PREFIX, + IFLA_IPTUN_FMR_IP6_PREFIX_LEN, + IFLA_IPTUN_FMR_IP4_PREFIX_LEN, + IFLA_IPTUN_FMR_EA_LEN, + IFLA_IPTUN_FMR_OFFSET, + __IFLA_IPTUN_FMR_MAX, +}; +#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) + enum tunnel_encap_types { TUNNEL_ENCAP_NONE, TUNNEL_ENCAP_FOU, diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index b72ca1034906..ff58b562758e 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -11,6 +11,9 @@ * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c * * RFC 2473 + * + * Changes: + * Steven Barth : MAP-E FMR support */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -68,9 +71,9 @@ static bool log_ecn_error = true; module_param(log_ecn_error, bool, 0644); MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); -static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) +static u32 HASH(const struct in6_addr *addr) { - u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); + u32 hash = ipv6_addr_hash(addr); return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT); } @@ -115,17 +118,33 @@ static struct ip6_tnl * ip6_tnl_lookup(struct net *net, int link, const struct in6_addr *remote, const struct in6_addr *local) { - unsigned int hash = HASH(remote, local); + unsigned int hash = HASH(local); struct ip6_tnl *t, *cand = NULL; struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); struct in6_addr any; for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { if (!ipv6_addr_equal(local, &t->parms.laddr) || - !ipv6_addr_equal(remote, &t->parms.raddr) || !(t->dev->flags & IFF_UP)) continue; + if (!ipv6_addr_equal(remote, &t->parms.raddr)) { + struct __ip6_tnl_fmr *fmr; + bool found = false; + + for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { + if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix, + fmr->ip6_prefix_len)) + continue; + + found = true; + break; + } + + if (!found) + continue; + } + if (link == t->parms.link) return t; else @@ -133,7 +152,7 @@ ip6_tnl_lookup(struct net *net, int link, } memset(&any, 0, sizeof(any)); - hash = HASH(&any, local); + hash = HASH(local); for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { if (!ipv6_addr_equal(local, &t->parms.laddr) || !ipv6_addr_any(&t->parms.raddr) || @@ -146,7 +165,7 @@ ip6_tnl_lookup(struct net *net, int link, cand = t; } - hash = HASH(remote, &any); + hash = HASH(&any); for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { if (!ipv6_addr_equal(remote, &t->parms.raddr) || !ipv6_addr_any(&t->parms.laddr) || @@ -195,7 +214,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p) if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { prio = 1; - h = HASH(remote, local); + h = HASH(local); } return &ip6n->tnls[prio][h]; } @@ -376,6 +395,12 @@ ip6_tnl_dev_uninit(struct net_device *dev) struct net *net = t->net; struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + while (t->parms.fmrs) { + struct __ip6_tnl_fmr *next = t->parms.fmrs->next; + kfree(t->parms.fmrs); + t->parms.fmrs = next; + } + if (dev == ip6n->fb_tnl_dev) RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); else @@ -790,6 +815,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, } EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); +/** + * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR + * @dest: destination IPv6 address buffer + * @skb: received socket buffer + * @fmr: MAP FMR + * @xmit: Calculate for xmit or rcv + **/ +static void ip4ip6_fmr_calc(struct in6_addr *dest, + const struct iphdr *iph, const uint8_t *end, + const struct __ip6_tnl_fmr *fmr, bool xmit) +{ + int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); + u8 *portp = NULL; + bool use_dest_addr; + const struct iphdr *dsth = iph; + + if ((u8*)dsth >= end) + return; + + /* find significant IP header */ + if (iph->protocol == IPPROTO_ICMP) { + struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); + if (ih && ((u8*)&ih[1]) <= end && ( + ih->type == ICMP_DEST_UNREACH || + ih->type == ICMP_SOURCE_QUENCH || + ih->type == ICMP_TIME_EXCEEDED || + ih->type == ICMP_PARAMETERPROB || + ih->type == ICMP_REDIRECT)) + dsth = (const struct iphdr*)&ih[1]; + } + + /* in xmit-path use dest port by default and source port only if + this is an ICMP reply to something else; vice versa in rcv-path */ + use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); + + /* get dst port */ + if (((u8*)&dsth[1]) <= end && ( + dsth->protocol == IPPROTO_UDP || + dsth->protocol == IPPROTO_TCP || + dsth->protocol == IPPROTO_SCTP || + dsth->protocol == IPPROTO_DCCP)) { + /* for UDP, TCP, SCTP and DCCP source and dest port + follow IPv4 header directly */ + portp = ((u8*)dsth) + dsth->ihl * 4; + + if (use_dest_addr) + portp += sizeof(u16); + } else if (iph->protocol == IPPROTO_ICMP) { + struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); + + /* use icmp identifier as port */ + if (((u8*)&ih) <= end && ( + (use_dest_addr && ( + ih->type == ICMP_ECHOREPLY || + ih->type == ICMP_TIMESTAMPREPLY || + ih->type == ICMP_INFO_REPLY || + ih->type == ICMP_ADDRESSREPLY)) || + (!use_dest_addr && ( + ih->type == ICMP_ECHO || + ih->type == ICMP_TIMESTAMP || + ih->type == ICMP_INFO_REQUEST || + ih->type == ICMP_ADDRESS) + ))) + portp = (u8*)&ih->un.echo.id; + } + + if ((portp && &portp[2] <= end) || psidlen == 0) { + int frombyte = fmr->ip6_prefix_len / 8; + int fromrem = fmr->ip6_prefix_len % 8; + int bytes = sizeof(struct in6_addr) - frombyte; + const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; + u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); + u64 t = 0; + + /* extract PSID from port and add it to eabits */ + u16 psidbits = 0; + if (psidlen > 0) { + psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); + psidbits >>= 16 - psidlen - fmr->offset; + psidbits = (u16)(psidbits << (16 - psidlen)); + eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); + } + + /* rewrite destination address */ + *dest = fmr->ip6_prefix; + memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); + dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); + + if (bytes > sizeof(u64)) + bytes = sizeof(u64); + + /* insert eabits */ + memcpy(&t, &dest->s6_addr[frombyte], bytes); + t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) + << (64 - fmr->ea_len - fromrem)); + t = cpu_to_be64(t | (eabits >> fromrem)); + memcpy(&dest->s6_addr[frombyte], &t, bytes); + } +} + + static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, @@ -855,6 +981,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs && + !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) { + /* Packet didn't come from BR, so lookup FMR */ + struct __ip6_tnl_fmr *fmr; + struct in6_addr expected = tunnel->parms.raddr; + for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next) + if (ipv6_prefix_equal(&ipv6h->saddr, + &fmr->ip6_prefix, fmr->ip6_prefix_len)) + break; + + /* Check that IPv6 matches IPv4 source to prevent spoofing */ + if (fmr) + ip4ip6_fmr_calc(&expected, ip_hdr(skb), + skb_tail_pointer(skb), fmr, false); + + if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { + rcu_read_unlock(); + goto drop; + } + } + __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); @@ -1004,6 +1151,7 @@ static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) opt->ops.opt_nflen = 8; } + /** * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own * @t: the outgoing tunnel device @@ -1293,6 +1441,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, u8 protocol) { struct ip6_tnl *t = netdev_priv(dev); + struct __ip6_tnl_fmr *fmr; struct ipv6hdr *ipv6h; const struct iphdr *iph; int encap_limit = -1; @@ -1392,6 +1541,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield); + /* try to find matching FMR */ + for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { + unsigned mshift = 32 - fmr->ip4_prefix_len; + if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == + ntohl(ip_hdr(skb)->daddr) >> mshift) + break; + } + + /* change dstaddr according to FMR */ + if (fmr) + ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true); + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) return -1; @@ -1545,6 +1706,14 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) t->parms.link = p->link; t->parms.proto = p->proto; t->parms.fwmark = p->fwmark; + + while (t->parms.fmrs) { + struct __ip6_tnl_fmr *next = t->parms.fmrs->next; + kfree(t->parms.fmrs); + t->parms.fmrs = next; + } + t->parms.fmrs = p->fmrs; + dst_cache_reset(&t->dst_cache); ip6_tnl_link_config(t); } @@ -1579,6 +1748,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) p->flowinfo = u->flowinfo; p->link = u->link; p->proto = u->proto; + p->fmrs = NULL; memcpy(p->name, u->name, sizeof(u->name)); } @@ -1962,6 +2132,15 @@ static int ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[], return 0; } +static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { + [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, + [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, + [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, + [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, + [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, + [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } +}; + static void ip6_tnl_netlink_parms(struct nlattr *data[], struct __ip6_tnl_parm *parms) { @@ -1999,6 +2178,46 @@ static void ip6_tnl_netlink_parms(struct nlattr *data[], if (data[IFLA_IPTUN_FWMARK]) parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); + + if (data[IFLA_IPTUN_FMRS]) { + unsigned rem; + struct nlattr *fmr; + nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { + struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; + struct __ip6_tnl_fmr *nfmr; + + nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, + fmr, ip6_tnl_fmr_policy, NULL); + + if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) + continue; + + nfmr->offset = 6; + + if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) + nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], + sizeof(nfmr->ip6_prefix)); + + if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) + nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], + sizeof(nfmr->ip4_prefix)); + + if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) + nfmr->ip6_prefix_len = nla_get_u8(c); + + if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) + nfmr->ip4_prefix_len = nla_get_u8(c); + + if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) + nfmr->ea_len = nla_get_u8(c); + + if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) + nfmr->offset = nla_get_u8(c); + + nfmr->next = parms->fmrs; + parms->fmrs = nfmr; + } + } } static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, @@ -2083,6 +2302,12 @@ static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head) static size_t ip6_tnl_get_size(const struct net_device *dev) { + const struct ip6_tnl *t = netdev_priv(dev); + struct __ip6_tnl_fmr *c; + int fmrs = 0; + for (c = t->parms.fmrs; c; c = c->next) + ++fmrs; + return /* IFLA_IPTUN_LINK */ nla_total_size(4) + @@ -2112,6 +2337,24 @@ static size_t ip6_tnl_get_size(const struct net_device *dev) nla_total_size(0) + /* IFLA_IPTUN_FWMARK */ nla_total_size(4) + + /* IFLA_IPTUN_FMRS */ + nla_total_size(0) + + ( + /* nest */ + nla_total_size(0) + + /* IFLA_IPTUN_FMR_IP6_PREFIX */ + nla_total_size(sizeof(struct in6_addr)) + + /* IFLA_IPTUN_FMR_IP4_PREFIX */ + nla_total_size(sizeof(struct in_addr)) + + /* IFLA_IPTUN_FMR_EA_LEN */ + nla_total_size(1) + + /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ + nla_total_size(1) + + /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ + nla_total_size(1) + + /* IFLA_IPTUN_FMR_OFFSET */ + nla_total_size(1) + ) * fmrs + 0; } @@ -2119,6 +2362,9 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct ip6_tnl *tunnel = netdev_priv(dev); struct __ip6_tnl_parm *parm = &tunnel->parms; + struct __ip6_tnl_fmr *c; + int fmrcnt = 0; + struct nlattr *fmrs; if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || @@ -2128,9 +2374,27 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || - nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark)) + nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) || + !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) goto nla_put_failure; + for (c = parm->fmrs; c; c = c->next) { + struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); + if (!fmr || + nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, + sizeof(c->ip6_prefix), &c->ip6_prefix) || + nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, + sizeof(c->ip4_prefix), &c->ip4_prefix) || + nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || + nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || + nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || + nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) + goto nla_put_failure; + + nla_nest_end(skb, fmr); + } + nla_nest_end(skb, fmrs); + if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || @@ -2170,6 +2434,7 @@ static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, + [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, }; static struct rtnl_link_ops ip6_link_ops __read_mostly = { -- 2.51.0 From 3878b9edc9d3b56abb5439d09dc4f05403518e35 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 3 Nov 2025 15:49:55 +0100 Subject: [PATCH 264/517] ipv6: allow rejecting with "source address failed policy" RFC6204 L-14 requires rejecting traffic from invalid addresses with ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ egress policy) on the LAN side, so add an appropriate rule for that. Signed-off-by: Jonas Gorski --- include/net/netns/ipv6.h | 1 + include/uapi/linux/fib_rules.h | 4 +++ include/uapi/linux/rtnetlink.h | 1 + net/ipv4/fib_semantics.c | 4 +++ net/ipv4/fib_trie.c | 1 + net/ipv4/ipmr.c | 1 + net/ipv6/fib6_rules.c | 4 +++ net/ipv6/ip6mr.c | 2 ++ net/ipv6/route.c | 56 ++++++++++++++++++++++++++++++++-- 9 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 5f2cfd84570a..c56a4b0e9636 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -86,6 +86,7 @@ struct netns_ipv6 { unsigned int fib6_routes_require_src; #endif struct rt6_info *ip6_prohibit_entry; + struct rt6_info *ip6_policy_failed_entry; struct rt6_info *ip6_blk_hole_entry; struct fib6_table *fib6_local_tbl; struct fib_rules_ops *fib6_rules_ops; diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index a6924dd3aff1..4b3e1d99a654 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h @@ -83,6 +83,10 @@ enum { FR_ACT_BLACKHOLE, /* Drop without notification */ FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ FR_ACT_PROHIBIT, /* Drop with EACCES */ + FR_ACT_RES9, + FR_ACT_RES10, + FR_ACT_RES11, + FR_ACT_POLICY_FAILED, /* Drop with EACCES */ __FR_ACT_MAX, }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index db7254d52d93..d49560d2bd71 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -265,6 +265,7 @@ enum { RTN_THROW, /* Not in this table */ RTN_NAT, /* Translate this address */ RTN_XRESOLVE, /* Use external resolver */ + RTN_POLICY_FAILED, /* Failed ingress/egress policy */ __RTN_MAX }; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index ba2df3d2ac15..f70f87839faa 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -145,6 +145,10 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE, }, + [RTN_POLICY_FAILED] = { + .error = -EACCES, + .scope = RT_SCOPE_UNIVERSE, + }, }; static void rt_fibinfo_free(struct rtable __rcu **rtp) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index cc86031d2050..b7440806041b 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2762,6 +2762,7 @@ static const char *const rtn_type_names[__RTN_MAX] = { [RTN_THROW] = "THROW", [RTN_NAT] = "NAT", [RTN_XRESOLVE] = "XRESOLVE", + [RTN_POLICY_FAILED] = "POLICY_FAILED", }; static inline const char *rtn_type(char *buf, size_t len, unsigned int t) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index de0d9cc7806a..bef0f63f4fd4 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -191,6 +191,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, case FR_ACT_UNREACHABLE: return -ENETUNREACH; case FR_ACT_PROHIBIT: + case FR_ACT_POLICY_FAILED: return -EACCES; case FR_ACT_BLACKHOLE: default: diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 29185c9ebd02..369fcdcfd0f0 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -222,6 +222,10 @@ static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp, err = -EACCES; rt = net->ipv6.ip6_prohibit_entry; goto discard_pkt; + case FR_ACT_POLICY_FAILED: + err = -EACCES; + rt = net->ipv6.ip6_policy_failed_entry; + goto discard_pkt; } tb_id = fib_rule_get_table(rule, arg); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 68bc518500f9..685d4c37b6ed 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -180,6 +180,8 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, return -ENETUNREACH; case FR_ACT_PROHIBIT: return -EACCES; + case FR_ACT_POLICY_FAILED: + return -EACCES; case FR_ACT_BLACKHOLE: default: return -EINVAL; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 22866444efc0..33cfc2dc9aaf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -98,6 +98,8 @@ static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); static int ip6_pkt_prohibit(struct sk_buff *skb); static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); +static int ip6_pkt_policy_failed(struct sk_buff *skb); +static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu, @@ -316,6 +318,18 @@ static const struct rt6_info ip6_prohibit_entry_template = { .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), }; +static const struct rt6_info ip6_policy_failed_entry_template = { + .dst = { + .__rcuref = RCUREF_INIT(1), + .__use = 1, + .obsolete = DST_OBSOLETE_FORCE_CHK, + .error = -EACCES, + .input = ip6_pkt_policy_failed, + .output = ip6_pkt_policy_failed_out, + }, + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), +}; + static const struct rt6_info ip6_blk_hole_entry_template = { .dst = { .__rcuref = RCUREF_INIT(1), @@ -1085,6 +1099,7 @@ static const int fib6_prop[RTN_MAX + 1] = { [RTN_BLACKHOLE] = -EINVAL, [RTN_UNREACHABLE] = -EHOSTUNREACH, [RTN_PROHIBIT] = -EACCES, + [RTN_POLICY_FAILED] = -EACCES, [RTN_THROW] = -EAGAIN, [RTN_NAT] = -EINVAL, [RTN_XRESOLVE] = -EINVAL, @@ -1120,6 +1135,10 @@ static void ip6_rt_init_dst_reject(struct rt6_info *rt, u8 fib6_type) rt->dst.output = ip6_pkt_prohibit_out; rt->dst.input = ip6_pkt_prohibit; break; + case RTN_POLICY_FAILED: + rt->dst.output = ip6_pkt_policy_failed_out; + rt->dst.input = ip6_pkt_policy_failed; + break; case RTN_THROW: case RTN_UNREACHABLE: default: @@ -4598,6 +4617,17 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } +static int ip6_pkt_policy_failed(struct sk_buff *skb) +{ + return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); +} + +static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb) +{ + skb->dev = skb_dst(skb)->dev; + return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); +} + /* * Allocate a dst for local (unicast / anycast) address. */ @@ -5089,7 +5119,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, if (rtm->rtm_type == RTN_UNREACHABLE || rtm->rtm_type == RTN_BLACKHOLE || rtm->rtm_type == RTN_PROHIBIT || - rtm->rtm_type == RTN_THROW) + rtm->rtm_type == RTN_THROW || + rtm->rtm_type == RTN_POLICY_FAILED) cfg->fc_flags |= RTF_REJECT; if (rtm->rtm_type == RTN_LOCAL) @@ -6357,6 +6388,8 @@ static int ip6_route_dev_notify(struct notifier_block *this, #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry->dst.dev = dev; net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_policy_failed_entry->dst.dev = dev; + net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); net->ipv6.ip6_blk_hole_entry->dst.dev = dev; net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); #endif @@ -6368,6 +6401,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); + in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev); in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); #endif } @@ -6563,6 +6597,8 @@ static int __net_init ip6_route_net_init(struct net *net) #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.fib6_has_custom_rules = false; + + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, sizeof(*net->ipv6.ip6_prohibit_entry), GFP_KERNEL); @@ -6573,11 +6609,21 @@ static int __net_init ip6_route_net_init(struct net *net) ip6_template_metrics, true); INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached); + net->ipv6.ip6_policy_failed_entry = + kmemdup(&ip6_policy_failed_entry_template, + sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); + if (!net->ipv6.ip6_policy_failed_entry) + goto out_ip6_prohibit_entry; + net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, + ip6_template_metrics, true); + INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->dst.rt_uncached); + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, sizeof(*net->ipv6.ip6_blk_hole_entry), GFP_KERNEL); if (!net->ipv6.ip6_blk_hole_entry) - goto out_ip6_prohibit_entry; + goto out_ip6_policy_failed_entry; net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, ip6_template_metrics, true); @@ -6604,6 +6650,8 @@ static int __net_init ip6_route_net_init(struct net *net) return ret; #ifdef CONFIG_IPV6_MULTIPLE_TABLES +out_ip6_policy_failed_entry: + kfree(net->ipv6.ip6_policy_failed_entry); out_ip6_prohibit_entry: kfree(net->ipv6.ip6_prohibit_entry); out_ip6_null_entry: @@ -6623,6 +6671,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) kfree(net->ipv6.ip6_null_entry); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_policy_failed_entry); kfree(net->ipv6.ip6_blk_hole_entry); #endif dst_entries_destroy(&net->ipv6.ip6_dst_ops); @@ -6706,6 +6755,9 @@ void __init ip6_route_init_special_entries(void) init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = + in6_dev_get(init_net.loopback_dev); #endif } -- 2.51.0 From afd618b85af8f8aac217bd64b5626dd6062caf19 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Mon, 3 Nov 2025 15:49:55 +0100 Subject: [PATCH 265/517] net: provide defines for _POLICY_FAILED until all code is updated Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination unreachable, conflicting with our name. Add appropriate defines to allow our code to build with the new name until we have updated our local patches for older kernels and userspace packages. Signed-off-by: Jonas Gorski --- include/uapi/linux/fib_rules.h | 2 ++ include/uapi/linux/icmpv6.h | 2 ++ include/uapi/linux/rtnetlink.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index 4b3e1d99a654..598fe9d0f409 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h @@ -90,6 +90,8 @@ enum { __FR_ACT_MAX, }; +#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED + #define FR_ACT_MAX (__FR_ACT_MAX - 1) #endif diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h index 4eaab89e2856..1d7e12b488ac 100644 --- a/include/uapi/linux/icmpv6.h +++ b/include/uapi/linux/icmpv6.h @@ -127,6 +127,8 @@ struct icmp6hdr { #define ICMPV6_POLICY_FAIL 5 #define ICMPV6_REJECT_ROUTE 6 +#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL + /* * Codes for Time Exceeded */ diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index d49560d2bd71..795736ef4217 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -269,6 +269,8 @@ enum { __RTN_MAX }; +#define RTN_FAILED_POLICY RTN_POLICY_FAILED + #define RTN_MAX (__RTN_MAX - 1) -- 2.51.0 From d1e0e08702e53d8608d0464cace36a3e1ef428b3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 15 Aug 2024 21:15:13 +0200 Subject: [PATCH 266/517] net: remove NETIF_F_GSO_FRAGLIST from NETIF_F_GSO_SOFTWARE Several drivers set NETIF_F_GSO_SOFTWARE, but mangle fraglist GRO packets in a way that they can't be properly segmented anymore. In order to properly deal with this, remove fraglist GSO from NETIF_F_GSO_SOFTWARE and switch to NETIF_F_GSO_SOFTWARE_ALL (which includes fraglist GSO) in places where it's safe to add. Signed-off-by: Felix Fietkau --- drivers/net/dummy.c | 2 +- drivers/net/loopback.c | 2 +- drivers/net/macvlan.c | 2 +- include/linux/netdev_features.h | 5 +++-- net/8021q/vlan.h | 2 +- net/8021q/vlan_dev.c | 4 ++-- net/core/sock.c | 2 +- net/mac80211/ieee80211_i.h | 2 +- net/openvswitch/vport-internal_dev.c | 2 +- 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index e9c5e1e11fa0..d32b6190bde1 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -111,7 +111,7 @@ static void dummy_setup(struct net_device *dev) dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; dev->lltx = true; dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST; - dev->features |= NETIF_F_GSO_SOFTWARE; + dev->features |= NETIF_F_GSO_SOFTWARE_ALL; dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; dev->features |= NETIF_F_GSO_ENCAP_ALL; dev->hw_features |= dev->features; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 491e56b3263f..602396bec287 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -174,7 +174,7 @@ static void gen_lo_setup(struct net_device *dev, dev->lltx = true; dev->netns_local = true; netif_keep_dst(dev); - dev->hw_features = NETIF_F_GSO_SOFTWARE; + dev->hw_features = NETIF_F_GSO_SOFTWARE_ALL; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | NETIF_F_HW_CSUM diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index cf18e66de142..e1a501061d21 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -897,7 +897,7 @@ static int macvlan_hwtstamp_set(struct net_device *dev, static struct lock_class_key macvlan_netdev_addr_lock_key; #define ALWAYS_ON_OFFLOADS \ - (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | \ + (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL | \ NETIF_F_GSO_ROBUST | NETIF_F_GSO_ENCAP_ALL) #define ALWAYS_ON_FEATURES ALWAYS_ON_OFFLOADS diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 11be70a7929f..e2e3dd919068 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -211,13 +211,14 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start) /* List of features with software fallbacks. */ #define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_GSO_SCTP | \ - NETIF_F_GSO_UDP_L4 | NETIF_F_GSO_FRAGLIST) + NETIF_F_GSO_UDP_L4) +#define NETIF_F_GSO_SOFTWARE_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_FRAGLIST) /* * If one device supports one of these features, then enable them * for all in netdev_increment_features. */ -#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ +#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ROBUST | \ NETIF_F_SG | NETIF_F_HIGHDMA | \ NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index c7ffe591d593..8a446f996172 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -109,7 +109,7 @@ static inline netdev_features_t vlan_tnl_features(struct net_device *real_dev) netdev_features_t ret; ret = real_dev->hw_enc_features & - (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE | + (NETIF_F_CSUM_MASK | NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ENCAP_ALL); if ((ret & NETIF_F_GSO_ENCAP_ALL) && (ret & NETIF_F_CSUM_MASK)) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 9184cf7eb128..3cecafc13a3e 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -538,7 +538,7 @@ static int vlan_dev_init(struct net_device *dev) dev->state |= (1 << __LINK_STATE_NOCARRIER); dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | - NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | + NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ENCAP_ALL | NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | NETIF_F_FCOE_CRC | NETIF_F_FSO; @@ -634,7 +634,7 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, if (lower_features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)) lower_features |= NETIF_F_HW_CSUM; features = netdev_intersect_features(features, lower_features); - features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE); + features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE_ALL); return features; } diff --git a/net/core/sock.c b/net/core/sock.c index a5f248a91404..57fafa7cb47b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2554,7 +2554,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) icsk->icsk_ack.dst_quick_ack = dst_metric(dst, RTAX_QUICKACK); } if (sk->sk_route_caps & NETIF_F_GSO) - sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; + sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE_ALL; if (unlikely(sk->sk_gso_disabled)) sk->sk_route_caps &= ~NETIF_F_GSO_MASK; if (sk_can_gso(sk)) { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2f017dbbcb97..6289ba270e23 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2021,7 +2021,7 @@ void ieee80211_color_collision_detection_work(struct wiphy *wiphy, /* interface handling */ #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ NETIF_F_HW_CSUM | NETIF_F_SG | \ - NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE | \ + NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE_ALL | \ NETIF_F_HW_TC) #define MAC80211_SUPPORTED_FEATURES_RX (NETIF_F_RXCSUM) #define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \ diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 5858d65ea1a9..2bc32affb98a 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -109,7 +109,7 @@ static void do_setup(struct net_device *netdev) netdev->rtnl_link_ops = &internal_dev_link_ops; netdev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE | + NETIF_F_HW_CSUM | NETIF_F_GSO_SOFTWARE_ALL | NETIF_F_GSO_ENCAP_ALL; netdev->vlan_features = netdev->features; -- 2.51.0 From 1d33d41f90da611376b78c3db81b12643fd330da Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 12:22:48 +0200 Subject: [PATCH 267/517] of/of_net: write back netdev MAC-address to device-tree The label-mac logic relies on the mac-address property of a netdev devices of-node. However, the mac address can also be stored as a different property or read from e.g. an mtd device. Create this node when reading a mac-address from OF if it does not already exist and copy the mac-address used for the device to this property. This way, the MAC address can be accessed using procfs. --- net/core/of_net.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/net/core/of_net.c b/net/core/of_net.c index 93ea425b9248..2497ae67dad5 100644 --- a/net/core/of_net.c +++ b/net/core/of_net.c @@ -97,6 +97,27 @@ int of_get_mac_address_nvmem(struct device_node *np, u8 *addr) } EXPORT_SYMBOL(of_get_mac_address_nvmem); +static int of_add_mac_address(struct device_node *np, u8* addr) +{ + struct property *prop; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return -ENOMEM; + + prop->name = "mac-address"; + prop->length = ETH_ALEN; + prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL); + if (!prop->value || of_update_property(np, prop)) + goto free; + + return 0; +free: + kfree(prop->value); + kfree(prop); + return -ENOMEM; +} + /** * of_get_mac_address() * @np: Caller's Device Node @@ -132,17 +153,23 @@ int of_get_mac_address(struct device_node *np, u8 *addr) ret = of_get_mac_addr(np, "mac-address", addr); if (!ret) - return 0; + goto found; ret = of_get_mac_addr(np, "local-mac-address", addr); if (!ret) - return 0; + goto found; ret = of_get_mac_addr(np, "address", addr); if (!ret) - return 0; + goto found; - return of_get_mac_address_nvmem(np, addr); + ret = of_get_mac_address_nvmem(np, addr); + if (ret) + return ret; + +found: + ret = of_add_mac_address(np, addr); + return ret; } EXPORT_SYMBOL(of_get_mac_address); -- 2.51.0 From f601c2883cdc25ee169350d3477da082fe5c5779 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 7 May 2024 11:24:50 +0200 Subject: [PATCH 268/517] net: add missing check for TCP fraglist GRO It turns out that the existing checks do not guarantee that the skb can be pulled up to the GRO offset. When using the usb r8152 network driver with GRO fraglist, the BUG() in __skb_pull is often triggered. Fix the crash by adding the missing check. Fixes: 8d95dc474f85 ("net: add code for TCP fraglist GRO") Signed-off-by: Felix Fietkau --- net/ipv4/tcp_offload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 3a9c5c14c310..eaf92be2d7fe 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -354,6 +354,7 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb, flush |= (__force int)(flags ^ tcp_flag_word(th2)); flush |= skb->ip_summed != p->ip_summed; flush |= skb->csum_level != p->csum_level; + flush |= !pskb_may_pull(skb, skb_gro_offset(skb)); flush |= NAPI_GRO_CB(p)->count >= 64; skb_set_network_header(skb, skb_gro_receive_network_offset(skb)); -- 2.51.0 From 7cdbd6508ee5fe893169c25d43598829a6fecc1d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 25 Jan 2018 12:58:55 +0100 Subject: [PATCH 269/517] netfilter: nft_flow_offload: handle netdevice events from nf_flow_table Move the code that deals with device events to the core. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_flow_table_core.c | 22 +++++++++++++++++++ net/netfilter/nft_flow_offload.c | 35 +----------------------------- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index df72b0376970..54881f0e878a 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -658,6 +658,23 @@ static struct pernet_operations nf_flow_table_net_ops = { .exit_batch = nf_flow_table_pernet_exit, }; +static int nf_flow_table_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + + if (event != NETDEV_DOWN) + return NOTIFY_DONE; + + nf_flow_table_cleanup(dev); + + return NOTIFY_DONE; +} + +static struct notifier_block flow_offload_netdev_notifier = { + .notifier_call = nf_flow_table_netdev_event, +}; + static int __init nf_flow_table_module_init(void) { int ret; @@ -674,6 +691,10 @@ static int __init nf_flow_table_module_init(void) if (ret) goto out_bpf; + ret = register_netdevice_notifier(&flow_offload_netdev_notifier); + if (ret) + goto out_bpf; + return 0; out_bpf: @@ -685,6 +706,7 @@ static int __init nf_flow_table_module_init(void) static void __exit nf_flow_table_module_exit(void) { + unregister_netdevice_notifier(&flow_offload_netdev_notifier); nf_flow_table_offload_exit(); unregister_pernet_subsys(&nf_flow_table_net_ops); } diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index da9ebd00b198..a7611b8a7ca2 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -487,47 +487,14 @@ static struct nft_expr_type nft_flow_offload_type __read_mostly = { .owner = THIS_MODULE, }; -static int flow_offload_netdev_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - if (event != NETDEV_DOWN) - return NOTIFY_DONE; - - nf_flow_table_cleanup(dev); - - return NOTIFY_DONE; -} - -static struct notifier_block flow_offload_netdev_notifier = { - .notifier_call = flow_offload_netdev_event, -}; - static int __init nft_flow_offload_module_init(void) { - int err; - - err = register_netdevice_notifier(&flow_offload_netdev_notifier); - if (err) - goto err; - - err = nft_register_expr(&nft_flow_offload_type); - if (err < 0) - goto register_expr; - - return 0; - -register_expr: - unregister_netdevice_notifier(&flow_offload_netdev_notifier); -err: - return err; + return nft_register_expr(&nft_flow_offload_type); } static void __exit nft_flow_offload_module_exit(void) { nft_unregister_expr(&nft_flow_offload_type); - unregister_netdevice_notifier(&flow_offload_netdev_notifier); } module_init(nft_flow_offload_module_init); -- 2.51.0 From 508c09b7af27f9d86d0dd3621932d17b40731195 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 31 Aug 2023 21:48:38 +0200 Subject: [PATCH 270/517] netfilter: nf_tables: ignore -EOPNOTSUPP on flowtable device offload setup On many embedded devices, it is common to configure flowtable offloading for a mix of different devices, some of which have hardware offload support and some of which don't. The current code limits the ability of user space to properly set up such a configuration by only allowing adding devices with hardware offload support to a offload-enabled flowtable. Given that offload-enabled flowtables also imply fallback to pure software offloading, this limitation makes little sense. Fix it by not bailing out when the offload setup returns -EOPNOTSUPP Signed-off-by: Felix Fietkau --- net/netfilter/nf_tables_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 3028d388b293..3b94f0d3995c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -8666,7 +8666,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, err = flowtable->data.type->setup(&flowtable->data, hook->ops.dev, FLOW_BLOCK_BIND); - if (err < 0) + if (err < 0 && err != -EOPNOTSUPP) goto err_unregister_net_hooks; err = nf_register_net_hook(net, &hook->ops); -- 2.51.0 From 7c144c4befb80c567d4225bbd64484bbcaece728 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 21 Mar 2022 20:39:59 +0100 Subject: [PATCH 271/517] net: ethernet: mtk_eth_soc: enable threaded NAPI This can improve performance under load by ensuring that NAPI processing is not pinned on CPU 0. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 2a0be107b3d7..e51ca80b4f15 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -5148,6 +5148,8 @@ static int mtk_probe(struct platform_device *pdev) dev_err(eth->dev, "failed to allocated dummy device\n"); goto err_unreg_netdev; } + eth->dummy_dev->threaded = 1; + strcpy(eth->dummy_dev->name, "mtk_eth"); netif_napi_add(eth->dummy_dev, ð->tx_napi, mtk_napi_tx); netif_napi_add(eth->dummy_dev, ð->rx_napi, mtk_napi_rx); -- 2.51.0 From 6fce75728838d9ed2cea822d5558eb619d3fd80a Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 3 Nov 2025 15:49:57 +0100 Subject: [PATCH 272/517] generic: add detach callback to struct phy_driver lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867 Signed-off-by: Gabor Juhos --- drivers/net/phy/phy_device.c | 3 +++ include/linux/phy.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2e08d20a3cfb..6e81501e5687 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2037,6 +2037,9 @@ void phy_detach(struct phy_device *phydev) phydev->devlink = NULL; } + if (phydev->drv && phydev->drv->detach) + phydev->drv->detach(phydev); + if (phydev->sysfs_links) { if (dev) sysfs_remove_link(&dev->dev.kobj, "phydev"); diff --git a/include/linux/phy.h b/include/linux/phy.h index 85217937e489..b6c372ea4e2d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1027,6 +1027,12 @@ struct phy_driver { /** @handle_interrupt: Override default interrupt handling */ irqreturn_t (*handle_interrupt)(struct phy_device *phydev); + /* + * Called before an ethernet device is detached + * from the PHY. + */ + void (*detach)(struct phy_device *phydev); + /** @remove: Clears up any memory if needed */ void (*remove)(struct phy_device *phydev); -- 2.51.0 From b164fe2b20f203a4b1456889693c9855179251c5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 6 May 2022 21:38:42 +0200 Subject: [PATCH 273/517] net: dsa: tag_mtk: add padding for tx packets Padding for transmitted packets needs to account for the special tag. With not enough padding, garbage bytes are inserted by the switch at the end of small packets. Fixes: 5cd8985a1909 ("net-next: dsa: add Mediatek tag RX/TX handler") Signed-off-by: Felix Fietkau --- net/dsa/tag_mtk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c index b670e3c53e91..791f87349ba6 100644 --- a/net/dsa/tag_mtk.c +++ b/net/dsa/tag_mtk.c @@ -29,6 +29,13 @@ static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, skb_set_queue_mapping(skb, dp->index); + /* The Ethernet switch we are interfaced with needs packets to be at + * least 64 bytes (including FCS) otherwise their padding might be + * corrupted. With tags enabled, we need to make sure that packets are + * at least 68 bytes (including FCS and tag). + */ + eth_skb_pad(skb); + /* Build the special tag after the MAC Source Address. If VLAN header * is present, it's required that VLAN header and special tag is * being combined. Only in this way we can allow the switch can parse -- 2.51.0 From 3d059952a5f51a3ee562b27a845b860bdeba7869 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 8 Oct 2024 23:58:41 +0100 Subject: [PATCH 274/517] net: phy: populate host_interfaces when attaching PHY Use bitmask of interfaces supported by the MAC for the PHY to choose from if the declared interface mode is among those using a single pair of SerDes lanes. This will allow 2500Base-T PHYs to switch to SGMII on most hosts, which results in half-duplex being supported in case the MAC supports them. Without this change, 2500Base-T PHYs will always operate in 2500Base-X mode with rate-matching, which is not only wasteful in terms of energy consumption, but also limits the supported interface modes to full-duplex only. Signed-off-by: Daniel Golle --- drivers/net/phy/phylink.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ede93109f9c5..e168766e465e 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2264,7 +2264,7 @@ int phylink_fwnode_phy_connect(struct phylink *pl, { struct fwnode_handle *phy_fwnode; struct phy_device *phy_dev; - int ret; + int i, ret; /* Fixed links and 802.3z are handled without needing a PHY */ if (pl->cfg_link_an_mode == MLO_AN_FIXED || @@ -2294,6 +2294,25 @@ int phylink_fwnode_phy_connect(struct phylink *pl, if (pl->config->mac_requires_rxc) flags |= PHY_F_RXC_ALWAYS_ON; + /* Assume single-lane SerDes interface modes share the same + * lanes and allow the PHY to switch to slower also supported modes + */ + for (i = ARRAY_SIZE(phylink_sfp_interface_preference) - 1; i >= 0; i--) { + /* skip unsupported modes */ + if (!test_bit(phylink_sfp_interface_preference[i], pl->config->supported_interfaces)) + continue; + + __set_bit(phylink_sfp_interface_preference[i], phy_dev->host_interfaces); + + /* skip all faster modes */ + if (phylink_sfp_interface_preference[i] == pl->link_interface) + break; + } + + if (test_bit(pl->link_interface, phylink_sfp_interfaces)) + phy_interface_and(phy_dev->host_interfaces, phylink_sfp_interfaces, + pl->config->supported_interfaces); + ret = phy_attach_direct(pl->netdev, phy_dev, flags, pl->link_interface); phy_device_free(phy_dev); -- 2.51.0 From 71873c04d3b023c84d1292d6ac910270998aece5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 27 Aug 2021 12:22:32 +0200 Subject: [PATCH 275/517] bridge: add knob for filtering rx/tx BPDU packets on a port Some devices (e.g. wireless APs) can't have devices behind them be part of a bridge topology with redundant links, due to address limitations. Additionally, broadcast traffic on these devices is somewhat expensive, due to the low data rate and wakeups of clients in powersave mode. This knob can be used to ensure that BPDU packets are never sent or forwarded to/from these devices Signed-off-by: Felix Fietkau --- include/linux/if_bridge.h | 1 + include/uapi/linux/if_link.h | 1 + net/bridge/br_forward.c | 5 +++++ net/bridge/br_input.c | 2 ++ net/bridge/br_netlink.c | 6 +++++- net/bridge/br_stp_bpdu.c | 9 +++++++-- net/bridge/br_sysfs_if.c | 2 ++ net/core/rtnetlink.c | 6 ++++-- 8 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 3ff96ae31bf6..cff03a1dfd68 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -61,6 +61,7 @@ struct br_ip_list { #define BR_PORT_LOCKED BIT(21) #define BR_PORT_MAB BIT(22) #define BR_NEIGH_VLAN_SUPPRESS BIT(23) +#define BR_BPDU_FILTER BIT(24) #define BR_DEFAULT_AGEING_TIME (300 * HZ) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 2acc7687e017..493ca8617d33 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1094,6 +1094,7 @@ enum { IFLA_BRPORT_MCAST_MAX_GROUPS, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, IFLA_BRPORT_BACKUP_NHID, + IFLA_BRPORT_BPDU_FILTER, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index e19b583ff2c6..20925747f36e 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -201,6 +201,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, enum br_pkt_type pkt_type, bool local_rcv, bool local_orig, u16 vid) { + const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *prev = NULL; struct net_bridge_port *p; @@ -218,6 +219,10 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, case BR_PKT_MULTICAST: if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) continue; + if ((p->flags & BR_BPDU_FILTER) && + unlikely(is_link_local_ether_addr(dest) && + dest[5] == 0)) + continue; break; case BR_PKT_BROADCAST: if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 0332371d19ab..da0ccd6b0034 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -368,6 +368,8 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) fwd_mask |= p->group_fwd_mask; switch (dest[5]) { case 0x00: /* Bridge Group Address */ + if (p->flags & BR_BPDU_FILTER) + goto drop; /* If STP is turned off, then must forward to keep loop detection */ if (p->br->stp_enabled == BR_NO_STP || diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 6b97ae47f855..5a6fdf3f9c86 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -190,6 +190,7 @@ static inline size_t br_port_info_size(void) + nla_total_size(1) /* IFLA_BRPORT_LOCKED */ + nla_total_size(1) /* IFLA_BRPORT_MAB */ + nla_total_size(1) /* IFLA_BRPORT_NEIGH_VLAN_SUPPRESS */ + + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */ + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ @@ -282,7 +283,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) || nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) || nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, - !!(p->flags & BR_NEIGH_VLAN_SUPPRESS))) + !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)) || + nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER))) return -EMSGSIZE; timerval = br_timer_value(&p->message_age_timer); @@ -902,6 +904,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { [IFLA_BRPORT_MCAST_MAX_GROUPS] = { .type = NLA_U32 }, [IFLA_BRPORT_NEIGH_VLAN_SUPPRESS] = NLA_POLICY_MAX(NLA_U8, 1), [IFLA_BRPORT_BACKUP_NHID] = { .type = NLA_U32 }, + [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 }, }; /* Change the state of the port and notify spanning tree */ @@ -970,6 +973,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[], br_set_port_flag(p, tb, IFLA_BRPORT_MAB, BR_PORT_MAB); br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, BR_NEIGH_VLAN_SUPPRESS); + br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER); if ((p->flags & BR_PORT_MAB) && (!(p->flags & BR_PORT_LOCKED) || !(p->flags & BR_LEARNING))) { diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 7895489ac6fe..34c7ae7c9d63 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) { unsigned char buf[35]; - if (p->br->stp_enabled != BR_KERNEL_STP) + if (p->br->stp_enabled != BR_KERNEL_STP || + (p->flags & BR_BPDU_FILTER)) return; buf[0] = 0; @@ -127,7 +128,8 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) { unsigned char buf[4]; - if (p->br->stp_enabled != BR_KERNEL_STP) + if (p->br->stp_enabled != BR_KERNEL_STP || + (p->flags & BR_BPDU_FILTER)) return; buf[0] = 0; @@ -172,6 +174,9 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, if (!(br->dev->flags & IFF_UP)) goto out; + if (p->flags & BR_BPDU_FILTER) + goto out; + if (p->state == BR_STATE_DISABLED) goto out; diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 74fdd8105dca..aee7c5902206 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -240,6 +240,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD); BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); BRPORT_ATTR_FLAG(isolated, BR_ISOLATED); +BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER); #ifdef CONFIG_BRIDGE_IGMP_SNOOPING static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) @@ -292,6 +293,7 @@ static const struct brport_attribute *brport_attrs[] = { &brport_attr_group_fwd_mask, &brport_attr_neigh_suppress, &brport_attr_isolated, + &brport_attr_bpdu_filter, &brport_attr_backup_port, NULL }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4d0ee1c9002a..e88f76b7ff00 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -62,7 +62,7 @@ #include "dev.h" #define RTNL_MAX_TYPE 50 -#define RTNL_SLAVE_MAX_TYPE 44 +#define RTNL_SLAVE_MAX_TYPE 45 struct rtnl_link { rtnl_doit_func doit; @@ -5012,7 +5012,9 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, brport_nla_put_flag(skb, flags, mask, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) { + IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD) || + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER)) { nla_nest_cancel(skb, protinfo); goto nla_put_failure; } -- 2.51.0 From a76fd2c1b182f24e3594eb106794b778f7287f1d Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 4 Jul 2023 22:50:12 +0200 Subject: [PATCH 276/517] net: dsa: qca8k: implement lag_fdb_add/del ops Implement lag_fdb_add/del ops to correctly support using LAG interface. Qca8k switch supports declaring fdb entry for link aggregation by simply setting the DES_PORT bits to all the LAG member. Signed-off-by: Christian Marangi --- drivers/net/dsa/qca/qca8k-8xxx.c | 2 ++ drivers/net/dsa/qca/qca8k-common.c | 36 ++++++++++++++++++++++++++++++ drivers/net/dsa/qca/qca8k.h | 6 +++++ 3 files changed, 44 insertions(+) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 59b4a7240b58..de3d1227d1ae 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -2031,6 +2031,8 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .port_fdb_add = qca8k_port_fdb_add, .port_fdb_del = qca8k_port_fdb_del, .port_fdb_dump = qca8k_port_fdb_dump, + .lag_fdb_add = qca8k_lag_fdb_add, + .lag_fdb_del = qca8k_lag_fdb_del, .port_mdb_add = qca8k_port_mdb_add, .port_mdb_del = qca8k_port_mdb_del, .port_mirror_add = qca8k_port_mirror_add, diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 560c74c4ac3d..2194f706aed5 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -1234,6 +1234,42 @@ int qca8k_port_lag_leave(struct dsa_switch *ds, int port, return qca8k_lag_refresh_portmap(ds, port, lag, true); } +int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct dsa_port *dp; + u16 port_mask = 0; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = QCA8K_PORT_VID_DEF; + + dsa_lag_foreach_port(dp, ds->dst, &lag) + port_mask |= BIT(dp->index); + + return qca8k_port_fdb_insert(priv, addr, port_mask, vid); +} + +int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct dsa_port *dp; + u16 port_mask = 0; + + /* Set the vid to the port vlan id if no vid is set */ + if (!vid) + vid = QCA8K_PORT_VID_DEF; + + dsa_lag_foreach_port(dp, ds->dst, &lag) + port_mask |= BIT(dp->index); + + return qca8k_fdb_del(priv, addr, port_mask, vid); +} + int qca8k_read_switch_id(struct qca8k_priv *priv) { u32 val; diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index 3664a2e2f1f6..894bd1f1e123 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -592,5 +592,11 @@ int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, struct netlink_ext_ack *extack); int qca8k_port_lag_leave(struct dsa_switch *ds, int port, struct dsa_lag lag); +int qca8k_lag_fdb_add(struct dsa_switch *ds, struct dsa_lag lag, + const unsigned char *addr, u16 vid, + struct dsa_db db); +int qca8k_lag_fdb_del(struct dsa_switch *ds, struct dsa_lag lag, + const unsigned char *addr, u16 vid, + struct dsa_db db); #endif /* __QCA8K_H */ -- 2.51.0 From 1ab637936c9a5b4385ad741d2228accb5d12580e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 20 Jun 2023 21:48:24 +0200 Subject: [PATCH 277/517] net: dsa: qca8k: enable flooding to both CPU port To permit a multi-CPU setup, flood all unknown frames to all CPU ports. Each CPU port should have correct LOOKUP MEMBER configuration to prevent receiving duplicate packets from user ports. Signed-off-by: Christian Marangi --- drivers/net/dsa/qca/qca8k-8xxx.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index de3d1227d1ae..552feb99d33c 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1913,15 +1913,12 @@ qca8k_setup(struct dsa_switch *ds) } } - /* Forward all unknown frames to CPU port for Linux processing - * Notice that in multi-cpu config only one port should be set - * for igmp, unknown, multicast and broadcast packet - */ + /* Forward all unknown frames to CPU port for Linux processing */ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, - FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | - FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | - FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | - FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, dsa_cpu_ports(ds)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, dsa_cpu_ports(ds)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, dsa_cpu_ports(ds)) | + FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, dsa_cpu_ports(ds))); if (ret) return ret; -- 2.51.0 From 5b32eeb255186bab8c0dc100a1b31b671bb89b69 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 20 Jun 2023 07:57:38 +0200 Subject: [PATCH 278/517] net: dsa: qca8k: add support for port_change_master Add support for port_change_master to permit assigning an alternative CPU port if the switch have both CPU port connected or create a LAG on both CPU port and assign the LAG as DSA master. On port change master request, we check if the master is a LAG. With LAG we compose the cpu_port_mask with the CPU port in the LAG, if master is a simple dsa_port, we derive the index. Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit the port to receive packet by the new CPU port setup for the port and we refresh the CPU ports LOOKUP MEMBER configuration to reflect the new user port state. port_lag_join/leave is updated to refresh the user ports if we detect that the LAG is a DSA master and we have user port using it as a master. Signed-off-by: Christian Marangi --- drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 552feb99d33c..aad8a20e72c7 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1750,6 +1750,117 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port, return DSA_TAG_PROTO_QCA; } +static int qca8k_port_change_master(struct dsa_switch *ds, int port, + struct net_device *master, + struct netlink_ext_ack *extack) +{ + struct dsa_switch_tree *dst = ds->dst; + struct qca8k_priv *priv = ds->priv; + u8 cpu_port_mask = 0; + struct dsa_port *dp; + u32 val; + int ret; + + /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */ + if (netif_is_lag_master(master)) { + struct dsa_lag *lag; + int id; + + id = dsa_lag_id(dst, master); + lag = dsa_lag_by_id(dst, id); + + dsa_lag_foreach_port(dp, dst, lag) + if (dsa_port_is_cpu(dp)) + cpu_port_mask |= BIT(dp->index); + } else { + dp = master->dsa_ptr; + cpu_port_mask |= BIT(dp->index); + } + + /* Connect port to new cpu port */ + ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val); + if (ret) + return ret; + + /* Reset connected CPU port in port LOOKUP MEMBER */ + val &= ~dsa_cpu_ports(ds); + /* Assign the new CPU port in port LOOKUP MEMBER */ + val |= cpu_port_mask; + + ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), + QCA8K_PORT_LOOKUP_MEMBER, + val); + if (ret) + return ret; + + /* Refresh CPU port LOOKUP MEMBER with new port */ + dsa_tree_for_each_cpu_port(dp, ds->dst) { + u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index); + + /* If CPU port in mask assign port, else remove port */ + if (BIT(dp->index) & cpu_port_mask) + ret = regmap_set_bits(priv->regmap, reg, BIT(port)); + else + ret = regmap_clear_bits(priv->regmap, reg, BIT(port)); + + if (ret) + return ret; + } + + return 0; +} + +static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds, + struct dsa_lag lag) +{ + struct net_device *lag_dev = lag.dev; + struct dsa_port *dp; + int ret; + + /* Ignore if LAG is not a DSA master */ + if (!netif_is_lag_master(lag_dev)) + return 0; + + dsa_switch_for_each_user_port(dp, ds) { + /* Skip if assigned master is not the LAG */ + if (dsa_port_to_conduit(dp) != lag_dev) + continue; + + ret = qca8k_port_change_master(ds, dp->index, + lag_dev, NULL); + if (ret) + return ret; + } + + return 0; +} + +static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port, + struct dsa_lag lag, + struct netdev_lag_upper_info *info, + struct netlink_ext_ack *extack) +{ + int ret; + + ret = qca8k_port_lag_join(ds, port, lag, info, extack); + if (ret) + return ret; + + return qca8k_port_lag_refresh_user_ports(ds, lag); +} + +static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port, + struct dsa_lag lag) +{ + int ret; + + ret = qca8k_port_lag_leave(ds, port, lag); + if (ret) + return ret; + + return qca8k_port_lag_refresh_user_ports(ds, lag); +} + static void qca8k_conduit_change(struct dsa_switch *ds, const struct net_device *conduit, bool operational) @@ -2039,8 +2150,9 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .port_vlan_del = qca8k_port_vlan_del, .phylink_get_caps = qca8k_phylink_get_caps, .get_phy_flags = qca8k_get_phy_flags, - .port_lag_join = qca8k_port_lag_join, - .port_lag_leave = qca8k_port_lag_leave, + .port_lag_join = qca8xxx_port_lag_join, + .port_lag_leave = qca8xxx_port_lag_leave, + .port_change_conduit = qca8k_port_change_master, .conduit_state_change = qca8k_conduit_change, .connect_tag_protocol = qca8k_connect_tag_protocol, }; -- 2.51.0 From d4996d68368205d76f6d715a69bf755bc441e721 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 6 Oct 2023 12:44:00 +0200 Subject: [PATCH 279/517] net: dsa: qca8k: enable assisted learning on CPU port Enable assisted learning on CPU port. It has been verified that there is a problem in packet roaming from one BSS to another in the same security settings from one physical R7800 to another physical R7800 where they are in the same L2 broadcast domain backhauled/linked together via one of the ethernet ports. DHCP will fail to complete and traffic cannot flow for around 300 seconds. Signed-off-by: Christian Marangi --- drivers/net/dsa/qca/qca8k-8xxx.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index aad8a20e72c7..de56bbc09cf9 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -2022,6 +2022,12 @@ qca8k_setup(struct dsa_switch *ds) dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index); return ret; } + + /* Disable learning by default on all ports */ + ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(dp->index), + QCA8K_PORT_LOOKUP_LEARN); + if (ret) + return ret; } /* Forward all unknown frames to CPU port for Linux processing */ @@ -2051,11 +2057,6 @@ qca8k_setup(struct dsa_switch *ds) if (ret) return ret; - ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), - QCA8K_PORT_LOOKUP_LEARN); - if (ret) - return ret; - /* For port based vlans to work we need to set the * default egress vid */ @@ -2107,6 +2108,9 @@ qca8k_setup(struct dsa_switch *ds) /* Set max number of LAGs supported */ ds->num_lag_ids = QCA8K_NUM_LAGS; + /* HW learn on CPU port is limited and require manual setting */ + ds->assisted_learning_on_cpu_port = true; + return 0; } -- 2.51.0 From cf6f77006d285fcf40f251a7988911316d99c134 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 2 Apr 2023 23:56:16 +0100 Subject: [PATCH 280/517] net: phy: realtek: use genphy_soft_reset for 2.5G PHYs Some vendor bootloaders do weird things with those PHYs which result in link modes being reported wrongly. Start from a clean sheet by resetting the PHY. Reported-by: Yevhen Kolomeiko Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 114d219562f1..2d2ed0a9d360 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1675,6 +1675,7 @@ static struct phy_driver realtek_drvs[] = { }, { .name = "RTL8226 2.5Gbps PHY", .match_phy_device = rtl8226_match_phy_device, + .soft_reset = genphy_soft_reset, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, @@ -1685,6 +1686,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_match_phy_device, .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .soft_reset = genphy_soft_reset, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, @@ -1707,6 +1709,7 @@ static struct phy_driver realtek_drvs[] = { }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", + .soft_reset = genphy_soft_reset, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl822xb_config_init, @@ -1719,6 +1722,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", + .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -1732,6 +1736,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", + .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, @@ -1743,6 +1748,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", + .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -1756,6 +1762,7 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", + .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, .config_init = rtl822xb_config_init, .get_rate_matching = rtl822xb_get_rate_matching, -- 2.51.0 From d1c87314cf69950550a4c6e3a64c4c194006f502 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Apr 2023 01:21:57 +0300 Subject: [PATCH 281/517] net: phy: realtek: disable SGMII in-band AN for 2.5G PHYs MAC drivers don't use SGMII in-band autonegotiation unless told to do so in device tree using 'managed = "in-band-status"'. When using MDIO to access a PHY, in-band-status is unneeded as we have link-status via MDIO. Switch off SGMII in-band autonegotiation using magic values. Reported-by: Chen Minqiang Reported-by: Chukun Pan Reported-by: Yevhen Kolomeiko Tested-by: Yevhen Kolomeiko Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 34 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 2d2ed0a9d360..0b2ec2ee0cf3 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1035,8 +1035,8 @@ static int rtl822x_probe(struct phy_device *phydev) static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) { bool has_2500, has_sgmii; + int ret, val; u16 mode; - int ret; has_2500 = test_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->host_interfaces) || @@ -1078,18 +1078,42 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) RTL822X_VND1_SERDES_OPTION, RTL822X_VND1_SERDES_OPTION_MODE_MASK, mode); - if (gen1 || ret < 0) + if (ret < 0) return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); + if (!gen1) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); + if (ret < 0) + return ret; + } + + /* Disable SGMII AN */ + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0); if (ret < 0) return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455); + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3); if (ret < 0) return ret; - return phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020); + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 0x7587, + val, !(val & BIT(0)), 500, 100000, false); + if (ret < 0) + return ret; + + return 0; } static int rtl822x_config_init(struct phy_device *phydev) -- 2.51.0 From 1b0e9bd766fd803b1df1b13ed2d6e4ac159f20d5 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 22 Apr 2023 01:21:14 +0100 Subject: [PATCH 282/517] net: phy: realtek: make sure paged read is protected by mutex As we cannot rely on phy_read_paged function before the PHY is identified, the paged read in rtlgen_supports_2_5gbps needs to be open coded as it is being called by the match_phy_device function, ie. before .read_page and .write_page have been populated. Make sure it is also protected by the MDIO bus mutex and use rtl821x_write_page instead of 3 individually locked MDIO bus operations. Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 0b2ec2ee0cf3..3bd9d52ce109 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1343,9 +1343,11 @@ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) { int val; - phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); - val = phy_read(phydev, 0x13); - phy_write(phydev, RTL821x_PAGE_SELECT, 0); + mutex_lock(&phydev->mdio.bus->mdio_lock); + rtl821x_write_page(phydev, 0xa61); + val = __phy_read(phydev, 0x13); + rtl821x_write_page(phydev, 0); + mutex_unlock(&phydev->mdio.bus->mdio_lock); return val >= 0 && val & MDIO_PMA_SPEED_2_5G; } -- 2.51.0 From 6b913911a8983435f5435892606fe4e418b94f39 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 22 Apr 2023 03:26:01 +0100 Subject: [PATCH 283/517] net: phy: realtek: setup ALDPS on RTL822x Setup Link Down Power Saving Mode according the DTS property just like for RTL821x 1GE PHYs. Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 3bd9d52ce109..036b27ab244e 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -129,6 +129,10 @@ */ #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) +#define RTL8221B_PHYCR1 0xa430 +#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) +#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) + #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) @@ -1095,6 +1099,15 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) return ret; } + if (of_property_read_bool(phydev->mdio.dev.of_node, "realtek,aldps-enable")) + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, + RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); + else + ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, + RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); + if (ret < 0) + return ret; + /* Disable SGMII AN */ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2); if (ret < 0) -- 2.51.0 From 4bc0f42ffef605a9a323a18105c572a0f26b7cdd Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 30 Apr 2023 00:15:41 +0100 Subject: [PATCH 284/517] net: phy: realtek: detect early version of RTL8221B Early versions (?) of the RTL8221B PHY cannot be identified in a regular Clause-45 bus scan as the PHY doesn't report the implemented MMDs correctly but returns 0 instead. Implement custom identify function using the PKGID instead of iterating over the implemented MMDs. Signed-off-by: Daniel Golle [forward-port by @namiltd] Signed-off-by: Mieczyslaw Nalewaj --- drivers/net/phy/realtek/realtek_main.c | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 036b27ab244e..88beb4c5c9db 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1400,10 +1400,32 @@ static int rtl8226_match_phy_device(struct phy_device *phydev, static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, bool is_c45) { - if (phydev->is_c45) - return is_c45 && (id == phydev->c45_ids.device_ids[1]); - else + if (phydev->is_c45) { + u32 rid; + + if (!is_c45) + return 0; + + rid = phydev->c45_ids.device_ids[1]; + if ((rid == 0xffffffff) && phydev->mdio.bus->read_c45) { + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1); + if (val < 0) + return 0; + + rid = val << 16; + val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2); + if (val < 0) + return 0; + + rid |= val; + } + + return (id == rid); + } else { return !is_c45 && (id == phydev->phy_id); + } } static int rtl8221b_match_phy_device(struct phy_device *phydev, -- 2.51.0 From d501f6a78763e0dfdce00fed1842bdb93f06b306 Mon Sep 17 00:00:00 2001 From: Jianhui Zhao Date: Sun, 24 Sep 2023 22:15:00 +0800 Subject: [PATCH 285/517] net: phy: realtek: add interrupt support for RTL8221B This commit introduces interrupt support for RTL8221B. Signed-off-by: Jianhui Zhao --- drivers/net/phy/realtek/realtek_main.c | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 88beb4c5c9db..c4cd0df5f971 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1619,6 +1619,51 @@ static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int rtl8221b_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa4d4); + + return (err < 0) ? err : 0; +} + +static int rtl8221b_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = rtl8221b_ack_interrupt(phydev); + if (err) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x7ff); + } else { + err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0); + if (err) + return err; + + err = rtl8221b_ack_interrupt(phydev); + } + + return err; +} + +static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev) +{ + int err; + + err = rtl8221b_ack_interrupt(phydev); + if (err) { + phy_error(phydev); + return IRQ_NONE; + } + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), @@ -1783,6 +1828,8 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, @@ -1797,6 +1844,8 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device, .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, .config_init = rtl822xb_config_init, @@ -1809,6 +1858,8 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device, .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = genphy_soft_reset, .probe = rtl822x_probe, .get_features = rtl822x_get_features, @@ -1823,6 +1874,8 @@ static struct phy_driver realtek_drvs[] = { }, { .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device, .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)", + .config_intr = rtl8221b_config_intr, + .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, .config_init = rtl822xb_config_init, -- 2.51.0 From 9715b901b205b49e6d1a24c5915ffef7936afd23 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 23 Jan 2025 03:25:29 +0000 Subject: [PATCH 286/517] net: phy: realtek: mark existing MMDs as present When using Clause-45 mode to access RealTek RTL8221B 2.5G PHYs some versions of the PHY fail to report the MMDs present on the PHY. Mark MMDs PMAPMD, PCS and AN which are always existing according to the datasheet as present to fix that. Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index c4cd0df5f971..cd4c452508ae 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1259,6 +1259,9 @@ static int rtl822x_c45_get_features(struct phy_device *phydev) linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, phydev->supported); + phydev->c45_ids.mmds_present |= MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_AN; + return genphy_c45_pma_read_abilities(phydev); } -- 2.51.0 From 5348f3256a254426ca1fd4c6e828e2b5bd1913d9 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 30 Jan 2025 05:33:12 +0000 Subject: [PATCH 287/517] net: phy: realtek: work around broken SerDes For still unknown reasons the SerDes init sequence may sometimes time out because a self-clearing bit never clears, indicating the PHY has entered an unrecoverable error state. Work-around the issue by triggering a hardware reset and retry the setup sequence while warning the user that this has happened. This is really more of a work-around than a fix, and should be replaced by a better actual fix in future (hopefully). Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index cd4c452508ae..7620935988ce 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1139,6 +1139,22 @@ static int rtl822xb_config_init(struct phy_device *phydev) return rtl822x_set_serdes_option_mode(phydev, false); } +static int rtl822xb_config_init_war(struct phy_device *phydev) +{ + int ret; + + ret = rtl822xb_config_init(phydev); + + if (ret == -ETIMEDOUT) { + phydev_warn(phydev, "SerDes setup timed out, retrying\n"); + phy_device_reset(phydev, 1); + phy_device_reset(phydev, 0); + ret = rtl822xb_config_init(phydev); + } + + return ret; +} + static int rtl822xb_get_rate_matching(struct phy_device *phydev, phy_interface_t iface) { @@ -1851,7 +1867,7 @@ static struct phy_driver realtek_drvs[] = { .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, - .config_init = rtl822xb_config_init, + .config_init = rtl822xb_config_init_war, .get_rate_matching = rtl822xb_get_rate_matching, .get_features = rtl822x_c45_get_features, .config_aneg = rtl822x_c45_config_aneg, @@ -1881,7 +1897,7 @@ static struct phy_driver realtek_drvs[] = { .handle_interrupt = rtl8221b_handle_interrupt, .soft_reset = rtl822x_c45_soft_reset, .probe = rtl822x_probe, - .config_init = rtl822xb_config_init, + .config_init = rtl822xb_config_init_war, .get_rate_matching = rtl822xb_get_rate_matching, .get_features = rtl822x_c45_get_features, .config_aneg = rtl822x_c45_config_aneg, -- 2.51.0 From 90d35efb01b9a152f1409a9029eae2e344115750 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 30 Jan 2025 05:38:31 +0000 Subject: [PATCH 288/517] net: phy: realtek: disable MDIO broadcast RealTek's PHYs by default also listen on MDIO address 0 which is defined as broadcast address. This can lead to problems if there is an actual PHY (such as MT7981 built-in PHY) present at this address, as accessing that PHY may then confuse the RealTek PHY. Disabled listening on the MDIO broadcast address to avoid such problems. Signed-off-by: Daniel Golle --- drivers/net/phy/realtek/realtek_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 7620935988ce..d9455b8a3db7 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1050,6 +1050,11 @@ static int rtl822x_set_serdes_option_mode(struct phy_device *phydev, bool gen1) phydev->host_interfaces) || phydev->interface == PHY_INTERFACE_MODE_SGMII; + /* disable listening on MDIO broadcast address (0) */ + ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, 0xa430, BIT(13)); + if (ret < 0) + return ret; + /* fill in possible interfaces */ __assign_bit(PHY_INTERFACE_MODE_2500BASEX, phydev->possible_interfaces, has_2500); -- 2.51.0 From f90b4d719f26a1089016a54d8a675d44654649e1 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 20 Oct 2022 03:34:43 +0200 Subject: [PATCH 289/517] net: permit ieee80211_ptr even with no CFG82111 support Introduce a new flag CONFIG_CFG80211_HEADERS to compile in ieee80211_ptr even if CFG80211 support is not compiled in. This is needed for the backports project and for any downstream wireless driver that loads in the kernel dynamically. Signed-off-by: Christian Marangi --- include/linux/netdevice.h | 2 +- net/batman-adv/hard-interface.c | 2 +- net/wireless/Kconfig | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 35b886385f32..c0a26b22f590 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2224,7 +2224,7 @@ struct net_device { #if IS_ENABLED(CONFIG_AX25) struct ax25_dev __rcu *ax25_ptr; #endif -#if IS_ENABLED(CONFIG_CFG80211) +#if IS_ENABLED(CONFIG_CFG80211_HEADERS) struct wireless_dev *ieee80211_ptr; #endif #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 96a412beab2d..abfa4dc9e050 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -309,7 +309,7 @@ static bool batadv_is_cfg80211_netdev(struct net_device *net_device) if (!net_device) return false; -#if IS_ENABLED(CONFIG_CFG80211) +#if IS_ENABLED(CONFIG_CFG80211_HEADERS) /* cfg80211 drivers have to set ieee80211_ptr */ if (net_device->ieee80211_ptr) return true; diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 10345388ad13..c141a1b74240 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -26,6 +26,7 @@ config CFG80211 # using a different algorithm, though right now they shouldn't # (this is here rather than below to allow it to be a module) select CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS + select CFG80211_HEADERS help cfg80211 is the Linux wireless LAN (802.11) configuration API. Enable this if you have a wireless device. @@ -36,6 +37,9 @@ config CFG80211 When built as a module it will be called cfg80211. +config CFG80211_HEADERS + bool "cfg80211 - headers support" + if CFG80211 config NL80211_TESTMODE -- 2.51.0 From adbd719bddb099f80db240cd3d80788d7d76096a Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 27 Oct 2022 23:39:52 +0200 Subject: [PATCH 290/517] net: ethernet: mtk_eth_soc: compile out netsys v2 code on mt7621 Avoid some branches in the hot path on low-end devices with limited CPU power, and reduce code size Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 723475570ff7..232659c596c4 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -1344,6 +1344,22 @@ struct mtk_mac { /* the struct describing the SoC. these are declared in the soc_xyz.c files */ extern const struct of_device_id of_mtk_match[]; +#ifdef CONFIG_SOC_MT7621 +static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) +{ + return true; +} + +static inline bool mtk_is_netsys_v2_or_greater(struct mtk_eth *eth) +{ + return false; +} + +static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) +{ + return false; +} +#else static inline bool mtk_is_netsys_v1(struct mtk_eth *eth) { return eth->soc->version == 1; @@ -1358,6 +1374,7 @@ static inline bool mtk_is_netsys_v3_or_greater(struct mtk_eth *eth) { return eth->soc->version > 2; } +#endif static inline struct mtk_foe_entry * mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) -- 2.51.0 From 8586fb600da61306b61d7a714af292fbf5e1ce43 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 3 Nov 2022 12:38:49 +0100 Subject: [PATCH 291/517] net: ethernet: mtk_eth_soc: work around issue with sending small fragments When lots of frames are sent with a number of very small fragments, an internal FIFO can overflow, causing the DMA engine to lock up lock up and transmit attempts time out. Fix this on MT7986 by increasing the reserved FIFO space. Fix this on older chips by detecting the presence of small fragments and use skb_gso_segment + skb_linearize to deal with them. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 39 +++++++++++++++++++-- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index e51ca80b4f15..0ab06e1ce084 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "mtk_eth_soc.h" @@ -1607,12 +1608,28 @@ static void mtk_wake_queue(struct mtk_eth *eth) } } +static bool mtk_skb_has_small_frag(struct sk_buff *skb) +{ + int min_size = 16; + int i; + + if (skb_headlen(skb) < min_size) + return true; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) + return true; + + return false; +} + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; struct mtk_tx_ring *ring = ð->tx_ring; struct net_device_stats *stats = &dev->stats; + struct sk_buff *segs, *next; bool gso = false; int tx_num; @@ -1641,6 +1658,18 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } + if (mtk_is_netsys_v1(eth) && + skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { + segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); + if (IS_ERR(segs)) + goto drop; + + if (segs) { + consume_skb(skb); + skb = segs; + } + } + /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { if (skb_cow_head(skb, 0)) { @@ -1656,8 +1685,14 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) - goto drop; + skb_list_walk_safe(skb, skb, next) { + if ((mtk_is_netsys_v1(eth) && + mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || + mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { + stats->tx_dropped++; + dev_kfree_skb_any(skb); + } + } if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) netif_tx_stop_all_queues(dev); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 232659c596c4..45ca9c17683a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -278,7 +278,7 @@ #define MTK_CHK_DDONE_EN BIT(28) #define MTK_DMAD_WR_WDONE BIT(26) #define MTK_WCOMP_EN BIT(24) -#define MTK_RESV_BUF (0x40 << 16) +#define MTK_RESV_BUF (0x80 << 16) #define MTK_MUTLI_CNT (0x4 << 12) #define MTK_LEAKY_BUCKET_EN BIT(11) -- 2.51.0 From badd05196d60a325cb7fc144c802fb6354b219aa Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 Oct 2024 12:52:56 +0200 Subject: [PATCH 292/517] net: ethernet: mtk_eth_soc: optimize dma ring address/index calculation Since DMA descriptor sizes are all power of 2, we can avoid costly integer division in favor or simple shifts. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 112 +++++++++++--------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 6 +- 2 files changed, 62 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 0ab06e1ce084..ff25dba46922 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -43,6 +43,11 @@ MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); offsetof(struct mtk_hw_stats, xdp_stats.x) / \ sizeof(u64) } +#define RX_DESC_OFS(eth, i) \ + ((i) << (eth)->soc->rx.desc_shift) +#define TX_DESC_OFS(eth, i) \ + ((i) << (eth)->soc->tx.desc_shift) + static const struct mtk_reg_map mtk_reg_map = { .tx_irq_mask = 0x1a1c, .tx_irq_status = 0x1a18, @@ -1160,14 +1165,14 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) eth->scratch_ring = eth->sram_base; else eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, - cnt * soc->tx.desc_size, + TX_DESC_OFS(eth, cnt), ð->phy_scratch_ring, GFP_KERNEL); if (unlikely(!eth->scratch_ring)) return -ENOMEM; - phy_ring_tail = eth->phy_scratch_ring + soc->tx.desc_size * (cnt - 1); + phy_ring_tail = eth->phy_scratch_ring + TX_DESC_OFS(eth, cnt - 1); for (j = 0; j < DIV_ROUND_UP(soc->tx.fq_dma_size, MTK_FQ_DMA_LENGTH); j++) { len = min_t(int, cnt - j * MTK_FQ_DMA_LENGTH, MTK_FQ_DMA_LENGTH); @@ -1186,11 +1191,11 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) for (i = 0; i < len; i++) { struct mtk_tx_dma_v2 *txd; - txd = eth->scratch_ring + (j * MTK_FQ_DMA_LENGTH + i) * soc->tx.desc_size; + txd = eth->scratch_ring + TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i); txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; if (j * MTK_FQ_DMA_LENGTH + i < cnt) txd->txd2 = eth->phy_scratch_ring + - (j * MTK_FQ_DMA_LENGTH + i + 1) * soc->tx.desc_size; + TX_DESC_OFS(eth, j * MTK_FQ_DMA_LENGTH + i + 1); txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA)) @@ -1220,9 +1225,9 @@ static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) } static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, - void *txd, u32 txd_size) + void *txd, u32 txd_shift) { - int idx = (txd - ring->dma) / txd_size; + int idx = (txd - ring->dma) >> txd_shift; return &ring->buf[idx]; } @@ -1233,9 +1238,9 @@ static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, return ring->dma_pdma - (struct mtk_tx_dma *)ring->dma + dma; } -static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size) +static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_shift) { - return (dma - ring->dma) / txd_size; + return (dma - ring->dma) >> txd_shift; } static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, @@ -1443,7 +1448,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, if (itxd == ring->last_free) return -ENOMEM; - itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size); + itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); memset(itx_buf, 0, sizeof(*itx_buf)); txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, @@ -1497,7 +1502,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, mtk_tx_set_dma_desc(dev, txd, &txd_info); tx_buf = mtk_desc_to_tx_buf(ring, txd, - soc->tx.desc_size); + soc->tx.desc_shift); if (new_desc) memset(tx_buf, 0, sizeof(*tx_buf)); tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; @@ -1540,7 +1545,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, } else { int next_idx; - next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_size), + next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift), ring->dma_size); mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); } @@ -1549,7 +1554,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, err_dma: do { - tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_size); + tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); /* unmap dma */ mtk_tx_unmap(eth, tx_buf, NULL, false); @@ -1723,7 +1728,7 @@ static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) ring = ð->rx_ring[i]; idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); - rxd = ring->dma + idx * eth->soc->rx.desc_size; + rxd = ring->dma + RX_DESC_OFS(eth, idx); if (rxd->rxd2 & RX_DMA_DONE) { ring->calc_idx_update = true; return ring; @@ -1891,7 +1896,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, } htxd = txd; - tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_size); + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_shift); memset(tx_buf, 0, sizeof(*tx_buf)); htx_buf = tx_buf; @@ -1910,7 +1915,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, goto unmap; tx_buf = mtk_desc_to_tx_buf(ring, txd, - soc->tx.desc_size); + soc->tx.desc_shift); memset(tx_buf, 0, sizeof(*tx_buf)); n_desc++; } @@ -1948,7 +1953,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, } else { int idx; - idx = txd_to_idx(ring, txd, soc->tx.desc_size); + idx = txd_to_idx(ring, txd, soc->tx.desc_shift); mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), MT7628_TX_CTX_IDX0); } @@ -1959,7 +1964,7 @@ static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, unmap: while (htxd != txd) { - tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_size); + tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->tx.desc_shift); mtk_tx_unmap(eth, tx_buf, NULL, false); htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; @@ -2091,7 +2096,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, goto rx_done; idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); - rxd = ring->dma + idx * eth->soc->rx.desc_size; + rxd = ring->dma + RX_DESC_OFS(eth, idx); data = ring->data[idx]; if (!mtk_rx_get_desc(eth, &trxd, rxd)) @@ -2355,7 +2360,7 @@ static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, break; tx_buf = mtk_desc_to_tx_buf(ring, desc, - eth->soc->tx.desc_size); + eth->soc->tx.desc_shift); if (!tx_buf->data) break; @@ -2406,7 +2411,7 @@ static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, } mtk_tx_unmap(eth, tx_buf, &bq, true); - desc = ring->dma + cpu * eth->soc->tx.desc_size; + desc = ring->dma + TX_DESC_OFS(eth, cpu); ring->last_free = desc; atomic_inc(&ring->free_count); @@ -2524,7 +2529,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) { const struct mtk_soc_data *soc = eth->soc; struct mtk_tx_ring *ring = ð->tx_ring; - int i, sz = soc->tx.desc_size; + int i, sz = TX_DESC_OFS(eth, 1); struct mtk_tx_dma_v2 *txd; int ring_size; u32 ofs, val; @@ -2571,7 +2576,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) * descriptors in ring->dma_pdma. */ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz, + ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, TX_DESC_OFS(eth, ring_size), &ring->phys_pdma, GFP_KERNEL); if (!ring->dma_pdma) goto no_tx_mem; @@ -2586,7 +2591,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) atomic_set(&ring->free_count, ring_size - 2); ring->next_free = ring->dma; ring->last_free = (void *)txd; - ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz)); + ring->last_free_ptr = (u32)(ring->phys + TX_DESC_OFS(eth, ring_size - 1)); ring->thresh = MAX_SKB_FRAGS; /* make sure that all changes to the dma ring are flushed before we @@ -2598,7 +2603,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); mtk_w32(eth, - ring->phys + ((ring_size - 1) * sz), + ring->phys + TX_DESC_OFS(eth, ring_size - 1), soc->reg_map->qdma.crx_ptr); mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); @@ -2647,14 +2652,14 @@ static void mtk_tx_clean(struct mtk_eth *eth) } if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) { dma_free_coherent(eth->dma_dev, - ring->dma_size * soc->tx.desc_size, + TX_DESC_OFS(eth, ring->dma_size), ring->dma, ring->phys); ring->dma = NULL; } if (ring->dma_pdma) { dma_free_coherent(eth->dma_dev, - ring->dma_size * soc->tx.desc_size, + TX_DESC_OFS(eth, ring->dma_size), ring->dma_pdma, ring->phys_pdma); ring->dma_pdma = NULL; } @@ -2710,15 +2715,13 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) || rx_flag != MTK_RX_FLAGS_NORMAL) { ring->dma = dma_alloc_coherent(eth->dma_dev, - rx_dma_size * eth->soc->rx.desc_size, + RX_DESC_OFS(eth, rx_dma_size), &ring->phys, GFP_KERNEL); } else { struct mtk_tx_ring *tx_ring = ð->tx_ring; - ring->dma = tx_ring->dma + tx_ring_size * - eth->soc->tx.desc_size * (ring_no + 1); - ring->phys = tx_ring->phys + tx_ring_size * - eth->soc->tx.desc_size * (ring_no + 1); + ring->dma = tx_ring->dma + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1)); + ring->phys = tx_ring->phys + TX_DESC_OFS(eth, tx_ring_size * (ring_no + 1)); } if (!ring->dma) @@ -2729,7 +2732,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) dma_addr_t dma_addr; void *data; - rxd = ring->dma + i * eth->soc->rx.desc_size; + rxd = ring->dma + RX_DESC_OFS(eth, i); if (ring->page_pool) { data = mtk_page_pool_get_buff(ring->page_pool, &dma_addr, GFP_KERNEL); @@ -2820,7 +2823,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_ if (!ring->data[i]) continue; - rxd = ring->dma + i * eth->soc->rx.desc_size; + rxd = ring->dma + RX_DESC_OFS(eth, i); if (!rxd->rxd1) continue; @@ -2837,7 +2840,7 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_ if (!in_sram && ring->dma) { dma_free_coherent(eth->dma_dev, - ring->dma_size * eth->soc->rx.desc_size, + RX_DESC_OFS(eth, ring->dma_size), ring->dma, ring->phys); ring->dma = NULL; } @@ -3208,7 +3211,7 @@ static void mtk_dma_free(struct mtk_eth *eth) if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) { dma_free_coherent(eth->dma_dev, - MTK_QDMA_RING_SIZE * soc->tx.desc_size, + TX_DESC_OFS(eth, MTK_QDMA_RING_SIZE), eth->scratch_ring, eth->phy_scratch_ring); eth->scratch_ring = NULL; eth->phy_scratch_ring = 0; @@ -5236,6 +5239,9 @@ static void mtk_remove(struct platform_device *pdev) mtk_mdio_cleanup(eth); } +#define DESC_SIZE(struct_name) \ + .desc_shift = const_ilog2(sizeof(struct_name)) + static const struct mtk_soc_data mt2701_data = { .reg_map = &mtk_reg_map, .caps = MT7623_CAPS | MTK_HWLRO, @@ -5244,14 +5250,14 @@ static const struct mtk_soc_data mt2701_data = { .required_pctl = true, .version = 1, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, .dma_size = MTK_DMA_SIZE(2K), @@ -5272,14 +5278,14 @@ static const struct mtk_soc_data mt7621_data = { .hash_offset = 2, .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, .dma_size = MTK_DMA_SIZE(2K), @@ -5302,14 +5308,14 @@ static const struct mtk_soc_data mt7622_data = { .has_accounting = true, .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, .dma_size = MTK_DMA_SIZE(2K), @@ -5331,14 +5337,14 @@ static const struct mtk_soc_data mt7623_data = { .foe_entry_size = MTK_FOE_ENTRY_V1_SIZE, .disable_pll_modes = true, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, .dma_size = MTK_DMA_SIZE(2K), @@ -5357,14 +5363,14 @@ static const struct mtk_soc_data mt7629_data = { .has_accounting = true, .version = 1, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, .dma_size = MTK_DMA_SIZE(2K), @@ -5387,14 +5393,14 @@ static const struct mtk_soc_data mt7981_data = { .has_accounting = true, .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE, .tx = { - .desc_size = sizeof(struct mtk_tx_dma_v2), + DESC_SIZE(struct mtk_tx_dma_v2), .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, .dma_len_offset = 8, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID_V2, .dma_max_len = MTK_TX_DMA_BUF_LEN, @@ -5417,14 +5423,14 @@ static const struct mtk_soc_data mt7986_data = { .has_accounting = true, .foe_entry_size = MTK_FOE_ENTRY_V2_SIZE, .tx = { - .desc_size = sizeof(struct mtk_tx_dma_v2), + DESC_SIZE(struct mtk_tx_dma_v2), .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, .dma_len_offset = 8, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID_V2, .dma_max_len = MTK_TX_DMA_BUF_LEN, @@ -5447,14 +5453,14 @@ static const struct mtk_soc_data mt7988_data = { .has_accounting = true, .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE, .tx = { - .desc_size = sizeof(struct mtk_tx_dma_v2), + DESC_SIZE(struct mtk_tx_dma_v2), .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, .dma_len_offset = 8, .dma_size = MTK_DMA_SIZE(2K), .fq_dma_size = MTK_DMA_SIZE(4K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma_v2), + DESC_SIZE(struct mtk_rx_dma_v2), .irq_done_mask = MTK_RX_DONE_INT_V2, .dma_l4_valid = RX_DMA_L4_VALID_V2, .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, @@ -5471,13 +5477,13 @@ static const struct mtk_soc_data rt5350_data = { .required_pctl = false, .version = 1, .tx = { - .desc_size = sizeof(struct mtk_tx_dma), + DESC_SIZE(struct mtk_tx_dma), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, .dma_size = MTK_DMA_SIZE(2K), }, .rx = { - .desc_size = sizeof(struct mtk_rx_dma), + DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID_PDMA, .dma_max_len = MTK_TX_DMA_BUF_LEN, diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 45ca9c17683a..b4699cdd65fa 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -1160,7 +1160,7 @@ struct mtk_reg_map { * @foe_entry_size Foe table entry size. * @has_accounting Bool indicating support for accounting of * offloaded flows. - * @desc_size Tx/Rx DMA descriptor size. + * @desc_shift Tx/Rx DMA descriptor size (in power-of-2). * @irq_done_mask Rx irq done register mask. * @dma_l4_valid Rx DMA valid register mask. * @dma_max_len Max DMA tx/rx buffer length. @@ -1181,14 +1181,14 @@ struct mtk_soc_data { bool has_accounting; bool disable_pll_modes; struct { - u32 desc_size; + u32 desc_shift; u32 dma_max_len; u32 dma_len_offset; u32 dma_size; u32 fq_dma_size; } tx; struct { - u32 desc_size; + u32 desc_shift; u32 irq_done_mask; u32 dma_l4_valid; u32 dma_max_len; -- 2.51.0 From 83c9e69493e9c550f16796ba7ca7859d07e50159 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 14 Jul 2025 10:52:59 +0200 Subject: [PATCH 293/517] net: ethernet: mtk_eth_soc: shrink struct mtk_tx_buf There is no need to track the difference between dma_map_page and dma_map_single, since they're unmapped in exactly the same way. Also reorder fields in order to avoid padding. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 42 ++++++--------------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 +------ 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index ff25dba46922..1d64979195c1 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1246,32 +1246,19 @@ static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_shift) static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, struct xdp_frame_bulk *bq, bool napi) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { - if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { - dma_unmap_single(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { - dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } - } else { - if (dma_unmap_len(tx_buf, dma_len0)) { - dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } + if (dma_unmap_len(tx_buf, dma_len0)) { + dma_unmap_page(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } - if (dma_unmap_len(tx_buf, dma_len1)) { - dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr1), - dma_unmap_len(tx_buf, dma_len1), - DMA_TO_DEVICE); - } + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) && + dma_unmap_len(tx_buf, dma_len1)) { + dma_unmap_page(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr1), + dma_unmap_len(tx_buf, dma_len1), + DMA_TO_DEVICE); } if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { @@ -1293,7 +1280,6 @@ static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, xdp_return_frame(xdpf); } } - tx_buf->flags = 0; tx_buf->data = NULL; } @@ -1458,7 +1444,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, mtk_tx_set_dma_desc(dev, itxd, &txd_info); - itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; itx_buf->mac_id = mac->id; setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, k++); @@ -1506,7 +1491,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, if (new_desc) memset(tx_buf, 0, sizeof(*tx_buf)); tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; - tx_buf->flags |= MTK_TX_FLAGS_PAGE0; tx_buf->mac_id = mac->id; setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, @@ -1839,8 +1823,6 @@ static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, txd_info->size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) return -ENOMEM; - - tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; } else { struct page *page = virt_to_head_page(data); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index b4699cdd65fa..b5aad9a7360c 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -701,14 +701,6 @@ struct mtk_hw_stats { struct u64_stats_sync syncp; }; -enum mtk_tx_flags { - /* PDMA descriptor can point at 1-2 segments. This enum allows us to - * track how memory was allocated so that it can be freed properly. - */ - MTK_TX_FLAGS_SINGLE0 = 0x01, - MTK_TX_FLAGS_PAGE0 = 0x02, -}; - /* This enum allows us to identify how the clock is defined on the array of the * clock in the order */ @@ -881,13 +873,12 @@ enum mtk_tx_buf_type { */ struct mtk_tx_buf { enum mtk_tx_buf_type type; + u16 mac_id; void *data; - u16 mac_id; - u16 flags; DEFINE_DMA_UNMAP_ADDR(dma_addr0); - DEFINE_DMA_UNMAP_LEN(dma_len0); DEFINE_DMA_UNMAP_ADDR(dma_addr1); + DEFINE_DMA_UNMAP_LEN(dma_len0); DEFINE_DMA_UNMAP_LEN(dma_len1); }; -- 2.51.0 From 930617345e8d124cf3ae225a46476dc20d03b264 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 14 Jul 2025 10:41:27 +0200 Subject: [PATCH 294/517] net: ethernet: mtk_eth_soc: add support for sending fraglist GSO packets When primarily forwarding traffic, TCP fraglist GRO can be noticeably more efficient than regular TCP GRO. In order to avoid the overhead of unnecessary segmentation on ethernet tx, add support for sending fraglist GRO packets. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 355 ++++++++++++++------ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + 2 files changed, 259 insertions(+), 98 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 1d64979195c1..98266707bc22 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include "mtk_eth_soc.h" @@ -1404,119 +1407,244 @@ static void mtk_tx_set_dma_desc(struct net_device *dev, void *txd, mtk_tx_set_dma_desc_v1(dev, txd, info); } +struct mtk_tx_map_state { + struct mtk_tx_dma *txd, *txd_pdma; + struct mtk_tx_buf *tx_buf; + int nbuf; + int ndesc; +}; + +static void +mtk_tx_map_set_txd(struct mtk_tx_map_state *state, struct mtk_tx_ring *ring, + const struct mtk_soc_data *soc, struct mtk_tx_dma *txd) +{ + state->txd = txd; + state->txd_pdma = qdma_to_pdma(ring, txd); + state->tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->tx.desc_shift); + memset(state->tx_buf, 0, sizeof(*state->tx_buf)); +} + +static int +mtk_tx_map_info(struct mtk_eth *eth, struct mtk_tx_ring *ring, + struct net_device *dev, struct mtk_tx_map_state *state, + struct mtk_tx_dma_desc_info *txd_info) +{ + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_buf *tx_buf = state->tx_buf; + struct mtk_tx_dma *txd = state->txd; + struct mtk_mac *mac = netdev_priv(dev); + + if (state->nbuf && + (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (state->nbuf & 1) == 0)) { + txd = mtk_qdma_phys_to_virt(ring, txd->txd2); + if (txd == ring->last_free) + return -1; + + mtk_tx_map_set_txd(state, ring, soc, txd); + state->ndesc++; + } + + mtk_tx_set_dma_desc(dev, txd, txd_info); + tx_buf = state->tx_buf; + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + tx_buf->mac_id = mac->id; + + setup_tx_buf(eth, tx_buf, state->txd_pdma, txd_info->addr, + txd_info->size, state->nbuf++); + return 0; +} + +static void +mtk_tx_update_ipaddr(struct sk_buff *skb, + struct iphdr *iph, struct tcphdr *th, + __be32 *old_ip, __be32 new_ip) +{ + if (*old_ip == new_ip) + return; + + inet_proto_csum_replace4(&th->check, skb, *old_ip, new_ip, true); + csum_replace4(&iph->check, *old_ip, new_ip); + *old_ip = new_ip; +} + +static void +mtk_tx_update_ip6addr(struct sk_buff *skb, struct ipv6hdr *iph, + struct tcphdr *th, struct in6_addr *old_ip, + const struct in6_addr *new_ip) +{ + if (ipv6_addr_equal(old_ip, new_ip)) + return; + + inet_proto_csum_replace16(&th->check, skb, old_ip->s6_addr32, + new_ip->s6_addr32, true); + *old_ip = *new_ip; +} + +static void +mtk_tx_update_port(struct sk_buff *skb, struct tcphdr *th, + __be16 *old_port, __be16 new_port) +{ + if (*old_port == new_port) + return; + + inet_proto_csum_replace2(&th->check, skb, *old_port, new_port, false); + *old_port = new_port; +} + static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, - int tx_num, struct mtk_tx_ring *ring, bool gso) + int tx_num, struct mtk_tx_ring *ring, bool gso, + unsigned int header_len) { - struct mtk_tx_dma_desc_info txd_info = { - .size = skb_headlen(skb), - .gso = gso, - .csum = skb->ip_summed == CHECKSUM_PARTIAL, - .vlan = skb_vlan_tag_present(skb), - .qid = skb_get_queue_mapping(skb), - .vlan_tci = skb_vlan_tag_get(skb), - .first = true, - .last = !skb_is_nonlinear(skb), + struct mtk_tx_dma_desc_info txd_info; + struct mtk_tx_map_state state = { + .ndesc = 1, }; struct netdev_queue *txq; struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_dma *itxd, *txd; - struct mtk_tx_dma *itxd_pdma, *txd_pdma; - struct mtk_tx_buf *itx_buf, *tx_buf; - int i, n_desc = 1; + struct mtk_tx_dma *itxd; + struct sk_buff *cur_skb, *next_skb; int queue = skb_get_queue_mapping(skb); - int k = 0; + int offset = 0; + int i, frag_size; + bool gso_v4; txq = netdev_get_tx_queue(dev, queue); itxd = ring->next_free; - itxd_pdma = qdma_to_pdma(ring, itxd); if (itxd == ring->last_free) return -ENOMEM; - itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); - memset(itx_buf, 0, sizeof(*itx_buf)); + cur_skb = skb; + next_skb = skb_shinfo(skb)->frag_list; + mtk_tx_map_set_txd(&state, ring, soc, itxd); + gso_v4 = skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4; - txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, - DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) - return -ENOMEM; +next: + txd_info = (struct mtk_tx_dma_desc_info){ + .gso = gso, + .qid = queue, + .csum = cur_skb->ip_summed == CHECKSUM_PARTIAL || gso, + .vlan = skb_vlan_tag_present(skb), + .vlan_tci = skb_vlan_tag_get(skb), + .first = true, + }; - mtk_tx_set_dma_desc(dev, itxd, &txd_info); + offset = 0; + frag_size = skb_headlen(cur_skb); + if (cur_skb != skb) { + struct tcphdr *th, *th2; - itx_buf->mac_id = mac->id; - setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, - k++); + if (skb_cow_head(cur_skb, header_len)) + goto err_dma; - /* TX SG offload */ - txd = itxd; - txd_pdma = qdma_to_pdma(ring, txd); + memcpy(cur_skb->data - header_len, skb->data, + skb_network_offset(skb)); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - unsigned int offset = 0; - int frag_size = skb_frag_size(frag); + th = tcp_hdr(cur_skb); + th2 = tcp_hdr(skb); + if (gso_v4) { + struct iphdr *iph = ip_hdr(cur_skb); + struct iphdr *iph2 = ip_hdr(skb); - while (frag_size) { - bool new_desc = true; + mtk_tx_update_ipaddr(skb, iph, th, &iph->saddr, + iph2->saddr); + mtk_tx_update_ipaddr(skb, iph, th, &iph->daddr, + iph2->daddr); + } else { + struct ipv6hdr *iph = ipv6_hdr(cur_skb); + struct ipv6hdr *iph2 = ipv6_hdr(skb); - if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || - (i & 0x1)) { - txd = mtk_qdma_phys_to_virt(ring, txd->txd2); - txd_pdma = qdma_to_pdma(ring, txd); - if (txd == ring->last_free) - goto err_dma; + mtk_tx_update_ip6addr(skb, iph, th, &iph->saddr, + &iph2->saddr); + mtk_tx_update_ip6addr(skb, iph, th, &iph->daddr, + &iph2->daddr); + } - n_desc++; - } else { - new_desc = false; - } + mtk_tx_update_port(skb, th, &th->source, th2->source); + mtk_tx_update_port(skb, th, &th->dest, th2->dest); - memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); + offset = -header_len; + frag_size += header_len; + } else if (next_skb) { + unsigned int ip_len = skb_pagelen(skb) - skb_network_offset(skb); + if (gso_v4) { + struct iphdr *iph = ip_hdr(cur_skb); + __be16 ip_len_val = cpu_to_be16(ip_len); + + csum_replace2(&iph->check, iph->tot_len, ip_len_val); + iph->tot_len = ip_len_val; + } else { + struct ipv6hdr *iph = ipv6_hdr(cur_skb); + __be16 ip_len_val = cpu_to_be16(ip_len - sizeof(*iph)); + + iph->payload_len = ip_len_val; + } + } + + while (frag_size) { + txd_info.size = min_t(unsigned int, frag_size, + soc->tx.dma_max_len); + txd_info.addr = dma_map_single(eth->dma_dev, cur_skb->data + offset, + txd_info.size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) + goto err_dma; + + frag_size -= txd_info.size; + offset += txd_info.size; + txd_info.last = !frag_size && !skb_shinfo(cur_skb)->nr_frags; + if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0) + goto err_dma; + } + + for (i = 0; i < skb_shinfo(cur_skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(cur_skb)->frags[i]; + + frag_size = skb_frag_size(frag); + memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); + txd_info.qid = queue; + offset = 0; + while (frag_size) { txd_info.size = min_t(unsigned int, frag_size, soc->tx.dma_max_len); - txd_info.qid = queue; - txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && - !(frag_size - txd_info.size); - txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, - offset, txd_info.size, - DMA_TO_DEVICE); + txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, offset, + txd_info.size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) goto err_dma; - mtk_tx_set_dma_desc(dev, txd, &txd_info); - - tx_buf = mtk_desc_to_tx_buf(ring, txd, - soc->tx.desc_shift); - if (new_desc) - memset(tx_buf, 0, sizeof(*tx_buf)); - tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; - tx_buf->mac_id = mac->id; - - setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, - txd_info.size, k++); - frag_size -= txd_info.size; offset += txd_info.size; + txd_info.last = i == skb_shinfo(cur_skb)->nr_frags - 1 && + !frag_size; + if (mtk_tx_map_info(eth, ring, dev, &state, &txd_info) < 0) + goto err_dma; } } - /* store skb to cleanup */ - itx_buf->type = MTK_TYPE_SKB; - itx_buf->data = skb; - if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - if (k & 0x1) - txd_pdma->txd2 |= TX_DMA_LS0; - else - txd_pdma->txd2 |= TX_DMA_LS1; + if (state.nbuf & 0x1) { + state.txd_pdma->txd2 |= TX_DMA_LS0; + state.nbuf++; + } else { + state.txd_pdma->txd2 |= TX_DMA_LS1; + } + } + + if (next_skb) { + cur_skb = next_skb; + next_skb = cur_skb->next; + goto next; } + /* store skb to cleanup */ + state.tx_buf->type = MTK_TYPE_SKB; + state.tx_buf->data = skb; + netdev_tx_sent_queue(txq, skb->len); skb_tx_timestamp(skb); - ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); - atomic_sub(n_desc, &ring->free_count); + ring->next_free = mtk_qdma_phys_to_virt(ring, state.txd->txd2); + atomic_sub(state.ndesc, &ring->free_count); /* make sure that all changes to the dma ring are flushed before we * continue @@ -1525,11 +1653,11 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { if (netif_xmit_stopped(txq) || !netdev_xmit_more()) - mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); + mtk_w32(eth, state.txd->txd2, soc->reg_map->qdma.ctx_ptr); } else { int next_idx; - next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->tx.desc_shift), + next_idx = NEXT_DESP_IDX(txd_to_idx(ring, state.txd, soc->tx.desc_shift), ring->dma_size); mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); } @@ -1538,18 +1666,20 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, err_dma: do { - tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); + struct mtk_tx_dma *itxd_pdma = qdma_to_pdma(ring, itxd); + struct mtk_tx_buf *itx_buf; + + itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->tx.desc_shift); /* unmap dma */ - mtk_tx_unmap(eth, tx_buf, NULL, false); + mtk_tx_unmap(eth, itx_buf, NULL, false); itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) itxd_pdma->txd2 = TX_DMA_DESP2_DEF; itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); - itxd_pdma = qdma_to_pdma(ring, itxd); - } while (itxd != txd); + } while (itxd != state.txd); return -ENOMEM; } @@ -1569,6 +1699,9 @@ static int mtk_cal_txd_req(struct mtk_eth *eth, struct sk_buff *skb) nfrags += skb_shinfo(skb)->nr_frags; } + for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) + nfrags += mtk_cal_txd_req(eth, skb) + 1; + return nfrags; } @@ -1609,9 +1742,29 @@ static bool mtk_skb_has_small_frag(struct sk_buff *skb) if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) return true; + for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) + if (mtk_skb_has_small_frag(skb)) + return true; + return false; } +static bool mtk_skb_valid_gso(struct mtk_eth *eth, struct sk_buff *skb, + unsigned int header_len) +{ + if (mtk_is_netsys_v1(eth) && mtk_skb_has_small_frag(skb)) + return false; + + if (!(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)) + return true; + + if (skb_tnl_header_len(skb)) + return false; + + return skb_pagelen(skb) - header_len == skb_shinfo(skb)->gso_size && + skb_headlen(skb) > header_len; +} + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); @@ -1619,6 +1772,7 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) struct mtk_tx_ring *ring = ð->tx_ring; struct net_device_stats *stats = &dev->stats; struct sk_buff *segs, *next; + unsigned int header_len = 0; bool gso = false; int tx_num; @@ -1647,37 +1801,42 @@ static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - if (mtk_is_netsys_v1(eth) && - skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { - segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); - if (IS_ERR(segs)) - goto drop; - - if (segs) { - consume_skb(skb); - skb = segs; - } - } - - /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { - if (skb_cow_head(skb, 0)) { - netif_warn(eth, tx_err, dev, - "GSO expand head fail.\n"); - goto drop; + header_len = skb_tcp_all_headers(skb); + if (!mtk_skb_valid_gso(eth, skb, header_len)) { + segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); + if (IS_ERR(segs)) + goto drop; + + if (segs) { + consume_skb(skb); + skb = segs; + } + goto send; } + if ((skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)) + goto send; + if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { + /* TSO: fill MSS info in tcp checksum field */ gso = true; + if (skb_cow_head(skb, 0)) { + netif_warn(eth, tx_err, dev, + "GSO expand head fail.\n"); + goto drop; + } + tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size); } } +send: skb_list_walk_safe(skb, skb, next) { if ((mtk_is_netsys_v1(eth) && mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || - mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { + mtk_tx_map(skb, dev, tx_num, ring, gso, header_len) < 0) { stats->tx_dropped++; dev_kfree_skb_any(skb); } diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index b5aad9a7360c..1cf701b4126c 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -51,6 +51,8 @@ NETIF_F_HW_VLAN_CTAG_TX | \ NETIF_F_SG | NETIF_F_TSO | \ NETIF_F_TSO6 | \ + NETIF_F_FRAGLIST | \ + NETIF_F_GSO_FRAGLIST | \ NETIF_F_IPV6_CSUM |\ NETIF_F_HW_TC) #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) -- 2.51.0 From 878fe32f74d05f5e8b1ab976b2ac1b6caec2e6c7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 May 2024 14:29:58 +0200 Subject: [PATCH 295/517] net: ethernet: mtk_eth_soc: use napi_build_skb() The napi_build_skb() can reuse the skb in skb cache per CPU or can allocate skbs in bulk, which helps improve the performance. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 98266707bc22..4f7fdb29ad5b 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2305,7 +2305,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, if (ret != XDP_PASS) goto skip_rx; - skb = build_skb(data, PAGE_SIZE); + skb = napi_build_skb(data, PAGE_SIZE); if (unlikely(!skb)) { page_pool_put_full_page(ring->page_pool, page, true); @@ -2343,7 +2343,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, dma_unmap_single(eth->dma_dev, ((u64)trxd.rxd1 | addr64), ring->buf_size, DMA_FROM_DEVICE); - skb = build_skb(data, ring->frag_size); + skb = napi_build_skb(data, ring->frag_size); if (unlikely(!skb)) { netdev->stats.rx_dropped++; skb_free_frag(data); -- 2.51.0 From c29fb4a652ba3554f49264320bea3f3355480ee3 Mon Sep 17 00:00:00 2001 From: Chad Monroe Date: Mon, 16 Sep 2024 19:29:03 -0700 Subject: [PATCH 296/517] net: ethernet: mediatek: increase QDMA RESV_BUF size Increase QDMA RESV_BUF from 2K to 3K for netsys v2 to match Mediatek SDK[1]. This helps reduce the possibility of Ethernet transmit timeouts. [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/19d8456c3051e5f6dabf42fa770916a2126ea4bf Signed-off-by: Chad Monroe --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++-- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 4f7fdb29ad5b..ba9b3d6be8b2 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -3476,12 +3476,14 @@ static int mtk_start_dma(struct mtk_eth *eth) MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; - if (mtk_is_netsys_v2_or_greater(eth)) + if (mtk_is_netsys_v2_or_greater(eth)) { + val &= ~MTK_RESV_BUF_MASK; val |= MTK_MUTLI_CNT | MTK_RESV_BUF | MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | MTK_CHK_DDONE_EN; - else + } else { val |= MTK_RX_BT_32DWORDS; + } mtk_w32(eth, val, reg_map->qdma.glo_cfg); mtk_w32(eth, diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 1cf701b4126c..88dee7983642 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -282,6 +282,7 @@ #define MTK_WCOMP_EN BIT(24) #define MTK_RESV_BUF (0x80 << 16) #define MTK_MUTLI_CNT (0x4 << 12) +#define MTK_RESV_BUF_MASK (0xff << 16) #define MTK_LEAKY_BUCKET_EN BIT(11) /* QDMA Flow Control Register */ -- 2.51.0 From 39e91a55c5696f31f8afd9d764863578695c3028 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 23 Mar 2023 10:24:11 +0100 Subject: [PATCH 297/517] net: ethernet: mtk_eth_soc: improve keeping track of offloaded flows Unify tracking of L2 and L3 flows. Use the generic list field in struct mtk_foe_entry for tracking L2 subflows. Preparation for improving flow accounting support. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_ppe.c | 162 ++++++++++++------------ drivers/net/ethernet/mediatek/mtk_ppe.h | 15 +-- 2 files changed, 86 insertions(+), 91 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index ada852adc5f7..5b352ab64ef7 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -479,42 +479,43 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, return 0; } +static int +mtk_flow_entry_match_len(struct mtk_eth *eth, struct mtk_foe_entry *entry) +{ + int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + + if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) + return offsetof(struct mtk_foe_entry, ipv6._rsv); + else + return offsetof(struct mtk_foe_entry, ipv4.ib2); +} + static bool mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, - struct mtk_foe_entry *data) + struct mtk_foe_entry *data, int len) { - int type, len; - if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) return false; - type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); - if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) - len = offsetof(struct mtk_foe_entry, ipv6._rsv); - else - len = offsetof(struct mtk_foe_entry, ipv4.ib2); - return !memcmp(&entry->data.data, &data->data, len - 4); } static void -__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + bool set_state) { - struct hlist_head *head; struct hlist_node *tmp; if (entry->type == MTK_FLOW_TYPE_L2) { rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, mtk_flow_l2_ht_params); - head = &entry->l2_flows; - hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) - __mtk_foe_entry_clear(ppe, entry); + hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list) + __mtk_foe_entry_clear(ppe, entry, set_state); return; } - hlist_del_init(&entry->list); - if (entry->hash != 0xffff) { + if (entry->hash != 0xffff && set_state) { struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); hwe->ib1 &= ~MTK_FOE_IB1_STATE; @@ -535,7 +536,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) return; - hlist_del_init(&entry->l2_data.list); + hlist_del_init(&entry->l2_list); + hlist_del_init(&entry->list); kfree(entry); } @@ -551,68 +553,57 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) return now - timestamp; } +static bool +mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +{ + struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; + u16 hash = entry->hash; + int len; + + if (hash == 0xffff) + return false; + + hwe = mtk_foe_get_entry(ppe, hash); + len = mtk_flow_entry_match_len(ppe->eth, &entry->data); + memcpy(&foe, hwe, len); + + if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || + FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) + return false; + + entry->data.ib1 = foe.ib1; + + return true; +} + static void mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); struct mtk_flow_entry *cur; - struct mtk_foe_entry *hwe; struct hlist_node *tmp; int idle; idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); - hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { int cur_idle; - u32 ib1; - - hwe = mtk_foe_get_entry(ppe, cur->hash); - ib1 = READ_ONCE(hwe->ib1); - if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { - cur->hash = 0xffff; - __mtk_foe_entry_clear(ppe, cur); + if (!mtk_flow_entry_update(ppe, cur)) { + __mtk_foe_entry_clear(ppe, entry, false); continue; } - cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); + cur_idle = __mtk_foe_entry_idle_time(ppe, cur->data.ib1); if (cur_idle >= idle) continue; idle = cur_idle; entry->data.ib1 &= ~ib1_ts_mask; - entry->data.ib1 |= ib1 & ib1_ts_mask; + entry->data.ib1 |= cur->data.ib1 & ib1_ts_mask; } } -static void -mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -{ - struct mtk_foe_entry foe = {}; - struct mtk_foe_entry *hwe; - - spin_lock_bh(&ppe_lock); - - if (entry->type == MTK_FLOW_TYPE_L2) { - mtk_flow_entry_update_l2(ppe, entry); - goto out; - } - - if (entry->hash == 0xffff) - goto out; - - hwe = mtk_foe_get_entry(ppe, entry->hash); - memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); - if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { - entry->hash = 0xffff; - goto out; - } - - entry->data.ib1 = foe.ib1; - -out: - spin_unlock_bh(&ppe_lock); -} - static void __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, u16 hash) @@ -653,7 +644,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { spin_lock_bh(&ppe_lock); - __mtk_foe_entry_clear(ppe, entry); + __mtk_foe_entry_clear(ppe, entry, true); + hlist_del_init(&entry->list); spin_unlock_bh(&ppe_lock); } @@ -700,8 +692,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, { const struct mtk_soc_data *soc = ppe->eth->soc; struct mtk_flow_entry *flow_info; - struct mtk_foe_entry foe = {}, *hwe; struct mtk_foe_mac_info *l2; + struct mtk_foe_entry *hwe; u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; int type; @@ -709,30 +701,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, if (!flow_info) return; - flow_info->l2_data.base_flow = entry; flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; flow_info->hash = hash; hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / soc->hash_offset]); - hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); + hlist_add_head(&flow_info->l2_list, &entry->l2_flows); hwe = mtk_foe_get_entry(ppe, hash); - memcpy(&foe, hwe, soc->foe_entry_size); - foe.ib1 &= ib1_mask; - foe.ib1 |= entry->data.ib1 & ~ib1_mask; + memcpy(&flow_info->data, hwe, soc->foe_entry_size); + flow_info->data.ib1 &= ib1_mask; + flow_info->data.ib1 |= entry->data.ib1 & ~ib1_mask; - l2 = mtk_foe_entry_l2(ppe->eth, &foe); + l2 = mtk_foe_entry_l2(ppe->eth, &flow_info->data); memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); - type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); + type = mtk_get_ib1_pkt_type(ppe->eth, flow_info->data.ib1); if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) - memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); + memcpy(&flow_info->data.ipv4.new, &flow_info->data.ipv4.orig, + sizeof(flow_info->data.ipv4.new)); else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) l2->etype = ETH_P_IPV6; - *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; + *mtk_foe_entry_ib2(ppe->eth, &flow_info->data) = entry->data.bridge.ib2; - __mtk_foe_entry_commit(ppe, &foe, hash); + __mtk_foe_entry_commit(ppe, &flow_info->data, hash); } void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) @@ -742,9 +734,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); struct mtk_flow_entry *entry; struct mtk_foe_bridge key = {}; + struct mtk_foe_entry foe = {}; struct hlist_node *n; struct ethhdr *eh; bool found = false; + int entry_len; u8 *tag; spin_lock_bh(&ppe_lock); @@ -752,20 +746,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) goto out; - hlist_for_each_entry_safe(entry, n, head, list) { - if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { - if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == - MTK_FOE_STATE_BIND)) - continue; - - entry->hash = 0xffff; - __mtk_foe_entry_clear(ppe, entry); - continue; - } + entry_len = mtk_flow_entry_match_len(ppe->eth, hwe); + memcpy(&foe, hwe, entry_len); - if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { + hlist_for_each_entry_safe(entry, n, head, list) { + if (found || + !mtk_flow_entry_match(ppe->eth, entry, &foe, entry_len)) { if (entry->hash != 0xffff) - entry->hash = 0xffff; + __mtk_foe_entry_clear(ppe, entry, false); continue; } @@ -816,9 +804,17 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { - mtk_flow_entry_update(ppe, entry); + int idle; + + spin_lock_bh(&ppe_lock); + if (entry->type == MTK_FLOW_TYPE_L2) + mtk_flow_entry_update_l2(ppe, entry); + else + mtk_flow_entry_update(ppe, entry); + idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); + spin_unlock_bh(&ppe_lock); - return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); + return idle; } int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h index 223f709e2704..aa0799c1ce95 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h @@ -286,7 +286,12 @@ enum { struct mtk_flow_entry { union { - struct hlist_node list; + /* regular flows + L2 subflows */ + struct { + struct hlist_node list; + struct hlist_node l2_list; + }; + /* L2 flows */ struct { struct rhash_head l2_node; struct hlist_head l2_flows; @@ -296,13 +301,7 @@ struct mtk_flow_entry { s8 wed_index; u8 ppe_index; u16 hash; - union { - struct mtk_foe_entry data; - struct { - struct mtk_flow_entry *base_flow; - struct hlist_node list; - } l2_data; - }; + struct mtk_foe_entry data; struct rhash_head node; unsigned long cookie; }; -- 2.51.0 From 5fc20c1af300b58d2ee1f802ae8d630ef24f3573 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 23 Mar 2023 11:05:22 +0100 Subject: [PATCH 298/517] net: ethernet: mediatek: fix ppe flow accounting for L2 flows For L2 flows, the packet/byte counters should report the sum of the counters of their subflows, both current and expired. In order to make this work, change the way that accounting data is tracked. Reset counters when a flow enters bind. Once it expires (or enters unbind), store the last counter value in struct mtk_flow_entry. Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_ppe.c | 140 ++++++++++-------- drivers/net/ethernet/mediatek/mtk_ppe.h | 8 +- .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- .../net/ethernet/mediatek/mtk_ppe_offload.c | 17 +-- 4 files changed, 89 insertions(+), 78 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index 5b352ab64ef7..96365a75b198 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -83,9 +83,9 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) int ret; u32 val; - ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, - !(val & MTK_PPE_MIB_SER_CR_ST), - 20, MTK_PPE_WAIT_TIMEOUT_US); + ret = readl_poll_timeout_atomic(ppe->base + MTK_PPE_MIB_SER_CR, val, + !(val & MTK_PPE_MIB_SER_CR_ST), + 20, MTK_PPE_WAIT_TIMEOUT_US); if (ret) dev_err(ppe->dev, "MIB table busy"); @@ -93,17 +93,31 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) return ret; } -static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) +static inline struct mtk_foe_accounting * +mtk_ppe_acct_data(struct mtk_ppe *ppe, u16 index) +{ + if (!ppe->acct_table) + return NULL; + + return ppe->acct_table + index * sizeof(struct mtk_foe_accounting); +} + +struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index) { u32 val, cnt_r0, cnt_r1, cnt_r2; + struct mtk_foe_accounting *acct; int ret; val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); + acct = mtk_ppe_acct_data(ppe, index); + if (!acct) + return NULL; + ret = mtk_ppe_mib_wait_busy(ppe); if (ret) - return ret; + return acct; cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); @@ -112,19 +126,19 @@ static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *p if (mtk_is_netsys_v3_or_greater(ppe->eth)) { /* 64 bit for each counter */ u32 cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3); - *bytes = ((u64)cnt_r1 << 32) | cnt_r0; - *packets = ((u64)cnt_r3 << 32) | cnt_r2; + acct->bytes += ((u64)cnt_r1 << 32) | cnt_r0; + acct->packets += ((u64)cnt_r3 << 32) | cnt_r2; } else { /* 48 bit byte counter, 40 bit packet counter */ u32 byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0); u32 byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); u32 pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); u32 pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); - *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; - *packets = ((u64)pkt_cnt_high << 16) | pkt_cnt_low; + acct->bytes += ((u64)byte_cnt_high << 32) | byte_cnt_low; + acct->packets += ((u64)pkt_cnt_high << 16) | pkt_cnt_low; } - return 0; + return acct; } static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) @@ -522,14 +536,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); mtk_ppe_cache_clear(ppe); - - if (ppe->accounting) { - struct mtk_foe_accounting *acct; - - acct = ppe->acct_table + entry->hash * sizeof(*acct); - acct->packets = 0; - acct->bytes = 0; - } } entry->hash = 0xffff; @@ -554,11 +560,14 @@ static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) } static bool -mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + u64 *packets, u64 *bytes) { + struct mtk_foe_accounting *acct; struct mtk_foe_entry foe = {}; struct mtk_foe_entry *hwe; u16 hash = entry->hash; + bool ret = false; int len; if (hash == 0xffff) @@ -569,18 +578,35 @@ mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) memcpy(&foe, hwe, len); if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || - FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) - return false; + FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) { + acct = mtk_ppe_acct_data(ppe, hash); + if (acct) { + entry->prev_packets += acct->packets; + entry->prev_bytes += acct->bytes; + } + + goto out; + } entry->data.ib1 = foe.ib1; + acct = mtk_ppe_mib_entry_read(ppe, hash); + ret = true; + +out: + if (acct) { + *packets += acct->packets; + *bytes += acct->bytes; + } - return true; + return ret; } static void mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + u64 *packets = &entry->packets; + u64 *bytes = &entry->bytes; struct mtk_flow_entry *cur; struct hlist_node *tmp; int idle; @@ -589,7 +615,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { int cur_idle; - if (!mtk_flow_entry_update(ppe, cur)) { + if (!mtk_flow_entry_update(ppe, cur, packets, bytes)) { + entry->prev_packets += cur->prev_packets; + entry->prev_bytes += cur->prev_bytes; __mtk_foe_entry_clear(ppe, entry, false); continue; } @@ -604,10 +632,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) } } +void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + int *idle) +{ + entry->packets = entry->prev_packets; + entry->bytes = entry->prev_bytes; + + spin_lock_bh(&ppe_lock); + + if (entry->type == MTK_FLOW_TYPE_L2) + mtk_flow_entry_update_l2(ppe, entry); + else + mtk_flow_entry_update(ppe, entry, &entry->packets, &entry->bytes); + + *idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); + + spin_unlock_bh(&ppe_lock); +} + static void __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, u16 hash) { + struct mtk_foe_accounting *acct; struct mtk_eth *eth = ppe->eth; u16 timestamp = mtk_eth_timestamp(eth); struct mtk_foe_entry *hwe; @@ -638,6 +685,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, dma_wmb(); + acct = mtk_ppe_mib_entry_read(ppe, hash); + if (acct) { + acct->packets = 0; + acct->bytes = 0; + } + mtk_ppe_cache_clear(ppe); } @@ -802,21 +855,6 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) spin_unlock_bh(&ppe_lock); } -int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -{ - int idle; - - spin_lock_bh(&ppe_lock); - if (entry->type == MTK_FLOW_TYPE_L2) - mtk_flow_entry_update_l2(ppe, entry); - else - mtk_flow_entry_update(ppe, entry); - idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); - spin_unlock_bh(&ppe_lock); - - return idle; -} - int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) { if (!ppe) @@ -844,32 +882,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) return mtk_ppe_wait_busy(ppe); } -struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, - struct mtk_foe_accounting *diff) -{ - struct mtk_foe_accounting *acct; - int size = sizeof(struct mtk_foe_accounting); - u64 bytes, packets; - - if (!ppe->accounting) - return NULL; - - if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) - return NULL; - - acct = ppe->acct_table + index * size; - - acct->bytes += bytes; - acct->packets += packets; - - if (diff) { - diff->bytes = bytes; - diff->packets = packets; - } - - return acct; -} - struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) { bool accounting = eth->soc->has_accounting; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h index aa0799c1ce95..9a4990aa5fa5 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h @@ -304,6 +304,8 @@ struct mtk_flow_entry { struct mtk_foe_entry data; struct rhash_head node; unsigned long cookie; + u64 prev_packets, prev_bytes; + u64 packets, bytes; }; struct mtk_mib_entry { @@ -348,6 +350,7 @@ void mtk_ppe_deinit(struct mtk_eth *eth); void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); +struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index); void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); @@ -397,9 +400,8 @@ int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, unsigned int queue); int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); -int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); -struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, - struct mtk_foe_accounting *diff); +void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + int *idle); #endif diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c index 570ebf91f693..9259d0925b88 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c @@ -97,7 +97,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) if (bind && state != MTK_FOE_STATE_BIND) continue; - acct = mtk_foe_entry_get_mib(ppe, i, NULL); + acct = mtk_ppe_mib_entry_read(ppe, i); type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1); seq_printf(m, "%05x %s %7s", i, diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index e9bd32741983..af8e0107fb93 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -522,24 +522,21 @@ static int mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) { struct mtk_flow_entry *entry; - struct mtk_foe_accounting diff; - u32 idle; + u64 packets, bytes; + int idle; entry = rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params); if (!entry) return -ENOENT; - idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); + packets = entry->packets; + bytes = entry->bytes; + mtk_foe_entry_get_stats(eth->ppe[entry->ppe_index], entry, &idle); + f->stats.pkts += entry->packets - packets; + f->stats.bytes += entry->bytes - bytes; f->stats.lastused = jiffies - idle * HZ; - if (entry->hash != 0xFFFF && - mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, - &diff)) { - f->stats.pkts += diff.packets; - f->stats.bytes += diff.bytes; - } - return 0; } -- 2.51.0 From 6ece59fe862195dec63a973bd2a6099bee78859d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 12 Sep 2025 14:18:14 +0200 Subject: [PATCH 299/517] net: ethernet: mtk_eth_soc: zero initialize PPE flow table Avoid picking up flows from last boot or other invalid data Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_ppe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index 96365a75b198..cb08d132bad9 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -914,6 +914,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) if (!foe) goto err_free_l2_flows; + memset(foe, 0, MTK_PPE_ENTRIES * soc->foe_entry_size); ppe->foe_table = foe; foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * @@ -928,6 +929,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) if (!mib) return NULL; + memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib)); ppe->mib_table = mib; acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct), -- 2.51.0 From a6edd3042d35a2553e33b9d880226c6187bc6579 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 12 Dec 2023 03:51:14 +0000 Subject: [PATCH 300/517] net: ethernet: mtk_eth_soc: add paths and SerDes modes for MT7988 MT7988 comes with a built-in 2.5G PHY as well as SerDes lanes to connect external PHYs or transceivers in USXGMII, 10GBase-R, 5GBase-R, 2500Base-X, 1000Base-X and Cisco SGMII interface modes. Implement support for configuring for the new paths to SerDes interfaces and the internal 2.5G PHY. Add USXGMII PCS driver for 10GBase-R, 5GBase-R and USXGMII mode, and setup the new PHYA on MT7988 to access the also still existing old LynxI PCS for 1000Base-X, 2500Base-X and Cisco SGMII PCS interface modes. Signed-off-by: Daniel Golle --- drivers/net/ethernet/mediatek/mtk_eth_path.c | 122 +++++++- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 288 +++++++++++++++++-- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 93 +++++- 3 files changed, 470 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c index 7c27a19c4d8f..3f4f4cfe6a23 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_path.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c @@ -31,10 +31,20 @@ static const char *mtk_eth_path_name(u64 path) return "gmac2_rgmii"; case MTK_ETH_PATH_GMAC2_SGMII: return "gmac2_sgmii"; + case MTK_ETH_PATH_GMAC2_2P5GPHY: + return "gmac2_2p5gphy"; case MTK_ETH_PATH_GMAC2_GEPHY: return "gmac2_gephy"; + case MTK_ETH_PATH_GMAC3_SGMII: + return "gmac3_sgmii"; case MTK_ETH_PATH_GDM1_ESW: return "gdm1_esw"; + case MTK_ETH_PATH_GMAC1_USXGMII: + return "gmac1_usxgmii"; + case MTK_ETH_PATH_GMAC2_USXGMII: + return "gmac2_usxgmii"; + case MTK_ETH_PATH_GMAC3_USXGMII: + return "gmac3_usxgmii"; default: return "unknown path"; } @@ -127,6 +137,27 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) return 0; } +static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path) +{ + int ret; + + if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) { + ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0, SYSCFG0_SGMII_GMAC2_V2); + if (ret) + return ret; + + /* Setup mux to 2p5g PHY */ + ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, MUX_G2_USXGMII_SEL); + if (ret) + return ret; + + dev_dbg(eth->dev, "path %s in %s updated\n", + mtk_eth_path_name(path), __func__); + } + + return 0; +} + static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) { unsigned int val = 0; @@ -165,7 +196,48 @@ static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) return 0; } -static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) +static int set_mux_gmac123_to_usxgmii(struct mtk_eth *eth, u64 path) +{ + unsigned int val = 0; + bool updated = true; + int mac_id = 0; + + /* Disable SYSCFG1 SGMII */ + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + + switch (path) { + case MTK_ETH_PATH_GMAC1_USXGMII: + val &= ~(u32)SYSCFG0_SGMII_GMAC1_V2; + mac_id = MTK_GMAC1_ID; + break; + case MTK_ETH_PATH_GMAC2_USXGMII: + val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; + mac_id = MTK_GMAC2_ID; + break; + case MTK_ETH_PATH_GMAC3_USXGMII: + val &= ~(u32)SYSCFG0_SGMII_GMAC3_V2; + mac_id = MTK_GMAC3_ID; + break; + default: + updated = false; + }; + + if (updated) { + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, val); + + if (mac_id == MTK_GMAC2_ID) + regmap_set_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, + MUX_G2_USXGMII_SEL); + } + + dev_dbg(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name(path), __func__, updated); + + return 0; +} + +static int set_mux_gmac123_to_gephy_sgmii(struct mtk_eth *eth, u64 path) { unsigned int val = 0; bool updated = true; @@ -182,6 +254,9 @@ static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) case MTK_ETH_PATH_GMAC2_SGMII: val |= SYSCFG0_SGMII_GMAC2_V2; break; + case MTK_ETH_PATH_GMAC3_SGMII: + val |= SYSCFG0_SGMII_GMAC3_V2; + break; default: updated = false; } @@ -209,6 +284,10 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { .name = "mux_u3_gmac2_to_qphy", .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, .set_path = set_mux_u3_gmac2_to_qphy, + }, { + .name = "mux_gmac2_to_2p5gphy", + .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, + .set_path = set_mux_gmac2_to_2p5gphy, }, { .name = "mux_gmac1_gmac2_to_sgmii_rgmii", .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, @@ -216,7 +295,15 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { }, { .name = "mux_gmac12_to_gephy_sgmii", .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, - .set_path = set_mux_gmac12_to_gephy_sgmii, + .set_path = set_mux_gmac123_to_gephy_sgmii, + }, { + .name = "mux_gmac123_to_gephy_sgmii", + .cap_bit = MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII, + .set_path = set_mux_gmac123_to_gephy_sgmii, + }, { + .name = "mux_gmac123_to_usxgmii", + .cap_bit = MTK_ETH_MUX_GMAC123_TO_USXGMII, + .set_path = set_mux_gmac123_to_usxgmii, }, }; @@ -249,12 +336,39 @@ static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path) return err; } +int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id) +{ + u64 path; + + path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_USXGMII : + (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_USXGMII : + MTK_ETH_PATH_GMAC3_USXGMII; + + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); +} + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) { u64 path; - path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : - MTK_ETH_PATH_GMAC2_SGMII; + path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_SGMII : + (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_SGMII : + MTK_ETH_PATH_GMAC3_SGMII; + + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); +} + +int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id) +{ + u64 path = 0; + + if (mac_id == MTK_GMAC2_ID) + path = MTK_ETH_PATH_GMAC2_2P5GPHY; + + if (!path) + return -EINVAL; /* Setup proper MUXes along the path */ return mtk_eth_mux_setup(eth, path); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index ba9b3d6be8b2..2883f53c016a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -522,6 +524,30 @@ static void mtk_setup_bridge_switch(struct mtk_eth *eth) MTK_GSW_CFG); } +static bool mtk_check_gmac23_idle(struct mtk_mac *mac) +{ + u32 mac_fsm, gdm_fsm; + + mac_fsm = mtk_r32(mac->hw, MTK_MAC_FSM(mac->id)); + + switch (mac->id) { + case MTK_GMAC2_ID: + gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM2_FSM); + break; + case MTK_GMAC3_ID: + gdm_fsm = mtk_r32(mac->hw, MTK_FE_GDM3_FSM); + break; + default: + return true; + }; + + if ((mac_fsm & 0xFFFF0000) == 0x01010000 && + (gdm_fsm & 0xFFFF0000) == 0x00000000) + return true; + + return false; +} + static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, phy_interface_t interface) { @@ -530,6 +556,21 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, struct mtk_eth *eth = mac->hw; unsigned int sid; + if (mtk_is_netsys_v3_or_greater(eth)) { + switch (interface) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + return mac->sgmii_pcs; + case PHY_INTERFACE_MODE_5GBASER: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: + return mac->usxgmii_pcs; + default: + return NULL; + } + } + if (interface == PHY_INTERFACE_MODE_SGMII || phy_interface_mode_is_8023z(interface)) { sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? @@ -581,7 +622,22 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, goto init_err; } break; + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_5GBASER: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) { + err = mtk_gmac_usxgmii_path_setup(eth, mac->id); + if (err) + goto init_err; + } + break; case PHY_INTERFACE_MODE_INTERNAL: + if (mac->id == MTK_GMAC2_ID && + MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) { + err = mtk_gmac_2p5gphy_path_setup(eth, mac->id); + if (err) + goto init_err; + } break; default: goto err_phy; @@ -628,8 +684,6 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id); val |= SYSCFG0_GE_MODE(ge_mode, mac->id); regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); - - mac->interface = state->interface; } /* SGMII */ @@ -646,21 +700,40 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, /* Save the syscfg0 value for mac_finish */ mac->syscfg0 = val; - } else if (phylink_autoneg_inband(mode)) { + } else if (state->interface != PHY_INTERFACE_MODE_USXGMII && + state->interface != PHY_INTERFACE_MODE_10GBASER && + state->interface != PHY_INTERFACE_MODE_5GBASER && + phylink_autoneg_inband(mode)) { dev_err(eth->dev, - "In-band mode not supported in non SGMII mode!\n"); + "In-band mode not supported in non-SerDes modes!\n"); return; } /* Setup gmac */ - if (mtk_is_netsys_v3_or_greater(eth) && - mac->interface == PHY_INTERFACE_MODE_INTERNAL) { - mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); - mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); + if (mtk_is_netsys_v3_or_greater(eth)) { + if (mtk_interface_mode_is_xgmii(state->interface)) { + mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); + mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); - mtk_setup_bridge_switch(eth); + if (mac->id == MTK_GMAC1_ID) + mtk_setup_bridge_switch(eth); + } else { + mtk_w32(eth, 0, MTK_GDMA_EG_CTRL(mac->id)); + + /* FIXME: In current hardware design, we have to reset FE + * when swtiching XGDM to GDM. Therefore, here trigger an SER + * to let GDM go back to the initial state. + */ + if ((mtk_interface_mode_is_xgmii(mac->interface) || + mac->interface == PHY_INTERFACE_MODE_NA) && + !mtk_check_gmac23_idle(mac) && + !test_bit(MTK_RESETTING, ð->state)) + schedule_work(ð->pending_work); + } } + mac->interface = state->interface; + return; err_phy: @@ -673,6 +746,18 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, mac->id, phy_modes(state->interface), err); } +static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + + if (mac->pextp && mac->interface != interface) + phy_reset(mac->pextp); + + return 0; +} + static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { @@ -681,6 +766,10 @@ static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, struct mtk_eth *eth = mac->hw; u32 mcr_cur, mcr_new; + /* Setup PMA/PMD */ + if (mac->pextp) + phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface); + /* Enable SGMII */ if (interface == PHY_INTERFACE_MODE_SGMII || phy_interface_mode_is_8023z(interface)) @@ -705,10 +794,14 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, { struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); - u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK); - mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + if (!mtk_interface_mode_is_xgmii(interface)) { + mtk_m32(mac->hw, MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK, 0, MTK_MAC_MCR(mac->id)); + if (mtk_is_netsys_v3_or_greater(mac->hw)) + mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), 0, MTK_XGMAC_STS(mac->id)); + } else if (mtk_is_netsys_v3_or_greater(mac->hw) && mac->id != MTK_GMAC1_ID) { + mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, XMAC_MCR_TRX_DISABLE, MTK_XMAC_MCR(mac->id)); + } } static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, @@ -780,13 +873,11 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); } -static void mtk_mac_link_up(struct phylink_config *config, - struct phy_device *phy, - unsigned int mode, phy_interface_t interface, - int speed, int duplex, bool tx_pause, bool rx_pause) +static void mtk_gdm_mac_link_up(struct mtk_mac *mac, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) { - struct mtk_mac *mac = container_of(config, struct mtk_mac, - phylink_config); u32 mcr; mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); @@ -830,9 +921,63 @@ static void mtk_mac_link_up(struct phylink_config *config, mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } +static void mtk_xgdm_mac_link_up(struct mtk_mac *mac, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + u32 mcr, force_link = 0; + + if (mac->id == MTK_GMAC1_ID) + return; + + /* Eliminate the interference(before link-up) caused by PHY noise */ + mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id)); + mdelay(20); + mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, MTK_XMAC_CNT_CTRL(mac->id)); + + if (mac->interface == PHY_INTERFACE_MODE_INTERNAL || mac->id == MTK_GMAC3_ID) + force_link = MTK_XGMAC_FORCE_LINK(mac->id); + + mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), force_link, MTK_XGMAC_STS(mac->id)); + + mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id)); + mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC | XMAC_MCR_TRX_DISABLE); + /* Configure pause modes - + * phylink will avoid these for half duplex + */ + if (tx_pause) + mcr |= XMAC_MCR_FORCE_TX_FC; + if (rx_pause) + mcr |= XMAC_MCR_FORCE_RX_FC; + + mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id)); +} + +static void mtk_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + + if (mtk_is_netsys_v3_or_greater(mac->hw) && mtk_interface_mode_is_xgmii(interface)) + mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex, + tx_pause, rx_pause); + else + mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex, + tx_pause, rx_pause); + + /* Repeat pextp setup to tune link */ + if (mac->pextp) + phy_set_mode_ext(mac->pextp, PHY_MODE_ETHERNET, interface); +} + static const struct phylink_mac_ops mtk_phylink_ops = { .mac_select_pcs = mtk_mac_select_pcs, .mac_config = mtk_mac_config, + .mac_prepare = mtk_mac_prepare, .mac_finish = mtk_mac_finish, .mac_link_down = mtk_mac_link_down, .mac_link_up = mtk_mac_link_up, @@ -3584,6 +3729,9 @@ static int mtk_open(struct net_device *dev) ppe_num = eth->soc->ppe_num; + if (mac->pextp) + phy_power_on(mac->pextp); + err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, @@ -3731,6 +3879,9 @@ static int mtk_stop(struct net_device *dev) for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) mtk_ppe_stop(eth->ppe[i]); + if (mac->pextp) + phy_power_off(mac->pextp); + return 0; } @@ -4821,6 +4972,7 @@ static const struct net_device_ops mtk_netdev_ops = { static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { const __be32 *_id = of_get_property(np, "reg", NULL); + struct device_node *pcs_np; phy_interface_t phy_mode; struct phylink *phylink; struct mtk_mac *mac; @@ -4859,16 +5011,41 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->id = id; mac->hw = eth; mac->of_node = np; + pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 0); + if (pcs_np) { + mac->sgmii_pcs = mtk_pcs_lynxi_get(eth->dev, pcs_np); + if (IS_ERR(mac->sgmii_pcs)) { + if (PTR_ERR(mac->sgmii_pcs) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_err(eth->dev, "cannot select SGMII PCS, error %ld\n", + PTR_ERR(mac->sgmii_pcs)); + return PTR_ERR(mac->sgmii_pcs); + } + } - err = of_get_ethdev_address(mac->of_node, eth->netdev[id]); - if (err == -EPROBE_DEFER) - return err; + pcs_np = of_parse_phandle(mac->of_node, "pcs-handle", 1); + if (pcs_np) { + mac->usxgmii_pcs = mtk_usxgmii_pcs_get(eth->dev, pcs_np); + if (IS_ERR(mac->usxgmii_pcs)) { + if (PTR_ERR(mac->usxgmii_pcs) == -EPROBE_DEFER) + return -EPROBE_DEFER; - if (err) { - /* If the mac address is invalid, use random mac address */ - eth_hw_addr_random(eth->netdev[id]); - dev_err(eth->dev, "generated random MAC address %pM\n", - eth->netdev[id]->dev_addr); + dev_err(eth->dev, "cannot select USXGMII PCS, error %ld\n", + PTR_ERR(mac->usxgmii_pcs)); + return PTR_ERR(mac->usxgmii_pcs); + } + } + + if (mtk_is_netsys_v3_or_greater(eth) && (mac->sgmii_pcs || mac->usxgmii_pcs)) { + mac->pextp = devm_of_phy_get(eth->dev, mac->of_node, NULL); + if (IS_ERR(mac->pextp)) { + if (PTR_ERR(mac->pextp) != -EPROBE_DEFER) + dev_err(eth->dev, "cannot get PHY, error %ld\n", + PTR_ERR(mac->pextp)); + + return PTR_ERR(mac->pextp); + } } memset(mac->hwlro_ip, 0, sizeof(mac->hwlro_ip)); @@ -4951,8 +5128,21 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) phy_interface_zero(mac->phylink_config.supported_interfaces); __set_bit(PHY_INTERFACE_MODE_INTERNAL, mac->phylink_config.supported_interfaces); + } else if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_USXGMII)) { + mac->phylink_config.mac_capabilities |= MAC_5000FD | MAC_10000FD; + __set_bit(PHY_INTERFACE_MODE_5GBASER, + mac->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_10GBASER, + mac->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_USXGMII, + mac->phylink_config.supported_interfaces); } + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && + id == MTK_GMAC2_ID) + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + mac->phylink_config.supported_interfaces); + phylink = phylink_create(&mac->phylink_config, of_fwnode_handle(mac->of_node), phy_mode, &mtk_phylink_ops); @@ -5003,6 +5193,26 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) return err; } +static int mtk_mac_assign_address(struct mtk_eth *eth, int i, bool test_defer_only) +{ + int err = of_get_ethdev_address(eth->mac[i]->of_node, eth->netdev[i]); + + if (err == -EPROBE_DEFER) + return err; + + if (test_defer_only) + return 0; + + if (err) { + /* If the mac address is invalid, use random mac address */ + eth_hw_addr_random(eth->netdev[i]); + dev_err(eth->dev, "generated random MAC address %pM\n", + eth->netdev[i]); + } + + return 0; +} + void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) { struct net_device *dev, *tmp; @@ -5149,7 +5359,8 @@ static int mtk_probe(struct platform_device *pdev) regmap_write(cci, 0, 3); } - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII) && + !mtk_is_netsys_v3_or_greater(eth)) { err = mtk_sgmii_init(eth); if (err) @@ -5260,6 +5471,24 @@ static int mtk_probe(struct platform_device *pdev) } } + for (i = 0; i < MTK_MAX_DEVS; i++) { + if (!eth->netdev[i]) + continue; + + err = mtk_mac_assign_address(eth, i, true); + if (err) + goto err_deinit_hw; + } + + for (i = 0; i < MTK_MAX_DEVS; i++) { + if (!eth->netdev[i]) + continue; + + err = mtk_mac_assign_address(eth, i, false); + if (err) + goto err_deinit_hw; + } + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq, 0, @@ -5370,6 +5599,11 @@ static void mtk_remove(struct platform_device *pdev) mtk_stop(eth->netdev[i]); mac = netdev_priv(eth->netdev[i]); phylink_disconnect_phy(mac->phylink); + if (mac->sgmii_pcs) + mtk_pcs_lynxi_put(mac->sgmii_pcs); + + if (mac->usxgmii_pcs) + mtk_usxgmii_pcs_put(mac->usxgmii_pcs); } mtk_wed_exit(); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 88dee7983642..c7ad88351a1b 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -527,6 +528,21 @@ #define INTF_MODE_RGMII_1000 (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED) #define INTF_MODE_RGMII_10_100 0 +/* XFI Mac control registers */ +#define MTK_XMAC_BASE(x) (0x12000 + (((x) - 1) * 0x1000)) +#define MTK_XMAC_MCR(x) (MTK_XMAC_BASE(x)) +#define XMAC_MCR_TRX_DISABLE 0xf +#define XMAC_MCR_FORCE_TX_FC BIT(5) +#define XMAC_MCR_FORCE_RX_FC BIT(4) + +/* XFI Mac logic reset registers */ +#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10) +#define XMAC_LOGIC_RST BIT(0) + +/* XFI Mac count global control */ +#define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100) +#define XMAC_GLB_CNTCLR BIT(0) + /* GPIO port control registers for GMAC 2*/ #define GPIO_OD33_CTRL8 0x4c0 #define GPIO_BIAS_CTRL 0xed0 @@ -552,6 +568,7 @@ #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) #define SYSCFG0_SGMII_GMAC1_V2 BIT(9) #define SYSCFG0_SGMII_GMAC2_V2 BIT(8) +#define SYSCFG0_SGMII_GMAC3_V2 BIT(7) /* ethernet subsystem clock register */ @@ -590,6 +607,11 @@ #define GEPHY_MAC_SEL BIT(1) /* Top misc registers */ +#define TOP_MISC_NETSYS_PCS_MUX 0x0 +#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) +#define MUX_G2_USXGMII_SEL BIT(1) +#define MUX_HSGMII1_G1_SEL BIT(0) + #define USB_PHY_SWITCH_REG 0x218 #define QPHY_SEL_MASK GENMASK(1, 0) #define SGMII_QPHY_SEL 0x2 @@ -614,6 +636,8 @@ #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c) #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110) +/* Debug Purpose Register */ +#define MTK_PSE_FQFC_CFG 0x100 #define MTK_FE_CDM1_FSM 0x220 #define MTK_FE_CDM2_FSM 0x224 #define MTK_FE_CDM3_FSM 0x238 @@ -622,6 +646,11 @@ #define MTK_FE_CDM6_FSM 0x328 #define MTK_FE_GDM1_FSM 0x228 #define MTK_FE_GDM2_FSM 0x22C +#define MTK_FE_GDM3_FSM 0x23C +#define MTK_FE_PSE_FREE 0x240 +#define MTK_FE_DROP_FQ 0x244 +#define MTK_FE_DROP_FC 0x248 +#define MTK_FE_DROP_PPE 0x24C #define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100)) @@ -945,6 +974,8 @@ enum mkt_eth_capabilities { MTK_RGMII_BIT = 0, MTK_TRGMII_BIT, MTK_SGMII_BIT, + MTK_USXGMII_BIT, + MTK_2P5GPHY_BIT, MTK_ESW_BIT, MTK_GEPHY_BIT, MTK_MUX_BIT, @@ -965,8 +996,11 @@ enum mkt_eth_capabilities { MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT, MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, + MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT, MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, + MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT, + MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT, /* PATH BITS */ MTK_ETH_PATH_GMAC1_RGMII_BIT, @@ -974,14 +1008,21 @@ enum mkt_eth_capabilities { MTK_ETH_PATH_GMAC1_SGMII_BIT, MTK_ETH_PATH_GMAC2_RGMII_BIT, MTK_ETH_PATH_GMAC2_SGMII_BIT, + MTK_ETH_PATH_GMAC2_2P5GPHY_BIT, MTK_ETH_PATH_GMAC2_GEPHY_BIT, + MTK_ETH_PATH_GMAC3_SGMII_BIT, MTK_ETH_PATH_GDM1_ESW_BIT, + MTK_ETH_PATH_GMAC1_USXGMII_BIT, + MTK_ETH_PATH_GMAC2_USXGMII_BIT, + MTK_ETH_PATH_GMAC3_USXGMII_BIT, }; /* Supported hardware group on SoCs */ #define MTK_RGMII BIT_ULL(MTK_RGMII_BIT) #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) +#define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT) +#define MTK_2P5GPHY BIT_ULL(MTK_2P5GPHY_BIT) #define MTK_ESW BIT_ULL(MTK_ESW_BIT) #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) #define MTK_MUX BIT_ULL(MTK_MUX_BIT) @@ -1004,10 +1045,16 @@ enum mkt_eth_capabilities { BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) +#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \ + BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT) #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT) +#define MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT) +#define MTK_ETH_MUX_GMAC123_TO_USXGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT) /* Supported path present on SoCs */ #define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT) @@ -1015,8 +1062,13 @@ enum mkt_eth_capabilities { #define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT) #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) +#define MTK_ETH_PATH_GMAC2_2P5GPHY BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT) #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) +#define MTK_ETH_PATH_GMAC3_SGMII BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT) #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) +#define MTK_ETH_PATH_GMAC1_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT) +#define MTK_ETH_PATH_GMAC2_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT) +#define MTK_ETH_PATH_GMAC3_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT) #define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII) #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) @@ -1024,7 +1076,12 @@ enum mkt_eth_capabilities { #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) +#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY) +#define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII) #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) +#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) +#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII) +#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII) /* MUXes present on SoCs */ /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ @@ -1043,10 +1100,20 @@ enum mkt_eth_capabilities { (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \ MTK_SHARED_SGMII) +/* 2: GMAC2 -> XGMII */ +#define MTK_MUX_GMAC2_TO_2P5GPHY \ + (MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA) + /* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) +#define MTK_MUX_GMAC123_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX) + +#define MTK_MUX_GMAC123_TO_USXGMII \ + (MTK_ETH_MUX_GMAC123_TO_USXGMII | MTK_MUX | MTK_INFRA) + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) #define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ @@ -1078,8 +1145,12 @@ enum mkt_eth_capabilities { MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_RSTCTRL_PPE1 | MTK_SRAM) -#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \ - MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) +#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC1_SGMII | \ + MTK_GMAC2_2P5GPHY | MTK_GMAC2_SGMII | MTK_GMAC2_USXGMII | \ + MTK_GMAC3_SGMII | MTK_GMAC3_USXGMII | \ + MTK_MUX_GMAC123_TO_GEPHY_SGMII | \ + MTK_MUX_GMAC123_TO_USXGMII | MTK_MUX_GMAC2_TO_2P5GPHY | \ + MTK_QDMA | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) struct mtk_tx_dma_desc_info { dma_addr_t addr; @@ -1327,6 +1398,9 @@ struct mtk_mac { struct device_node *of_node; struct phylink *phylink; struct phylink_config phylink_config; + struct phylink_pcs *sgmii_pcs; + struct phylink_pcs *usxgmii_pcs; + struct phy *pextp; struct mtk_eth *hw; struct mtk_hw_stats *hw_stats; __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; @@ -1450,6 +1524,19 @@ static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) return MTK_FOE_IB2_MULTICAST; } +static inline bool mtk_interface_mode_is_xgmii(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_INTERNAL: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_5GBASER: + return true; + default: + return false; + } +} + /* read the hardware status register */ void mtk_stats_update_mac(struct mtk_mac *mac); @@ -1458,8 +1545,10 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg); u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg); int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); +int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); +int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id); int mtk_eth_offload_init(struct mtk_eth *eth, u8 id); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, -- 2.51.0 From f45eeb706a8d64bfc50fd9b3b667530ff0625232 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 15 Oct 2024 13:09:37 +0200 Subject: [PATCH 301/517] net: ethernet: mtk_eth_soc: reduce rx ring size for older chipsets Commit c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific") resolved some tx timeout issues by bumping FQ and tx ring sizes from 512 to 2048 entries (the value used in the MediaTek SDK), however it also changed the rx ring size for all chipsets in the same way. Based on a few tests, it seems that a symmetric rx/tx ring size of 2048 really only makes sense on MT7988, which is capable of 10G ethernet links. Older chipsets are typically deployed in systems that are more memory constrained and don't actually need the larger rings to handle received packets. In order to reduce wasted memory set the ring size based on the SoC to the following values: - 2048 on MT7988 - 1024 on MT7986 - 512 (previous value) on everything else, except: - 256 on RT5350 (the oldest supported chipset) Fixes: c57e55819443 ("net: ethernet: mtk_eth_soc: handle dma buffer size soc specific") Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 2883f53c016a..18a31e6ed350 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -5637,7 +5637,7 @@ static const struct mtk_soc_data mt2701_data = { DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, }, @@ -5665,7 +5665,7 @@ static const struct mtk_soc_data mt7621_data = { DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, }, @@ -5695,7 +5695,7 @@ static const struct mtk_soc_data mt7622_data = { DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, }, @@ -5724,7 +5724,7 @@ static const struct mtk_soc_data mt7623_data = { DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, }, @@ -5750,7 +5750,7 @@ static const struct mtk_soc_data mt7629_data = { DESC_SIZE(struct mtk_rx_dma), .irq_done_mask = MTK_RX_DONE_INT, .dma_l4_valid = RX_DMA_L4_VALID, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, }, @@ -5782,7 +5782,7 @@ static const struct mtk_soc_data mt7981_data = { .dma_l4_valid = RX_DMA_L4_VALID_V2, .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(512), }, }; @@ -5812,7 +5812,7 @@ static const struct mtk_soc_data mt7986_data = { .dma_l4_valid = RX_DMA_L4_VALID_V2, .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(1K), }, }; @@ -5865,7 +5865,7 @@ static const struct mtk_soc_data rt5350_data = { .dma_l4_valid = RX_DMA_L4_VALID_PDMA, .dma_max_len = MTK_TX_DMA_BUF_LEN, .dma_len_offset = 16, - .dma_size = MTK_DMA_SIZE(2K), + .dma_size = MTK_DMA_SIZE(256), }, }; -- 2.51.0 From 7fa390446c8e232a3663e8ed59c0efbb9a3978f3 Mon Sep 17 00:00:00 2001 From: Danila Romanov Date: Wed, 22 Jan 2025 06:48:45 +0100 Subject: [PATCH 302/517] net: ethernet: mtk_eth_soc: do not enable page pool stats by default There is no reason for it to be enabled by default. Align mtk_eth_soc driver to mt76 driver. This option incurs additional CPU cost in allocation and recycle paths and additional memory cost to store the statistics. Signed-off-by: Danila Romanov Signed-off-by: Felix Fietkau --- drivers/net/ethernet/mediatek/Kconfig | 1 - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig index 95c4405b7d7b..d97431682c3a 100644 --- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig @@ -26,7 +26,6 @@ config NET_MEDIATEK_SOC select PHYLINK select DIMLIB select PAGE_POOL - select PAGE_POOL_STATS select PCS_MTK_LYNXI select REGMAP_MMIO help diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 18a31e6ed350..bc217da6ffc7 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -4740,6 +4740,7 @@ static int mtk_get_sset_count(struct net_device *dev, int sset) static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) { +#ifdef CONFIG_PAGE_POOL_STATS struct page_pool_stats stats = {}; int i; @@ -4752,6 +4753,7 @@ static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) page_pool_get_stats(ring->page_pool, &stats); } page_pool_ethtool_stats_get(data, &stats); +#endif } static void mtk_get_ethtool_stats(struct net_device *dev, -- 2.51.0 From 9e1ea8c49deab1c1c5681faf44991ca8ad03de1c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 1 Feb 2024 21:52:20 +0000 Subject: [PATCH 303/517] dt-bindings: phy: mediatek,xfi-tphy: add new bindings Add bindings for the MediaTek XFI T-PHY Ethernet SerDes PHY found in the MediaTek MT7988 SoC which can operate at various interfaces modes: via USXGMII PCS: * USXGMII * 10GBase-R * 5GBase-R via LynxI SGMII PCS: * 2500Base-X * 1000Base-X * Cisco SGMII (MAC side) Signed-off-by: Daniel Golle --- .../bindings/phy/mediatek,xfi-tphy.yaml | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml new file mode 100644 index 000000000000..e897118dcf7e --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,xfi-tphy.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/mediatek,xfi-tphy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek XFI T-PHY + +maintainers: + - Daniel Golle + +description: + The MediaTek XFI SerDes T-PHY provides the physical SerDes lanes + used by the (10G/5G) USXGMII PCS and (1G/2.5G) LynxI PCS found in + MediaTek's 10G-capabale SoCs. + +properties: + $nodename: + pattern: "^phy@[0-9a-f]+$" + + compatible: + const: mediatek,mt7988-xfi-tphy + + reg: + maxItems: 1 + + clocks: + items: + - description: XFI PHY clock + - description: XFI register clock + + clock-names: + items: + - const: xfipll + - const: topxtal + + resets: + items: + - description: PEXTP reset + + mediatek,usxgmii-performance-errata: + $ref: /schemas/types.yaml#/definitions/flag + description: + One instance of the T-PHY on MT7988 suffers from a performance + problem in 10GBase-R mode which needs a work-around in the driver. + The work-around is enabled using this flag. + + "#phy-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + phy@11f20000 { + compatible = "mediatek,mt7988-xfi-tphy"; + reg = <0 0x11f20000 0 0x10000>; + clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, + <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>; + clock-names = "xfipll", "topxtal"; + resets = <&watchdog 14>; + mediatek,usxgmii-performance-errata; + #phy-cells = <0>; + }; + }; + +... -- 2.51.0 From 6521c70d317c1145ac508e6d30bf15238af9c73f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 12 Dec 2023 03:47:18 +0000 Subject: [PATCH 304/517] net: pcs: pcs-mtk-lynxi: add platform driver for MT7988 Introduce a proper platform MFD driver for the LynxI (H)SGMII PCS which is going to initially be used for the MT7988 SoC. Signed-off-by: Daniel Golle --- drivers/net/pcs/pcs-mtk-lynxi.c | 224 ++++++++++++++++++++++++++++-- include/linux/pcs/pcs-mtk-lynxi.h | 11 ++ 2 files changed, 224 insertions(+), 11 deletions(-) diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 7de804535229..9f32540bba9c 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018-2019 MediaTek Inc. -/* A library for MediaTek SGMII circuit +/* A library and platform driver for the MediaTek LynxI SGMII circuit * * Author: Sean Wang * Author: Alexander Couzens @@ -8,11 +8,17 @@ * */ +#include #include +#include +#include #include +#include #include #include +#include #include +#include /* SGMII subsystem config registers */ /* BMCR (low 16) BMSR (high 16) */ @@ -65,6 +71,8 @@ #define SGMII_PN_SWAP_MASK GENMASK(1, 0) #define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) +#define MTK_NETSYS_V3_AMA_RGC3 0x128 + /* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated * data * @regmap: The register map pointing at the range used to setup @@ -74,15 +82,29 @@ * @interface: Currently configured interface mode * @pcs: Phylink PCS structure * @flags: Flags indicating hardware properties + * @rstc: Reset controller + * @sgmii_sel: SGMII Register Clock + * @sgmii_rx: SGMII RX Clock + * @sgmii_tx: SGMII TX Clock + * @node: List node */ struct mtk_pcs_lynxi { struct regmap *regmap; + struct device *dev; u32 ana_rgc3; phy_interface_t interface; struct phylink_pcs pcs; u32 flags; + struct reset_control *rstc; + struct clk *sgmii_sel; + struct clk *sgmii_rx; + struct clk *sgmii_tx; + struct list_head node; }; +static LIST_HEAD(mtk_pcs_lynxi_instances); +static DEFINE_MUTEX(instance_mutex); + static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) { return container_of(pcs, struct mtk_pcs_lynxi, pcs); @@ -117,6 +139,17 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, FIELD_GET(SGMII_LPA, adv)); } +static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs) +{ + if (!mpcs->rstc) + return; + + reset_control_assert(mpcs->rstc); + udelay(100); + reset_control_deassert(mpcs->rstc); + mdelay(1); +} + static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, @@ -162,6 +195,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, SGMII_PHYA_PWD); /* Reset SGMII PCS state */ + mtk_sgmii_reset(mpcs); regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0, SGMII_SW_RESET); @@ -248,10 +282,29 @@ static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, } } +static int mtk_pcs_lynxi_enable(struct phylink_pcs *pcs) +{ + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + + if (mpcs->sgmii_tx && mpcs->sgmii_rx) { + clk_prepare_enable(mpcs->sgmii_rx); + clk_prepare_enable(mpcs->sgmii_tx); + } + + return 0; +} + static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD); + + if (mpcs->sgmii_tx && mpcs->sgmii_rx) { + clk_disable_unprepare(mpcs->sgmii_tx); + clk_disable_unprepare(mpcs->sgmii_rx); + } + mpcs->interface = PHY_INTERFACE_MODE_NA; } @@ -262,11 +315,12 @@ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { .pcs_an_restart = mtk_pcs_lynxi_restart_an, .pcs_link_up = mtk_pcs_lynxi_link_up, .pcs_disable = mtk_pcs_lynxi_disable, + .pcs_enable = mtk_pcs_lynxi_enable, }; -struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, - struct regmap *regmap, u32 ana_rgc3, - u32 flags) +static struct phylink_pcs *mtk_pcs_lynxi_init(struct device *dev, struct regmap *regmap, + u32 ana_rgc3, u32 flags, + struct mtk_pcs_lynxi *prealloc) { struct mtk_pcs_lynxi *mpcs; u32 id, ver; @@ -274,29 +328,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id); if (ret < 0) - return NULL; + return ERR_PTR(ret); if (id != SGMII_LYNXI_DEV_ID) { dev_err(dev, "unknown PCS device id %08x\n", id); - return NULL; + return ERR_PTR(-ENODEV); } ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver); if (ret < 0) - return NULL; + return ERR_PTR(ret); ver = FIELD_GET(SGMII_DEV_VERSION, ver); if (ver != 0x1) { dev_err(dev, "unknown PCS device version %04x\n", ver); - return NULL; + return ERR_PTR(-ENODEV); } dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id, ver); - mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); - if (!mpcs) - return NULL; + if (prealloc) { + mpcs = prealloc; + } else { + mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); + if (!mpcs) + return ERR_PTR(-ENOMEM); + }; mpcs->ana_rgc3 = ana_rgc3; mpcs->regmap = regmap; @@ -307,6 +365,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, mpcs->interface = PHY_INTERFACE_MODE_NA; return &mpcs->pcs; +}; + +struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, + struct regmap *regmap, u32 ana_rgc3, + u32 flags) +{ + return mtk_pcs_lynxi_init(dev, regmap, ana_rgc3, flags, NULL); } EXPORT_SYMBOL(mtk_pcs_lynxi_create); @@ -319,5 +384,142 @@ void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); +static int mtk_pcs_lynxi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct mtk_pcs_lynxi *mpcs; + struct phylink_pcs *pcs; + struct regmap *regmap; + u32 flags = 0; + + mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); + if (!mpcs) + return -ENOMEM; + + mpcs->dev = dev; + regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + if (of_property_read_bool(np->parent, "mediatek,pnswap")) + flags |= MTK_SGMII_FLAG_PN_SWAP; + + mpcs->rstc = of_reset_control_get_shared(np->parent, NULL); + if (IS_ERR(mpcs->rstc)) + return PTR_ERR(mpcs->rstc); + + reset_control_deassert(mpcs->rstc); + mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel"); + if (IS_ERR(mpcs->sgmii_sel)) + return PTR_ERR(mpcs->sgmii_sel); + + mpcs->sgmii_rx = devm_clk_get(dev, "sgmii_rx"); + if (IS_ERR(mpcs->sgmii_rx)) + return PTR_ERR(mpcs->sgmii_rx); + + mpcs->sgmii_tx = devm_clk_get(dev, "sgmii_tx"); + if (IS_ERR(mpcs->sgmii_tx)) + return PTR_ERR(mpcs->sgmii_tx); + + pcs = mtk_pcs_lynxi_init(dev, regmap, (uintptr_t)of_device_get_match_data(dev), + flags, mpcs); + if (IS_ERR(pcs)) + return PTR_ERR(pcs); + + regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD); + + platform_set_drvdata(pdev, mpcs); + + mutex_lock(&instance_mutex); + list_add_tail(&mpcs->node, &mtk_pcs_lynxi_instances); + mutex_unlock(&instance_mutex); + + return 0; +} + +static void mtk_pcs_lynxi_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_pcs_lynxi *cur, *tmp; + + mutex_lock(&instance_mutex); + list_for_each_entry_safe(cur, tmp, &mtk_pcs_lynxi_instances, node) + if (cur->dev == dev) { + list_del(&cur->node); + kfree(cur); + break; + } + mutex_unlock(&instance_mutex); +} + +static const struct of_device_id mtk_pcs_lynxi_of_match[] = { + { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mtk_pcs_lynxi_of_match); + +struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np) +{ + struct platform_device *pdev; + struct mtk_pcs_lynxi *mpcs; + + if (!np) + return NULL; + + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); + + if (!of_match_node(mtk_pcs_lynxi_of_match, np)) + return ERR_PTR(-EINVAL); + + pdev = of_find_device_by_node(np); + if (!pdev || !platform_get_drvdata(pdev)) { + if (pdev) + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + + mpcs = platform_get_drvdata(pdev); + device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + + return &mpcs->pcs; +} +EXPORT_SYMBOL(mtk_pcs_lynxi_get); + +void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) +{ + struct mtk_pcs_lynxi *cur, *mpcs = NULL; + + if (!pcs) + return; + + mutex_lock(&instance_mutex); + list_for_each_entry(cur, &mtk_pcs_lynxi_instances, node) + if (pcs == &cur->pcs) { + mpcs = cur; + break; + } + mutex_unlock(&instance_mutex); + + if (WARN_ON(!mpcs)) + return; + + put_device(mpcs->dev); +} +EXPORT_SYMBOL(mtk_pcs_lynxi_put); + +static struct platform_driver mtk_pcs_lynxi_driver = { + .driver = { + .name = "mtk-pcs-lynxi", + .suppress_bind_attrs = true, + .of_match_table = mtk_pcs_lynxi_of_match, + }, + .probe = mtk_pcs_lynxi_probe, + .remove_new = mtk_pcs_lynxi_remove, +}; +module_platform_driver(mtk_pcs_lynxi_driver); + +MODULE_AUTHOR("Daniel Golle "); MODULE_DESCRIPTION("MediaTek SGMII library for LynxI"); MODULE_LICENSE("GPL"); diff --git a/include/linux/pcs/pcs-mtk-lynxi.h b/include/linux/pcs/pcs-mtk-lynxi.h index be3b4ab32f4a..2d44e951229c 100644 --- a/include/linux/pcs/pcs-mtk-lynxi.h +++ b/include/linux/pcs/pcs-mtk-lynxi.h @@ -10,4 +10,15 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, struct regmap *regmap, u32 ana_rgc3, u32 flags); void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs); + +#if IS_ENABLED(CONFIG_PCS_MTK_LYNXI) +struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np); +void mtk_pcs_lynxi_put(struct phylink_pcs *pcs); +#else +static inline struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np) +{ + return NULL; +} +static inline void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) { } +#endif /* IS_ENABLED(CONFIG_PCS_MTK_LYNXI) */ #endif -- 2.51.0 From a09eaf2a559be259da7878179db062e574fcf9ad Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 12 Dec 2023 03:47:31 +0000 Subject: [PATCH 305/517] dt-bindings: net: pcs: add bindings for MediaTek USXGMII PCS MediaTek's USXGMII can be found in the MT7988 SoC. We need to access it in order to configure and monitor the Ethernet SerDes link in USXGMII, 10GBase-R and 5GBase-R mode. By including a wrapped legacy 1000Base-X/2500Base-X/Cisco SGMII LynxI PCS as well, those interface modes are also available. Signed-off-by: Daniel Golle --- .../bindings/net/pcs/mediatek,usxgmii.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml diff --git a/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml b/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml new file mode 100644 index 000000000000..0cdaa3545edb --- /dev/null +++ b/Documentation/devicetree/bindings/net/pcs/mediatek,usxgmii.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/pcs/mediatek,usxgmii.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek USXGMII PCS + +maintainers: + - Daniel Golle + +description: + The MediaTek USXGMII PCS provides physical link control and status + for USXGMII, 10GBase-R and 5GBase-R links on the SerDes interfaces + provided by the PEXTP PHY. + In order to also support legacy 2500Base-X, 1000Base-X and Cisco + SGMII an existing mediatek,*-sgmiisys LynxI PCS is wrapped to + provide those interfaces modes on the same SerDes interfaces shared + with the USXGMII PCS. + +properties: + $nodename: + pattern: "^pcs@[0-9a-f]+$" + + compatible: + const: mediatek,mt7988-usxgmiisys + + reg: + maxItems: 1 + + clocks: + items: + - description: USXGMII top-level clock + + resets: + items: + - description: XFI reset + +required: + - compatible + - reg + - clocks + - resets + +additionalProperties: false + +examples: + - | + #include + #define MT7988_TOPRGU_XFI0_GRST 12 + soc { + #address-cells = <2>; + #size-cells = <2>; + usxgmiisys0: pcs@10080000 { + compatible = "mediatek,mt7988-usxgmiisys"; + reg = <0 0x10080000 0 0x1000>; + clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>; + resets = <&watchdog MT7988_TOPRGU_XFI0_GRST>; + }; + }; -- 2.51.0 From 0005a0d86158863f4dd392dae5faca22f13d5f0e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 12 Dec 2023 03:47:47 +0000 Subject: [PATCH 306/517] net: pcs: add driver for MediaTek USXGMII PCS Add driver for USXGMII PCS found in the MediaTek MT7988 SoC and supporting USXGMII, 10GBase-R and 5GBase-R interface modes. Signed-off-by: Daniel Golle --- MAINTAINERS | 2 + drivers/net/pcs/Kconfig | 11 + drivers/net/pcs/Makefile | 1 + drivers/net/pcs/pcs-mtk-usxgmii.c | 454 ++++++++++++++++++++++++++++ include/linux/pcs/pcs-mtk-usxgmii.h | 27 ++ 5 files changed, 495 insertions(+) create mode 100644 drivers/net/pcs/pcs-mtk-usxgmii.c create mode 100644 include/linux/pcs/pcs-mtk-usxgmii.h diff --git a/MAINTAINERS b/MAINTAINERS index dcb5c71bc204..3a22c29b35a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14419,7 +14419,9 @@ M: Daniel Golle L: netdev@vger.kernel.org S: Maintained F: drivers/net/pcs/pcs-mtk-lynxi.c +F: drivers/net/pcs/pcs-mtk-usxgmii.c F: include/linux/pcs/pcs-mtk-lynxi.h +F: include/linux/pcs/pcs-mtk-usxgmii.h MEDIATEK ETHERNET PHY DRIVERS M: Daniel Golle diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig index f6aa437473de..8c642da2c6e0 100644 --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig @@ -25,6 +25,17 @@ config PCS_MTK_LYNXI This module provides helpers to phylink for managing the LynxI PCS which is part of MediaTek's SoC and Ethernet switch ICs. +config PCS_MTK_USXGMII + tristate "MediaTek USXGMII PCS" + select PCS_MTK_LYNXI + select PHY_MTK_PEXTP + select PHYLINK + help + This module provides a driver for MediaTek's USXGMII PCS supporting + 10GBase-R, 5GBase-R and USXGMII interface modes. + 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same + differential pairs via an embedded LynxI PHY. + config PCS_RZN1_MIIC tristate "Renesas RZ/N1 MII converter" depends on OF && (ARCH_RZN1 || COMPILE_TEST) diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile index 4f7920618b90..20647ac375d5 100644 --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o +obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o diff --git a/drivers/net/pcs/pcs-mtk-usxgmii.c b/drivers/net/pcs/pcs-mtk-usxgmii.c new file mode 100644 index 000000000000..9691d9e73790 --- /dev/null +++ b/drivers/net/pcs/pcs-mtk-usxgmii.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Henry Yen + * Daniel Golle + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* USXGMII subsystem config registers */ +/* Register to control speed */ +#define RG_PHY_TOP_SPEED_CTRL1 0x80c +#define USXGMII_RATE_UPDATE_MODE BIT(31) +#define USXGMII_MAC_CK_GATED BIT(29) +#define USXGMII_IF_FORCE_EN BIT(28) +#define USXGMII_RATE_ADAPT_MODE GENMASK(10, 8) +#define USXGMII_RATE_ADAPT_MODE_X1 0 +#define USXGMII_RATE_ADAPT_MODE_X2 1 +#define USXGMII_RATE_ADAPT_MODE_X4 2 +#define USXGMII_RATE_ADAPT_MODE_X10 3 +#define USXGMII_RATE_ADAPT_MODE_X100 4 +#define USXGMII_RATE_ADAPT_MODE_X5 5 +#define USXGMII_RATE_ADAPT_MODE_X50 6 +#define USXGMII_XFI_RX_MODE GENMASK(6, 4) +#define USXGMII_XFI_TX_MODE GENMASK(2, 0) +#define USXGMII_XFI_MODE_10G 0 +#define USXGMII_XFI_MODE_5G 1 +#define USXGMII_XFI_MODE_2P5G 3 + +/* Register to control PCS AN */ +#define RG_PCS_AN_CTRL0 0x810 +#define USXGMII_AN_RESTART BIT(31) +#define USXGMII_AN_SYNC_CNT GENMASK(30, 11) +#define USXGMII_AN_ENABLE BIT(0) + +#define RG_PCS_AN_CTRL2 0x818 +#define USXGMII_LINK_TIMER_IDLE_DETECT GENMASK(29, 20) +#define USXGMII_LINK_TIMER_COMP_ACK_DETECT GENMASK(19, 10) +#define USXGMII_LINK_TIMER_AN_RESTART GENMASK(9, 0) + +/* Register to read PCS AN status */ +#define RG_PCS_AN_STS0 0x81c +#define USXGMII_LPA GENMASK(15, 0) +#define USXGMII_LPA_LATCH BIT(31) + +/* Register to read PCS link status */ +#define RG_PCS_RX_STATUS0 0x904 +#define RG_PCS_RX_STATUS_UPDATE BIT(16) +#define RG_PCS_RX_LINK_STATUS BIT(2) + +/* struct mtk_usxgmii_pcs - This structure holds each usxgmii PCS + * @pcs: Phylink PCS structure + * @dev: Pointer to device structure + * @base: IO memory to access PCS hardware + * @clk: Pointer to USXGMII clk + * @reset: Pointer to USXGMII reset control + * @interface: Currently selected interface mode + * @neg_mode: Currently used phylink neg_mode + * @node: List node + */ +struct mtk_usxgmii_pcs { + struct phylink_pcs pcs; + struct device *dev; + void __iomem *base; + struct clk *clk; + struct reset_control *reset; + phy_interface_t interface; + unsigned int neg_mode; + struct list_head node; +}; + +static LIST_HEAD(mtk_usxgmii_pcs_instances); +static DEFINE_MUTEX(instance_mutex); + +static u32 mtk_r32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg) +{ + return ioread32(mpcs->base + reg); +} + +static void mtk_m32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg, u32 mask, u32 set) +{ + u32 val; + + val = ioread32(mpcs->base + reg); + val &= ~mask; + val |= set; + iowrite32(val, mpcs->base + reg); +} + +static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct mtk_usxgmii_pcs, pcs); +} + +static void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs) +{ + reset_control_assert(mpcs->reset); + udelay(100); + reset_control_deassert(mpcs->reset); + + mdelay(10); +} + +static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); + unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0; + bool mode_changed = false; + + if (interface == PHY_INTERFACE_MODE_USXGMII) { + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) | USXGMII_AN_ENABLE; + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); + } else if (interface == PHY_INTERFACE_MODE_10GBASER) { + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF); + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); + adapt_mode = USXGMII_RATE_UPDATE_MODE; + } else if (interface == PHY_INTERFACE_MODE_5GBASER) { + an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF); + link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) | + FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) | + FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D); + xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_5G) | + FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_5G); + adapt_mode = USXGMII_RATE_UPDATE_MODE; + } else { + return -EINVAL; + } + + adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1); + + if (mpcs->interface != interface) { + mpcs->interface = interface; + mode_changed = true; + } + + mtk_usxgmii_reset(mpcs); + + /* Setup USXGMII AN ctrl */ + mtk_m32(mpcs, RG_PCS_AN_CTRL0, + USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE, + an_ctrl); + + mtk_m32(mpcs, RG_PCS_AN_CTRL2, + USXGMII_LINK_TIMER_IDLE_DETECT | + USXGMII_LINK_TIMER_COMP_ACK_DETECT | + USXGMII_LINK_TIMER_AN_RESTART, + link_timer); + + mpcs->neg_mode = neg_mode; + + /* Gated MAC CK */ + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, + USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED); + + /* Enable interface force mode */ + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, + USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN); + + /* Setup USXGMII adapt mode */ + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, + USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE, + adapt_mode); + + /* Setup USXGMII speed */ + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, + USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE, + xfi_mode); + + usleep_range(1, 10); + + /* Un-gated MAC CK */ + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_MAC_CK_GATED, 0); + + usleep_range(1, 10); + + /* Disable interface force mode for the AN mode */ + if (an_ctrl & USXGMII_AN_ENABLE) + mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_IF_FORCE_EN, 0); + + return mode_changed; +} + +static void mtk_usxgmii_pcs_get_fixed_speed(struct mtk_usxgmii_pcs *mpcs, + struct phylink_link_state *state) +{ + u32 val = mtk_r32(mpcs, RG_PHY_TOP_SPEED_CTRL1); + int speed; + + /* Calculate speed from interface speed and rate adapt mode */ + switch (FIELD_GET(USXGMII_XFI_RX_MODE, val)) { + case USXGMII_XFI_MODE_10G: + speed = 10000; + break; + case USXGMII_XFI_MODE_5G: + speed = 5000; + break; + case USXGMII_XFI_MODE_2P5G: + speed = 2500; + break; + default: + state->speed = SPEED_UNKNOWN; + return; + } + + switch (FIELD_GET(USXGMII_RATE_ADAPT_MODE, val)) { + case USXGMII_RATE_ADAPT_MODE_X100: + speed /= 100; + break; + case USXGMII_RATE_ADAPT_MODE_X50: + speed /= 50; + break; + case USXGMII_RATE_ADAPT_MODE_X10: + speed /= 10; + break; + case USXGMII_RATE_ADAPT_MODE_X5: + speed /= 5; + break; + case USXGMII_RATE_ADAPT_MODE_X4: + speed /= 4; + break; + case USXGMII_RATE_ADAPT_MODE_X2: + speed /= 2; + break; + case USXGMII_RATE_ADAPT_MODE_X1: + break; + default: + state->speed = SPEED_UNKNOWN; + return; + } + + state->speed = speed; + state->duplex = DUPLEX_FULL; +} + +static void mtk_usxgmii_pcs_get_an_state(struct mtk_usxgmii_pcs *mpcs, + struct phylink_link_state *state) +{ + u16 lpa; + + /* Refresh LPA by toggling LPA_LATCH */ + mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, USXGMII_LPA_LATCH); + ndelay(1020); + mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, 0); + ndelay(1020); + lpa = FIELD_GET(USXGMII_LPA, mtk_r32(mpcs, RG_PCS_AN_STS0)); + + phylink_decode_usxgmii_word(state, lpa); +} + +static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); + + /* Refresh USXGMII link status by toggling RG_PCS_AN_STATUS_UPDATE */ + mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, + RG_PCS_RX_STATUS_UPDATE); + ndelay(1020); + mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, 0); + ndelay(1020); + + /* Read USXGMII link status */ + state->link = FIELD_GET(RG_PCS_RX_LINK_STATUS, + mtk_r32(mpcs, RG_PCS_RX_STATUS0)); + + /* Continuously repeat re-configuration sequence until link comes up */ + if (!state->link) { + mtk_usxgmii_pcs_config(pcs, mpcs->neg_mode, + state->interface, NULL, false); + return; + } + + if (FIELD_GET(USXGMII_AN_ENABLE, mtk_r32(mpcs, RG_PCS_AN_CTRL0))) + mtk_usxgmii_pcs_get_an_state(mpcs, state); + else + mtk_usxgmii_pcs_get_fixed_speed(mpcs, state); +} + +static void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs) +{ + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); + + mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_RESTART, USXGMII_AN_RESTART); +} + +static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, + int speed, int duplex) +{ + /* Reconfiguring USXGMII to ensure the quality of the RX signal + * after the line side link up. + */ + mtk_usxgmii_pcs_config(pcs, neg_mode, interface, NULL, false); +} + +static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs) +{ + struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); + + mpcs->interface = PHY_INTERFACE_MODE_NA; + mpcs->neg_mode = -1; +} + +static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = { + .pcs_config = mtk_usxgmii_pcs_config, + .pcs_get_state = mtk_usxgmii_pcs_get_state, + .pcs_an_restart = mtk_usxgmii_pcs_restart_an, + .pcs_link_up = mtk_usxgmii_pcs_link_up, + .pcs_disable = mtk_usxgmii_pcs_disable, +}; + +static int mtk_usxgmii_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_usxgmii_pcs *mpcs; + + mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); + if (!mpcs) + return -ENOMEM; + + mpcs->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mpcs->base)) + return PTR_ERR(mpcs->base); + + mpcs->dev = dev; + mpcs->pcs.ops = &mtk_usxgmii_pcs_ops; + mpcs->pcs.poll = true; + mpcs->pcs.neg_mode = true; + mpcs->interface = PHY_INTERFACE_MODE_NA; + mpcs->neg_mode = -1; + + mpcs->clk = devm_clk_get_enabled(mpcs->dev, NULL); + if (IS_ERR(mpcs->clk)) + return PTR_ERR(mpcs->clk); + + mpcs->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(mpcs->reset)) + return PTR_ERR(mpcs->reset); + + reset_control_deassert(mpcs->reset); + + platform_set_drvdata(pdev, mpcs); + + mutex_lock(&instance_mutex); + list_add_tail(&mpcs->node, &mtk_usxgmii_pcs_instances); + mutex_unlock(&instance_mutex); + + return 0; +} + +static void mtk_usxgmii_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_usxgmii_pcs *cur, *tmp; + + mutex_lock(&instance_mutex); + list_for_each_entry_safe(cur, tmp, &mtk_usxgmii_pcs_instances, node) + if (cur->dev == dev) { + list_del(&cur->node); + break; + } + mutex_unlock(&instance_mutex); +} + +static const struct of_device_id mtk_usxgmii_of_mtable[] = { + { .compatible = "mediatek,mt7988-usxgmiisys" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mtk_usxgmii_of_mtable); + +struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np) +{ + struct platform_device *pdev; + struct mtk_usxgmii_pcs *mpcs; + + if (!np) + return NULL; + + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); + + if (!of_match_node(mtk_usxgmii_of_mtable, np)) + return ERR_PTR(-EINVAL); + + pdev = of_find_device_by_node(np); + if (!pdev || !platform_get_drvdata(pdev)) { + if (pdev) + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + + mpcs = platform_get_drvdata(pdev); + device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + + return &mpcs->pcs; +} +EXPORT_SYMBOL(mtk_usxgmii_pcs_get); + +void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) +{ + struct mtk_usxgmii_pcs *cur, *mpcs = NULL; + + if (!pcs) + return; + + mutex_lock(&instance_mutex); + list_for_each_entry(cur, &mtk_usxgmii_pcs_instances, node) + if (pcs == &cur->pcs) { + mpcs = cur; + break; + } + mutex_unlock(&instance_mutex); + + if (WARN_ON(!mpcs)) + return; + + put_device(mpcs->dev); +} +EXPORT_SYMBOL(mtk_usxgmii_pcs_put); + +static struct platform_driver mtk_usxgmii_driver = { + .driver = { + .name = "mtk_usxgmii", + .suppress_bind_attrs = true, + .of_match_table = mtk_usxgmii_of_mtable, + }, + .probe = mtk_usxgmii_probe, + .remove_new = mtk_usxgmii_remove, +}; +module_platform_driver(mtk_usxgmii_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek USXGMII PCS driver"); +MODULE_AUTHOR("Daniel Golle "); diff --git a/include/linux/pcs/pcs-mtk-usxgmii.h b/include/linux/pcs/pcs-mtk-usxgmii.h new file mode 100644 index 000000000000..ef936d9c5f11 --- /dev/null +++ b/include/linux/pcs/pcs-mtk-usxgmii.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_PCS_MTK_USXGMII_H +#define __LINUX_PCS_MTK_USXGMII_H + +#include + +/** + * mtk_usxgmii_select_pcs() - Get MediaTek PCS instance + * @np: Pointer to device node indentifying a MediaTek USXGMII PCS + * @mode: Ethernet PHY interface mode + * + * Return PCS identified by a device node and the PHY interface mode in use + * + * Return: Pointer to phylink PCS instance of NULL + */ +#if IS_ENABLED(CONFIG_PCS_MTK_USXGMII) +struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np); +void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs); +#else +static inline struct phylink_pcs *mtk_usxgmii_pcs_get(struct device *dev, struct device_node *np) +{ + return NULL; +} +static inline void mtk_usxgmii_pcs_put(struct phylink_pcs *pcs) { } +#endif /* IS_ENABLED(CONFIG_PCS_MTK_USXGMII) */ + +#endif /* __LINUX_PCS_MTK_USXGMII_H */ -- 2.51.0 From 8d0a817f11fff5555100d757f73aa7d702774a83 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 21 May 2023 22:24:56 +0200 Subject: [PATCH 307/517] net: phy: motorcomm: Add missing include Directly include linux/bitfield.h which provides FIELD_PREP. Signed-off-by: Hauke Mehrtens --- drivers/net/phy/motorcomm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 0e91f5d1a4fd..cb57ebb87237 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -6,6 +6,7 @@ * Author: Frank */ +#include #include #include #include -- 2.51.0 From 64c6f86708f9e4ccf5e70f38508f88be90d095c9 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 16 Nov 2024 22:36:15 +0100 Subject: [PATCH 308/517] net: phy: broadcom: update dependency condition The broadcom PHY driver only has to depend upon PTP_1588_CLOCK_OPTIONAL if NETWORK_PHY_TIMESTAMPING is enabled. The PTP functionality is stubbed in this case. Reflect this circumstance in the dependence condition. This allows to build the driver as a built-in module even if PTP is built as a module. This is required to include the broadcom PHY module regardless of the built-setting of the PTP subsystem. On ath79 (and probably more) targets with Broadcom PHY, Gigabit operation is currently broken as the PHY driver is only built as a module in case all kernel-packages are built. Due to this circumstance, affected devices fall back to using the generic PHY driver. Signed-off-by: David Bauer --- drivers/net/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bf7c34402e74..8c92405b84d4 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -151,7 +151,7 @@ config BROADCOM_PHY tristate "Broadcom 54XX PHYs" select BCM_NET_PHYLIB select BCM_NET_PHYPTP if NETWORK_PHY_TIMESTAMPING - depends on PTP_1588_CLOCK_OPTIONAL + depends on NETWORK_PHY_TIMESTAMPING=n || PTP_1588_CLOCK_OPTIONAL help Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, BCM5481, BCM54810 and BCM5482 PHYs. -- 2.51.0 From e3a83bc28d2d129742cc38dbb1e652c9839c110b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 5 Aug 2021 23:23:30 +0100 Subject: [PATCH 309/517] ARM: kirkwood: add missing for ETH_ALEN After commit 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()") build fails for kirkwood as ETH_ALEN is not defined. arch/arm/mach-mvebu/kirkwood.c: In function 'kirkwood_dt_eth_fixup': arch/arm/mach-mvebu/kirkwood.c:87:13: error: 'ETH_ALEN' undeclared (first use in this function); did you mean 'ESTALE'? u8 tmpmac[ETH_ALEN]; ^~~~~~~~ ESTALE arch/arm/mach-mvebu/kirkwood.c:87:13: note: each undeclared identifier is reported only once for each function it appears in arch/arm/mach-mvebu/kirkwood.c:87:6: warning: unused variable 'tmpmac' [-Wunused-variable] u8 tmpmac[ETH_ALEN]; ^~~~~~ make[5]: *** [scripts/Makefile.build:262: arch/arm/mach-mvebu/kirkwood.o] Error 1 make[5]: *** Waiting for unfinished jobs.... Add missing #include to fix this. Cc: David S. Miller Cc: Andrew Lunn Cc: Michael Walle Reported-by: https://buildbot.openwrt.org/master/images/#/builders/56/builds/220/steps/44/logs/stdio Fixes: 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()") Signed-off-by: Daniel Golle --- arch/arm/mach-mvebu/kirkwood.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index 73b2a86d6489..b375df4010c2 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include -- 2.51.0 From 47f8ae989e1a237b33f2e91babea618444b71d42 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sat, 5 Nov 2022 20:02:56 +0100 Subject: [PATCH 310/517] bus: mhi: core: add SBL state callback Add support for SBL state callback in MHI core. It is required for ath11k MHI devices in order to be able to set QRTR instance ID in the SBL state so that QRTR instance ID-s dont conflict in case of multiple PCI/MHI cards or AHB + PCI/MHI card. Setting QRTR instance ID is only possible in SBL state and there is currently no way to ensure that we are in that state, so provide a callback that the controller can trigger off. Signed-off-by: Robert Marko --- drivers/bus/mhi/host/main.c | 1 + include/linux/mhi.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index 45ec1b585577..45b28cd4f9b8 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -916,6 +916,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl, switch (event) { case MHI_EE_SBL: st = DEV_ST_TRANSITION_SBL; + mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_SBL_MODE); break; case MHI_EE_WFW: case MHI_EE_AMSS: diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 059dc94d20bb..b2f1cf400065 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -34,6 +34,7 @@ struct mhi_buf_info; * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover) * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state * @MHI_CB_BW_REQ: Received a bandwidth switch request from device + * @MHI_CB_EE_SBL_MODE: MHI device entered SBL mode */ enum mhi_callback { MHI_CB_IDLE, @@ -45,6 +46,7 @@ enum mhi_callback { MHI_CB_SYS_ERROR, MHI_CB_FATAL_ERROR, MHI_CB_BW_REQ, + MHI_CB_EE_SBL_MODE, }; /** -- 2.51.0 From e75c28fcf09e756a41d0be9abc31eaa86b8f5ca3 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Tue, 10 Dec 2024 03:28:31 -0800 Subject: [PATCH 311/517] tg3: Fix DMA allocations on 57766 devices The coherent DMA mask of 31b may not be accepted if the DMA mask is configured to use higher memories of 64b. Set the DMA mask also to lower 32b for 57766 devices. Fixes: 614f4d166eee ("tg3: Set coherent DMA mask bits to 31 for BCM57766 chipsets") Reported-By: Rui Salvaterra Signed-off-by: Pavan Chebbi --- drivers/net/ethernet/broadcom/tg3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index dc170feee8ad..cf61cb311f23 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17799,8 +17799,10 @@ static int tg3_init_one(struct pci_dev *pdev, } else persist_dma_mask = dma_mask = DMA_BIT_MASK(64); - if (tg3_asic_rev(tp) == ASIC_REV_57766) + if (tg3_asic_rev(tp) == ASIC_REV_57766) { + dma_mask = DMA_BIT_MASK(32); persist_dma_mask = DMA_BIT_MASK(31); + } /* Configure DMA attributes. */ if (dma_mask > DMA_BIT_MASK(32)) { -- 2.51.0 From 672489ca59270bcbe18cf959c77b9401292371e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 3 Nov 2025 15:50:09 +0100 Subject: [PATCH 312/517] bcma: get SoC device struct & copy its DMA params to the subdevices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For bus devices to be fully usable it's required to set their DMA parameters. For years it has been missing and remained unnoticed because of mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask. Kernel 4.19 came with a lot of DMA changes and caused a regression on the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") DMA coherent allocations just fail. Example: [ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed [ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA [ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12 [ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded This change fixes above regression in addition to the MIPS bcm47xx commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC"). It also fixes another *old* GPIO regression caused by a parent pointing to the NULL: [ 0.157054] missing gpiochip .dev parent pointer [ 0.157287] bcma: bus0: Error registering GPIO driver: -22 introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP"). Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP") Cc: linux-mips@linux-mips.org Cc: Christoph Hellwig Cc: Linus Walleij Signed-off-by: Rafał Miłecki --- drivers/bcma/host_soc.c | 2 ++ drivers/bcma/main.c | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 8ae0b918e740..280c2caeaf86 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcma_soc *soc) struct bcma_bus *bus = &soc->bus; int err; + bus->dev = soc->dev; + /* Scan bus and initialize it */ err = bcma_bus_early_register(bus); if (err) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 6ecfc821cf83..6842fe781eef 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -237,13 +237,17 @@ EXPORT_SYMBOL(bcma_core_irq); void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) { - device_initialize(&core->dev); + struct device *dev = &core->dev; + + device_initialize(dev); core->dev.release = bcma_release_core_dev; core->dev.bus = &bcma_bus_type; - dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); + dev_set_name(dev, "bcma%d:%d", bus->num, core->core_index); core->dev.parent = bus->dev; - if (bus->dev) + if (bus->dev) { bcma_of_fill_device(bus->dev, core); + dma_coerce_mask_and_coherent(dev, bus->dev->coherent_dma_mask); + } switch (bus->hosttype) { case BCMA_HOSTTYPE_PCI: -- 2.51.0 From cf2b01ee5a6c91e55e54d40ebc0382ba875b19d5 Mon Sep 17 00:00:00 2001 From: Mauri Sandberg Date: Thu, 25 Mar 2021 11:48:05 +0200 Subject: [PATCH 313/517] gpio: gpio-cascade: add generic GPIO cascade Adds support for building cascades of GPIO lines. That is, it allows setups when there is one upstream line and multiple cascaded lines, out of which one can be chosen at a time. The status of the upstream line can be conveyed to the selected cascaded line or, vice versa, the status of the cascaded line can be conveyed to the upstream line. A multiplexer is being used to select, which cascaded GPIO line is being used at any given time. At the moment only input direction is supported. In future it should be possible to add support for output direction, too. Signed-off-by: Mauri Sandberg Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko --- drivers/gpio/Kconfig | 15 +++++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-cascade.c | 112 ++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 drivers/gpio/gpio-cascade.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d93cd4f722b4..6c74cafa987e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1929,4 +1929,19 @@ config GPIO_VIRTUSER endmenu +comment "Other GPIO expanders" + +config GPIO_CASCADE + tristate "General GPIO cascade" + select MULTIPLEXER + help + Say yes here to enable support for generic GPIO cascade. + + This allows building one-to-many cascades of GPIO lines using + different types of multiplexers readily available. At the + moment only input lines are supported. + + To build the driver as a module choose 'm' and the resulting module + will be called 'gpio-cascade'. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1429e8c0229b..b0c5979fd84e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o +obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o diff --git a/drivers/gpio/gpio-cascade.c b/drivers/gpio/gpio-cascade.c new file mode 100644 index 000000000000..5fae4f46ecf3 --- /dev/null +++ b/drivers/gpio/gpio-cascade.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * A generic GPIO cascade driver + * + * Copyright (C) 2021 Mauri Sandberg + * + * This allows building cascades of GPIO lines in a manner illustrated + * below: + * + * /|---- Cascaded GPIO line 0 + * Upstream | |---- Cascaded GPIO line 1 + * GPIO line ----+ | . + * | | . + * \|---- Cascaded GPIO line n + * + * A multiplexer is being used to select, which cascaded line is being + * addressed at any given time. + * + * At the moment only input mode is supported due to lack of means for + * testing output functionality. At least theoretically output should be + * possible with open drain constructions. + */ + +#include +#include +#include +#include + +#include +#include + +struct gpio_cascade { + struct gpio_chip gpio_chip; + struct device *parent; + struct mux_control *mux_control; + struct gpio_desc *upstream_line; +}; + +static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + return GPIO_LINE_DIRECTION_IN; +} + +static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_cascade *cas = gpiochip_get_data(gc); + int ret; + + ret = mux_control_select(cas->mux_control, offset); + if (ret) + return ret; + + ret = gpiod_get_value(cas->upstream_line); + mux_control_deselect(cas->mux_control); + return ret; +} + +static int gpio_cascade_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_cascade *cas; + struct mux_control *mc; + struct gpio_desc *upstream; + struct gpio_chip *gc; + + cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL); + if (!cas) + return -ENOMEM; + + mc = devm_mux_control_get(dev, NULL); + if (IS_ERR(mc)) + return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n"); + + cas->mux_control = mc; + upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN); + if (IS_ERR(upstream)) + return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n"); + + cas->upstream_line = upstream; + cas->parent = dev; + + gc = &cas->gpio_chip; + gc->get = gpio_cascade_get_value; + gc->get_direction = gpio_cascade_get_direction; + gc->base = -1; + gc->ngpio = mux_control_states(mc); + gc->label = dev_name(cas->parent); + gc->parent = cas->parent; + gc->owner = THIS_MODULE; + + platform_set_drvdata(pdev, cas); + return devm_gpiochip_add_data(dev, &cas->gpio_chip, cas); +} + +static const struct of_device_id gpio_cascade_id[] = { + { .compatible = "gpio-cascade" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, gpio_cascade_id); + +static struct platform_driver gpio_cascade_driver = { + .driver = { + .name = "gpio-cascade", + .of_match_table = gpio_cascade_id, + }, + .probe = gpio_cascade_probe, +}; +module_platform_driver(gpio_cascade_driver); + +MODULE_AUTHOR("Mauri Sandberg "); +MODULE_DESCRIPTION("Generic GPIO cascade"); +MODULE_LICENSE("GPL"); -- 2.51.0 From 1e797580d94af360372d4ee9b0287b4add407be4 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 15 Sep 2022 18:49:43 +0200 Subject: [PATCH 314/517] OPP: Provide old opp to config_clks on _set_opp With the target opp, also pass the old opp to config_clks function. This can be useful when a driver needs to take decision on what fequency to set based on what is the current frequency without using a clk_get_freq call. Update the only user of custom config_clks (tegra30 devfreq driver) to this new implementation. Signed-off-by: Christian Marangi --- drivers/devfreq/tegra30-devfreq.c | 5 +++-- drivers/opp/core.c | 11 ++++++----- drivers/ufs/core/ufshcd.c | 4 ++-- include/linux/pm_opp.h | 11 ++++++----- include/ufs/ufshcd.h | 4 ++-- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c index 4a4f0106ab9d..82616eeca6c3 100644 --- a/drivers/devfreq/tegra30-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c @@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(struct device *dev, static int tegra_devfreq_config_clks_nop(struct device *dev, struct opp_table *opp_table, - struct dev_pm_opp *opp, void *data, - bool scaling_down) + struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, + void *data, bool scaling_down) { /* We want to skip clk configuration via dev_pm_opp_set_opp() */ return 0; diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 5ac209472c0c..07cfde8119bf 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -965,7 +965,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, static int _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, - struct dev_pm_opp *opp, void *data, bool scaling_down) + struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, + void *data, bool scaling_down) { unsigned long *target = data; unsigned long freq; @@ -997,8 +998,8 @@ _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, * the order in which they are present in the array while scaling up. */ int dev_pm_opp_config_clks_simple(struct device *dev, - struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, - bool scaling_down) + struct opp_table *opp_table, struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, void *data, bool scaling_down) { int ret, i; @@ -1265,7 +1266,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, } if (opp_table->config_clks) { - ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down); + ret = opp_table->config_clks(dev, opp_table, old_opp, opp, clk_data, scaling_down); if (ret) return ret; } @@ -1344,7 +1345,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) * equivalent to a clk_set_rate() */ if (!_get_opp_count(opp_table)) { - ret = opp_table->config_clks(dev, opp_table, NULL, + ret = opp_table->config_clks(dev, opp_table, NULL, NULL, &target_freq, false); goto put_opp_table; } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index e079cb5d9ec6..a700da1d03e5 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1119,8 +1119,8 @@ static int ufshcd_set_clk_freq(struct ufs_hba *hba, bool scale_up) } int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, - struct dev_pm_opp *opp, void *data, - bool scaling_down) + struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, + void *data, bool scaling_down) { struct ufs_hba *hba = dev_get_drvdata(dev); struct list_head *head = &hba->clk_list_head; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 6424692c30b7..44b50cf91e93 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -50,7 +50,8 @@ typedef int (*config_regulators_t)(struct device *dev, struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp, struct regulator **regulators, unsigned int count); -typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table, +typedef int (*config_clks_t)(struct device *dev, + struct opp_table *opp_table, struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, void *data, bool scaling_down); /** @@ -184,8 +185,8 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); void dev_pm_opp_clear_config(int token); int dev_pm_opp_config_clks_simple(struct device *dev, - struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, - bool scaling_down); + struct opp_table *opp_table, struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, void *data, bool scaling_down); struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); @@ -395,8 +396,8 @@ static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_c static inline void dev_pm_opp_clear_config(int token) {} static inline int dev_pm_opp_config_clks_simple(struct device *dev, - struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, - bool scaling_down) + struct opp_table *opp_table, struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, void *data, bool scaling_down) { return -EOPNOTSUPP; } diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 47cba116f87b..a303f853acf0 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -1326,8 +1326,8 @@ void ufshcd_mcq_enable(struct ufs_hba *hba); void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); int ufshcd_opp_config_clks(struct device *dev, struct opp_table *opp_table, - struct dev_pm_opp *opp, void *data, - bool scaling_down); + struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, + void *data, bool scaling_down); /** * ufshcd_set_variant - set variant specific data to the hba * @hba: per adapter instance -- 2.51.0 From af475ef6d3d0d36054adbf764810eafc2d0e3ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 13 Jul 2023 18:29:19 +0200 Subject: [PATCH 315/517] nvmem: core: support "mac-base" fixed layout cells Fixed layout binding allows specifying "mac-base" NVMEM cells. It's used for base MAC address (that can be used for calculating relative addresses). It can be stored in a raw binary format or as an ASCII string. --- drivers/nvmem/Kconfig | 1 + drivers/nvmem/core.c | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 40b5fd1bfde4..51257aa2cd3e 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -2,6 +2,7 @@ menuconfig NVMEM bool "NVMEM Support" imply NVMEM_LAYOUTS + select GENERIC_NET_UTILS help Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES... diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index d1869e6de384..f978adbc5fff 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -7,9 +7,12 @@ */ #include +#include +#include #include #include #include +#include #include #include #include @@ -811,6 +814,62 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem) return 0; } +static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + if (WARN_ON(bytes != ETH_ALEN)) + return -EINVAL; + + if (index) + eth_addr_add(buf, index); + + return 0; +} + +static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + u8 mac[ETH_ALEN]; + + if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) + return -EINVAL; + + if (!mac_pton(buf, mac)) + return -EINVAL; + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + +static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + u8 mac[ETH_ALEN], *hexstr; + int i; + + if (WARN_ON(bytes != 2 * ETH_ALEN)) + return -EINVAL; + + hexstr = (u8 *)buf; + for (i = 0; i < ETH_ALEN; i++) { + if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) + return -EINVAL; + + mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); + } + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) { struct device *dev = &nvmem->dev; @@ -852,6 +911,25 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod if (nvmem->fixup_dt_cell_info) nvmem->fixup_dt_cell_info(nvmem, &info); + if (of_device_is_compatible(np, "fixed-layout")) { + if (of_device_is_compatible(child, "mac-base")) { + if (info.bytes == ETH_ALEN) { + info.raw_len = info.bytes; + info.bytes = ETH_ALEN; + info.read_post_process = nvmem_mac_base_raw_read; + } else if (info.bytes == 2 * ETH_ALEN) { + info.raw_len = info.bytes; + info.bytes = ETH_ALEN; + info.read_post_process = nvmem_mac_base_hex_read; + } else if (info.bytes == 3 * ETH_ALEN - 1) { + info.raw_len = info.bytes; + info.bytes = ETH_ALEN; + info.read_post_process = nvmem_mac_base_ascii_read; + } + + } + } + ret = nvmem_add_one_cell(nvmem, &info); kfree(info.name); if (ret) { -- 2.51.0 From 38d604ad64b2a28e0d8560c01e741c2aada79bc8 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 3 Feb 2025 00:10:18 +0100 Subject: [PATCH 316/517] nvmem: core: generalize "mac-base" cells handling Generalize support of "mac-base" nvmem cells and provide a GPL symbol to permit also other NVMEM layout driver to parse mac-base cells. It's VERY COMMON for some specially formatted NVMEM to expose a mac address in ASCII format or HEX format hence prevent code duplication by exposing a common helper. Such helper will change the nvmem_info_cell and apply the correct post process function to correctly parse the mac address. Since the API requires OF and is only related to layout, move the function in layouts.c to correctly handle non-OF NVMEM. Signed-off-by: Christian Marangi --- drivers/nvmem/core.c | 79 +-------------------------------- drivers/nvmem/layouts.c | 80 ++++++++++++++++++++++++++++++++++ include/linux/nvmem-provider.h | 4 ++ 3 files changed, 86 insertions(+), 77 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index f978adbc5fff..9b9177e28706 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -7,12 +7,9 @@ */ #include -#include -#include #include #include #include -#include #include #include #include @@ -814,62 +811,6 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem) return 0; } -static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, - void *buf, size_t bytes) -{ - if (WARN_ON(bytes != ETH_ALEN)) - return -EINVAL; - - if (index) - eth_addr_add(buf, index); - - return 0; -} - -static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, - void *buf, size_t bytes) -{ - u8 mac[ETH_ALEN]; - - if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) - return -EINVAL; - - if (!mac_pton(buf, mac)) - return -EINVAL; - - if (index) - eth_addr_add(mac, index); - - ether_addr_copy(buf, mac); - - return 0; -} - -static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, - void *buf, size_t bytes) -{ - u8 mac[ETH_ALEN], *hexstr; - int i; - - if (WARN_ON(bytes != 2 * ETH_ALEN)) - return -EINVAL; - - hexstr = (u8 *)buf; - for (i = 0; i < ETH_ALEN; i++) { - if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) - return -EINVAL; - - mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); - } - - if (index) - eth_addr_add(mac, index); - - ether_addr_copy(buf, mac); - - return 0; -} - static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np) { struct device *dev = &nvmem->dev; @@ -911,24 +852,8 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod if (nvmem->fixup_dt_cell_info) nvmem->fixup_dt_cell_info(nvmem, &info); - if (of_device_is_compatible(np, "fixed-layout")) { - if (of_device_is_compatible(child, "mac-base")) { - if (info.bytes == ETH_ALEN) { - info.raw_len = info.bytes; - info.bytes = ETH_ALEN; - info.read_post_process = nvmem_mac_base_raw_read; - } else if (info.bytes == 2 * ETH_ALEN) { - info.raw_len = info.bytes; - info.bytes = ETH_ALEN; - info.read_post_process = nvmem_mac_base_hex_read; - } else if (info.bytes == 3 * ETH_ALEN - 1) { - info.raw_len = info.bytes; - info.bytes = ETH_ALEN; - info.read_post_process = nvmem_mac_base_ascii_read; - } - - } - } + if (of_device_is_compatible(np, "fixed-layout")) + nvmem_layout_parse_mac_base(&info); ret = nvmem_add_one_cell(nvmem, &info); kfree(info.name); diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c index f381ce1e84bd..3220cd20c33a 100644 --- a/drivers/nvmem/layouts.c +++ b/drivers/nvmem/layouts.c @@ -6,8 +6,11 @@ * Author: Miquel Raynal #include #include +#include +#include #include #include #include @@ -21,6 +24,83 @@ #define to_nvmem_layout_device(_dev) \ container_of((_dev), struct nvmem_layout, dev) +static int nvmem_mac_base_raw_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + if (WARN_ON(bytes != ETH_ALEN)) + return -EINVAL; + + if (index) + eth_addr_add(buf, index); + + return 0; +} + +static int nvmem_mac_base_ascii_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + u8 mac[ETH_ALEN]; + + if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) + return -EINVAL; + + if (!mac_pton(buf, mac)) + return -EINVAL; + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + +static int nvmem_mac_base_hex_read(void *context, const char *id, int index, unsigned int offset, + void *buf, size_t bytes) +{ + u8 mac[ETH_ALEN], *hexstr; + int i; + + if (WARN_ON(bytes != 2 * ETH_ALEN)) + return -EINVAL; + + hexstr = (u8 *)buf; + for (i = 0; i < ETH_ALEN; i++) { + if (!isxdigit(hexstr[i * 2]) || !isxdigit(hexstr[i * 2 + 1])) + return -EINVAL; + + mac[i] = (hex_to_bin(hexstr[i * 2]) << 4) | hex_to_bin(hexstr[i * 2 + 1]); + } + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + +void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) +{ + if (!of_device_is_compatible(info->np, "mac-base")) + return; + + if (info->bytes == ETH_ALEN) { + info->raw_len = info->bytes; + info->bytes = ETH_ALEN; + info->read_post_process = nvmem_mac_base_raw_read; + } else if (info->bytes == 2 * ETH_ALEN) { + info->raw_len = info->bytes; + info->bytes = ETH_ALEN; + info->read_post_process = nvmem_mac_base_hex_read; + } else if (info->bytes == 3 * ETH_ALEN - 1) { + info->raw_len = info->bytes; + info->bytes = ETH_ALEN; + info->read_post_process = nvmem_mac_base_ascii_read; + } +} +EXPORT_SYMBOL_GPL(nvmem_layout_parse_mac_base); + static int nvmem_layout_bus_match(struct device *dev, const struct device_driver *drv) { return of_driver_match_device(dev, drv); diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h index 3ebeaa0ded00..97698b898dcf 100644 --- a/include/linux/nvmem-provider.h +++ b/include/linux/nvmem-provider.h @@ -242,6 +242,8 @@ static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {} #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info); + /** * of_nvmem_layout_get_container() - Get OF node of layout container * @@ -254,6 +256,8 @@ struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem); #else /* CONFIG_NVMEM && CONFIG_OF */ +static inline void nvmem_layout_parse_mac_base(struct nvmem_cell_info *info) {} + static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) { return NULL; -- 2.51.0 From c7d5b37e95ce1865a1c04a2d863966379f13b7fb Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 3 Feb 2025 00:36:12 +0100 Subject: [PATCH 317/517] nvmem: layouts: add support for ascii-env driver Add support for simple ASCII envirorment driver for NVMEM layouts. It's very common for devices to store simple text file format in partition for environment varibles. The most common pattern is variable name, a delimiter and variable value all separated by a new line character (\n). This driver adds support for exporting such data and expose NVMEM cells so they can be referenced by other drivers. This driver also supports parsing mac-base NVMEM cells to parse ASCII or HEX mac address. Signed-off-by: Christian Marangi --- drivers/nvmem/layouts/Kconfig | 13 +++ drivers/nvmem/layouts/Makefile | 1 + drivers/nvmem/layouts/ascii-env.c | 148 ++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 drivers/nvmem/layouts/ascii-env.c diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig index 5e586dfebe47..58df4ad61e13 100644 --- a/drivers/nvmem/layouts/Kconfig +++ b/drivers/nvmem/layouts/Kconfig @@ -37,6 +37,19 @@ config NVMEM_LAYOUT_U_BOOT_ENV If unsure, say N. +config NVMEM_LAYOUT_ASCII_ENV + tristate "ASCII environment variables layout" + help + It's very common for devices to store simple text file format in + partition for environment varibles. The most common pattern is variable + name, a delimiter and variable value all separated by a new line + character (\n). + This driver adds support for exporting such data and expose NVMEM cells + so they can be referenced by other drivers. This driver also supports + parsing mac-base NVMEM cells to parse ASCII or HEX mac address. + + If unsure, say N. + endmenu endif diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile index 4940c9db0665..060ddf18d05a 100644 --- a/drivers/nvmem/layouts/Makefile +++ b/drivers/nvmem/layouts/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o +obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o diff --git a/drivers/nvmem/layouts/ascii-env.c b/drivers/nvmem/layouts/ascii-env.c new file mode 100644 index 000000000000..491fcfd3a501 --- /dev/null +++ b/drivers/nvmem/layouts/ascii-env.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Christian Marangi + * + * This borrow some parse logic from u-boot-env. + */ +#include +#include +#include +#include + +struct ascii_env_match_data { + const char delim; +}; + +/* + * Parse a buffer as an ASCII text with name delimiter value and each pattern separated + * with a new line char '\n' + * Example: (delimiter '=') + * name=value\nname2=value2\n + * 2 Cell: + * - name: value + * - name2: value2 + */ +static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf, + size_t data_len, const char delim) +{ + char *var, *value, *eq, *lf; + char *data = buf; + + /* + * Warning the inner loop take care of replacing '\n' + * with '\0', hence we can use strlen on value. + */ + for (var = data; var < data + data_len && *var; + var = value + strlen(value) + 1) { + struct nvmem_cell_info info = {}; + struct device_node *child; + const char *label; + + eq = strchr(var, delim); + if (!eq) + break; + *eq = '\0'; + value = eq + 1; + + /* Replace '\n' with '\0' to use strlen for value */ + lf = strchr(value, '\n'); + if (!lf) + break; + *lf = '\0'; + + info.name = devm_kstrdup(dev, var, GFP_KERNEL); + if (!info.name) + return -ENOMEM; + info.offset = value - data; + info.bytes = strlen(value); + info.np = of_get_child_by_name(dev->of_node, info.name); + for_each_child_of_node(dev->of_node, child) { + if (!of_property_read_string(child, "label", &label) && + !strncmp(info.name, label, info.bytes)) + info.np = child; + else if (of_node_name_eq(child, info.name)) + info.np = child; + } + + nvmem_layout_parse_mac_base(&info); + + nvmem_add_one_cell(nvmem, &info); + } + + return 0; +} + +static int ascii_env_add_cells(struct nvmem_layout *layout) +{ + struct nvmem_device *nvmem = layout->nvmem; + const struct ascii_env_match_data *data; + struct device *dev = &layout->dev; + size_t dev_size; + uint8_t *buf; + int bytes; + int ret; + + /* Get the delimiter for name value pattern */ + data = device_get_match_data(dev); + + dev_size = nvmem_dev_size(nvmem); + + buf = kzalloc(dev_size, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto err_out; + } + + bytes = nvmem_device_read(nvmem, 0, dev_size, buf); + if (bytes < 0) { + ret = bytes; + goto err_kfree; + } else if (bytes != dev_size) { + ret = -EIO; + goto err_kfree; + } + + buf[dev_size - 1] = '\0'; + ret = ascii_env_parse_cells(dev, nvmem, buf, dev_size, data->delim); + +err_kfree: + kfree(buf); +err_out: + return ret; +} + +static int ascii_env_probe(struct nvmem_layout *layout) +{ + layout->add_cells = ascii_env_add_cells; + + return nvmem_layout_register(layout); +} + +static void ascii_env_remove(struct nvmem_layout *layout) +{ + nvmem_layout_unregister(layout); +} + +static const struct ascii_env_match_data ascii_env_eq = { + .delim = '=', +}; + +static const struct of_device_id ascii_env_of_match_table[] = { + { .compatible = "ascii-eq-delim-env", .data = &ascii_env_eq, }, + {}, +}; + +static struct nvmem_layout_driver ascii_env_layout = { + .driver = { + .name = "ascii-env-layout", + .of_match_table = ascii_env_of_match_table, + }, + .probe = ascii_env_probe, + .remove = ascii_env_remove, +}; +module_nvmem_layout_driver(ascii_env_layout); + +MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, ascii_env_of_match_table); +MODULE_DESCRIPTION("NVMEM layout driver for ASCII environment variables"); -- 2.51.0 From 773d9fc4bc823e602c25cb93786fd38bc9bfd9ac Mon Sep 17 00:00:00 2001 From: George Moussalem Date: Thu, 6 Feb 2025 21:55:28 +0400 Subject: [PATCH 318/517] nvmem: layouts: ascii-env handle CRLF while parsing The current driver supports LF line endings only. For CRLF-based line endings in the ASCII env, the length of the value of the variable passed to nvmem_layout_parse_mac_base is 18 bytes instead of an expected length of 17 causing the parsing to fail. So, let's add the ability to handle CRLF line endings by adding a condition to check if the value ends with a '\r' character and replace it with '\0' to properly parse the mac address. Tested on Linksys MX2000, MX5500, and SPNMX56. Signed-off-by: George Moussalem --- drivers/nvmem/layouts/ascii-env.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/layouts/ascii-env.c b/drivers/nvmem/layouts/ascii-env.c index 491fcfd3a501..119bfc2b26f7 100644 --- a/drivers/nvmem/layouts/ascii-env.c +++ b/drivers/nvmem/layouts/ascii-env.c @@ -25,18 +25,20 @@ struct ascii_env_match_data { static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, uint8_t *buf, size_t data_len, const char delim) { - char *var, *value, *eq, *lf; + char *var, *value, *eq, *lf, *cr; char *data = buf; + uint incr = 0; /* * Warning the inner loop take care of replacing '\n' * with '\0', hence we can use strlen on value. */ for (var = data; var < data + data_len && *var; - var = value + strlen(value) + 1) { + var = value + strlen(value) + incr) { struct nvmem_cell_info info = {}; struct device_node *child; const char *label; + incr = 0; eq = strchr(var, delim); if (!eq) @@ -49,6 +51,15 @@ static int ascii_env_parse_cells(struct device *dev, struct nvmem_device *nvmem, if (!lf) break; *lf = '\0'; + incr++; + + /* For CRLF based env, replace '\r' with '\0' too to use strlen + * for value, and increment var by one in loop for next variable */ + cr = strchr(value, '\r'); + if (cr) { + *cr = '\0'; + incr++; + } info.name = devm_kstrdup(dev, var, GFP_KERNEL); if (!info.name) -- 2.51.0 From baede361c7b81acf63a533c25fe10c05b5116cf4 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Mon, 3 Nov 2025 15:50:11 +0100 Subject: [PATCH 319/517] debloat: add kernel config option to disabling common PCI quirks Signed-off-by: Gabor Juhos --- drivers/pci/Kconfig | 7 +++++++ drivers/pci/quirks.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 7cef00d9d7ab..6b458cba5c2f 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -118,6 +118,13 @@ config XEN_PCIDEV_FRONTEND The PCI device frontend driver allows the kernel to import arbitrary PCI devices from a PCI backend to support PCI driver domains. +config PCI_DISABLE_COMMON_QUIRKS + bool "PCI disable common quirks" + depends on PCI + help + If you don't know what to do here, say N. + + config PCI_ATS bool diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index db609d26811b..26e7a21a5ee7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -313,6 +313,7 @@ static void quirk_mmio_always_on(struct pci_dev *dev) DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); +#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS /* * The Mellanox Tavor device gives false positive parity errors. Disable * parity error reporting. @@ -3508,6 +3509,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f8, quirk_intel_mc_errata); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); +#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + /* * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. * To work around this, query the size it should be configured to by the @@ -3533,6 +3536,8 @@ static void quirk_intel_ntb(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); +#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* * Some BIOS implementations leave the Intel GPU interrupts enabled, even * though no one is handling them (e.g., if the i915 driver is never @@ -3571,6 +3576,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0106, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); +#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ + /* * PCI devices which are on Intel chips can skip the 10ms delay * before entering D3 mode. -- 2.51.0 From 5ba95a2dade8bae2429b2e6de0d7eed0e7819c7d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 26 Apr 2025 21:10:40 +0200 Subject: [PATCH 320/517] debloat: disable common USB quirks Signed-off-by: Felix Fietkau --- drivers/usb/host/pci-quirks.c | 7 +++++++ drivers/usb/host/pci-quirks.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 0404489c2f6a..362d347b5982 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -590,6 +590,7 @@ bool usb_amd_pt_check_port(struct device *device, int port) EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); #endif /* CONFIG_USB_PCI_AMD */ +#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS static int usb_asmedia_wait_write(struct pci_dev *pdev) { unsigned long retry_count; @@ -642,6 +643,7 @@ static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) } #define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) +#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ #if defined(CONFIG_HAS_IOPORT) && IS_ENABLED(CONFIG_USB_UHCI_HCD) /* @@ -724,6 +726,10 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) return 1; } EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); +#endif + +#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS +#if defined(CONFIG_HAS_IOPORT) && IS_ENABLED(CONFIG_USB_UHCI_HCD) #define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) @@ -1304,3 +1310,4 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); +#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index a5230b0b9e91..9cc969a3b352 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -38,12 +38,16 @@ static inline bool usb_amd_pt_check_port(struct device *device, int port) #ifdef CONFIG_USB_PCI void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); +#endif + +#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev); void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); #else struct pci_dev; static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} +static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {} #endif /* CONFIG_USB_PCI */ -- 2.51.0 From 922d037dad402d02ba7937afa88740db3487d89b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 13 Oct 2025 20:45:25 +0200 Subject: [PATCH 321/517] PCI/sysfs: enforce single creation of sysfs entry for pdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some specific scenario it's possible that the pci_create_resource_files() gets called multiple times and the created entry actually gets wrongly deleted with extreme case of having a NULL pointer dereference when the PCI is removed. This mainly happen due to bad timing where the PCI bus is adding PCI devices and at the same time the sysfs code is adding the entry causing double execution of the pci_create_resource_files function and kernel WARNING. To be more precise there is a race between the late_initcall of pci-sysfs with pci_sysfs_init and PCI bus.c pci_bus_add_device that also call pci_create_sysfs_dev_files. With correct amount of ""luck"" (or better say bad luck) pci_create_sysfs_dev_files in bus.c might be called with pci_sysfs_init is executing the loop. This has been reported multiple times and on multiple system, like imx6 system, ipq806x systems... To address this, imlement multiple improvement to the implementation: 1. Add a bool to pci_dev to flag when sysfs entry are created (sysfs_init) 2. Implement a simple completion to wait pci_sysfs_init execution. 3. Permit additional call of pci_create_sysfs_dev_files only after pci_sysfs_init has finished. With such logic in place, we address al kind of timing problem with minimal change to any driver. A notice worth to mention is that the remove function are not affected by this as the pci_remove_resource_files have enough check in place to always work and it's always called by pci_stop_dev. Cc: stable@vger.kernel.org Reported-by: Krzysztof Hałasa Closes: https://bugzilla.kernel.org/show_bug.cgi?id=215515 Signed-off-by: Christian Marangi --- drivers/pci/pci-sysfs.c | 34 +++++++++++++++++++++++++++++----- include/linux/pci.h | 1 + 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 96f9cf9f8d64..85440b4312e5 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -36,6 +37,7 @@ #endif static int sysfs_initialized; /* = 0 */ +static DECLARE_COMPLETION(sysfs_init_completion); /* show configuration fields */ #define pci_config_attr(field, format_string) \ @@ -1551,12 +1553,32 @@ static const struct attribute_group pci_dev_resource_resize_group = { .is_visible = resource_resize_is_visible, }; +static int __pci_create_sysfs_dev_files(struct pci_dev *pdev) +{ + int ret; + + ret = pci_create_resource_files(pdev); + if (ret) + return ret; + + /* on success set sysfs correctly created */ + pdev->sysfs_init = true; + return 0; +} + int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev) { if (!sysfs_initialized) return -EACCES; - return pci_create_resource_files(pdev); + /* sysfs entry already created */ + if (pdev->sysfs_init) + return 0; + + /* wait for pci_sysfs_init */ + wait_for_completion(&sysfs_init_completion); + + return __pci_create_sysfs_dev_files(pdev); } /** @@ -1577,21 +1599,23 @@ static int __init pci_sysfs_init(void) { struct pci_dev *pdev = NULL; struct pci_bus *pbus = NULL; - int retval; + int retval = 0; sysfs_initialized = 1; for_each_pci_dev(pdev) { - retval = pci_create_sysfs_dev_files(pdev); + retval = __pci_create_sysfs_dev_files(pdev); if (retval) { pci_dev_put(pdev); - return retval; + goto exit; } } while ((pbus = pci_find_next_bus(pbus))) pci_create_legacy_files(pbus); - return 0; +exit: + complete_all(&sysfs_init_completion); + return retval; } late_initcall(pci_sysfs_init); diff --git a/include/linux/pci.h b/include/linux/pci.h index 452a3dca28ea..2c3758975d35 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -484,6 +484,7 @@ struct pci_dev { unsigned int rom_attr_enabled:1; /* Display of ROM attribute enabled? */ pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ + bool sysfs_init; /* sysfs entry has been created */ spinlock_t pcie_cap_lock; /* Protects RMW ops in capability accessors */ u32 saved_config_space[16]; /* Config space saved at suspend time */ -- 2.51.0 From ddc0f7fa795c53ea0c7728a6fabf718eead7aedd Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:50:12 +0100 Subject: [PATCH 322/517] libata: add ledtrig support This adds a LED trigger for each ATA port indicating disk activity. As this is needed only on specific platforms (NAS SoCs and such), these platforms should define ARCH_WANTS_LIBATA_LEDS if there are boards with LED(s) intended to indicate ATA disk activity and need the OS to take care of that. In that way, if not selected, LED trigger support not will be included in libata-core and both, codepaths and structures remain untouched. Signed-off-by: Daniel Golle --- drivers/ata/Kconfig | 16 ++++++++++++++++ drivers/ata/libata-core.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/libata.h | 7 +++++++ 3 files changed, 62 insertions(+) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 120a2b7067fc..9f7d5609a577 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -67,6 +67,22 @@ config ATA_FORCE If unsure, say Y. +config ARCH_WANT_LIBATA_LEDS + bool + +config ATA_LEDS + bool "support ATA port LED triggers" + depends on ARCH_WANT_LIBATA_LEDS + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + default y + help + This option adds a LED trigger for each registered ATA port. + It is used to drive disk activity leds connected via GPIO. + + If unsure, say N. + config ATA_ACPI bool "ATA ACPI Support" depends on ACPI diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0cb97181d10a..faf86008348c 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -703,6 +703,17 @@ static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int cdl) qc->flags |= ATA_QCFLAG_HAS_CDL | ATA_QCFLAG_RESULT_TF; } +#ifdef CONFIG_ATA_LEDS +#define LIBATA_BLINK_DELAY 20 /* ms */ +static inline void ata_led_act(struct ata_port *ap) +{ + if (unlikely(!ap->ledtrig)) + return; + + led_trigger_blink_oneshot(ap->ledtrig, LIBATA_BLINK_DELAY, LIBATA_BLINK_DELAY, 0); +} +#endif + /** * ata_build_rw_tf - Build ATA taskfile for given read/write request * @qc: Metadata associated with the taskfile to build @@ -4767,6 +4778,9 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) link->active_tag = ATA_TAG_POISON; ap->nr_active_links--; } +#ifdef CONFIG_ATA_LEDS + ata_led_act(ap); +#endif /* clear exclusive status */ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && @@ -5488,6 +5502,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host) #ifdef ATA_IRQ_TRAP ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; +#endif +#ifdef CONFIG_ATA_LEDS + ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); #endif ata_sff_port_init(ap); @@ -5505,6 +5522,12 @@ void ata_port_free(struct ata_port *ap) kfree(ap->pmp_link); kfree(ap->slave_link); ida_free(&ata_ida, ap->print_id); +#ifdef CONFIG_ATA_LEDS + if (ap->ledtrig) { + led_trigger_unregister(ap->ledtrig); + kfree(ap->ledtrig); + }; +#endif kfree(ap); } EXPORT_SYMBOL_GPL(ata_port_free); @@ -5909,7 +5932,23 @@ int ata_host_register(struct ata_host *host, const struct scsi_host_template *sh WARN_ON(1); return -EINVAL; } +#ifdef CONFIG_ATA_LEDS + for (i = 0; i < host->n_ports; i++) { + if (unlikely(!host->ports[i]->ledtrig)) + continue; + + snprintf(host->ports[i]->ledtrig_name, + sizeof(host->ports[i]->ledtrig_name), "ata%u", + host->ports[i]->print_id); + host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; + + if (led_trigger_register(host->ports[i]->ledtrig)) { + kfree(host->ports[i]->ledtrig); + host->ports[i]->ledtrig = NULL; + } + } +#endif /* Create associated sysfs transport objects */ for (i = 0; i < host->n_ports; i++) { rc = ata_tport_add(host->dev,host->ports[i]); diff --git a/include/linux/libata.h b/include/linux/libata.h index 1983a98e3d67..4b9a57cfb801 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_ATA_LEDS +#include +#endif /* * Define if arch has non-standard setup. This is a _PCI_ standard @@ -935,6 +938,10 @@ struct ata_port { #ifdef CONFIG_ATA_ACPI struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ #endif +#ifdef CONFIG_ATA_LEDS + struct led_trigger *ledtrig; + char ledtrig_name[8]; +#endif }; /* The following initializer overrides a method to NULL whether one of -- 2.51.0 From e21a9da306cb81ea815c95e7222b4a5cf31c1f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Sat, 20 Feb 2021 18:36:38 +0100 Subject: [PATCH 323/517] hwrng: bcm2835: set quality to 1000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows devices without a high precission timer to reduce boot from >100s to <30s. Signed-off-by: Álvaro Fernández Rojas --- drivers/char/hw_random/bcm2835-rng.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c index aa2b135e3ee2..1a7b3fcd5eb8 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -169,6 +169,7 @@ static int bcm2835_rng_probe(struct platform_device *pdev) priv->rng.init = bcm2835_rng_init; priv->rng.read = bcm2835_rng_read; priv->rng.cleanup = bcm2835_rng_cleanup; + priv->rng.quality = 1000; if (dev_of_node(dev)) { rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node); -- 2.51.0 From f207db8602135a5efdbdb5d9be0464162dc43531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Mon, 10 Jan 2022 02:02:00 +0100 Subject: [PATCH 324/517] PCI: aardvark: Make main irq_chip structure a static driver structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marc Zyngier says [1] that we should use struct irq_chip as a global static struct in the driver. Even though the structure currently contains a dynamic member (parent_device), Marc says [2] that he plans to kill it and make the structure completely static. We have already converted others irq_chip structures in this driver in this way, but we omitted this one because the .name member is dynamically created from device's name, and the name is displayed in sysfs, so changing it would break sysfs ABI. The rationale for changing the name (to "advk-INT") in spite of sysfs ABI, and thus allowing to convert to a static structure, is that after the other changes we made in this series, the IRQ chip is basically something different: it no logner generates ERR and PME interrupts (they are generated by emulated bridge's rp_irq_chip). [1] https://lore.kernel.org/linux-pci/877dbcvngf.wl-maz@kernel.org/ [2] https://lore.kernel.org/linux-pci/874k6gvkhz.wl-maz@kernel.org/ Signed-off-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index a598a98247ce..b2acf14fe414 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -276,7 +276,6 @@ struct advk_pcie { u8 wins_count; struct irq_domain *rp_irq_domain; struct irq_domain *irq_domain; - struct irq_chip irq_chip; raw_spinlock_t irq_lock; struct irq_domain *msi_domain; struct irq_domain *msi_inner_domain; @@ -1418,14 +1417,19 @@ static void advk_pcie_irq_unmask(struct irq_data *d) raw_spin_unlock_irqrestore(&pcie->irq_lock, flags); } +static struct irq_chip advk_irq_chip = { + .name = "advk-INT", + .irq_mask = advk_pcie_irq_mask, + .irq_unmask = advk_pcie_irq_unmask, +}; + static int advk_pcie_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { struct advk_pcie *pcie = h->host_data; irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, &pcie->irq_chip, - handle_level_irq); + irq_set_chip_and_handler(virq, &advk_irq_chip, handle_level_irq); irq_set_chip_data(virq, pcie); return 0; @@ -1485,7 +1489,6 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) struct device *dev = &pcie->pdev->dev; struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; - struct irq_chip *irq_chip; int ret = 0; raw_spin_lock_init(&pcie->irq_lock); @@ -1496,28 +1499,14 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) return -ENODEV; } - irq_chip = &pcie->irq_chip; - - irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq", - dev_name(dev)); - if (!irq_chip->name) { - ret = -ENOMEM; - goto out_put_node; - } - - irq_chip->irq_mask = advk_pcie_irq_mask; - irq_chip->irq_unmask = advk_pcie_irq_unmask; - pcie->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &advk_pcie_irq_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); ret = -ENOMEM; - goto out_put_node; } -out_put_node: of_node_put(pcie_intc_node); return ret; } -- 2.51.0 From 772fcedd8d860ca53e1f543962c11f4dcad5c3ba Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 7 May 2024 13:15:22 +0000 Subject: [PATCH 325/517] usb: serial: add support for CH348 The CH348 is an USB octo port serial adapter. The device multiplexes all 8 ports in the same pair of Bulk endpoints. Since there is no public datasheet, unfortunately it remains some magic values Signed-off-by: Corentin Labbe Tested-by: Martin Blumenstingl --- drivers/usb/serial/Kconfig | 9 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/ch348.c | 725 ++++++++++++++++++++++++++++++++++++ 3 files changed, 735 insertions(+) create mode 100644 drivers/usb/serial/ch348.c diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index ef8d1c73c754..1e1842656b54 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -112,6 +112,15 @@ config USB_SERIAL_CH341 To compile this driver as a module, choose M here: the module will be called ch341. +config USB_SERIAL_CH348 + tristate "USB Winchiphead CH348 Octo Port Serial Driver" + help + Say Y here if you want to use a Winchiphead CH348 octo port + USB to serial adapter. + + To compile this driver as a module, choose M here: the + module will be called ch348. + config USB_SERIAL_WHITEHEAT tristate "USB ConnectTech WhiteHEAT Serial Driver" select USB_EZUSB_FX2 diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index c7bb1a88173e..d16ff59fde68 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o +obj-$(CONFIG_USB_SERIAL_CH348) += ch348.o obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o diff --git a/drivers/usb/serial/ch348.c b/drivers/usb/serial/ch348.c new file mode 100644 index 000000000000..e437ba36bb5e --- /dev/null +++ b/drivers/usb/serial/ch348.c @@ -0,0 +1,725 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB serial driver for USB to Octal UARTs chip ch348. + * + * Copyright (C) 2022 Corentin Labbe + * With the help of Neil Armstrong + * and the help of Martin Blumenstingl + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CH348_CMD_TIMEOUT 2000 + +#define CH348_CTO_D 0x01 +#define CH348_CTO_R 0x02 + +#define CH348_CTI_C 0x10 +#define CH348_CTI_DSR 0x20 +#define CH348_CTI_R 0x40 +#define CH348_CTI_DCD 0x80 + +#define CH348_LO 0x02 +#define CH348_LP 0x04 +#define CH348_LF 0x08 +#define CH348_LB 0x10 + +#define CMD_W_R 0xC0 +#define CMD_W_BR 0x80 + +#define CMD_WB_E 0x90 +#define CMD_RB_E 0xC0 + +#define M_NOR 0x00 +#define M_HF 0x03 + +#define R_MOD 0x97 +#define R_IO_D 0x98 +#define R_IO_O 0x99 +#define R_IO_I 0x9b +#define R_TM_O 0x9c +#define R_INIT 0xa1 + +#define R_C1 0x01 +#define R_C2 0x02 +#define R_C4 0x04 +#define R_C5 0x06 + +#define R_II_B1 0x06 +#define R_II_B2 0x02 +#define R_II_B3 0x00 + +#define CMD_VER 0x96 + +#define CH348_RX_PORT_CHUNK_LENGTH 32 +#define CH348_RX_PORT_MAX_LENGTH 30 + +struct ch348_rxbuf { + u8 port; + u8 length; + u8 data[CH348_RX_PORT_MAX_LENGTH]; +} __packed; + +struct ch348_txbuf { + u8 port; + __le16 length; + u8 data[]; +} __packed; + +#define CH348_TX_HDRSIZE offsetof(struct ch348_txbuf, data) + +struct ch348_initbuf { + u8 cmd; + u8 reg; + u8 port; + __be32 baudrate; + u8 format; + u8 paritytype; + u8 databits; + u8 rate; + u8 unknown; +} __packed; + +#define CH348_MAXPORT 8 + +/* + * The CH348 multiplexes rx & tx into a pair of Bulk USB endpoints for + * the 8 serial ports, and another pair of Bulk USB endpoints to + * set port settings and receive port status events. + * + * The USB serial cores ties every Bulk endpoints pairs to each ports, + * but in our case it will set port 0 with the rx/tx endpoints + * and port 1 with the setup/status endpoints. + * + * To still take advantage of the generic code, we (re-)initialize + * the USB serial port structure with the correct USB endpoint + * for read and write, and write proper process_read_urb() + * and prepare_write_buffer() to correctly (de-)multiplex data. + * Also we use a custom write() implementation to wait until the buffer + * has been fully transmitted to prevent TX buffer overruns. + */ + +/* + * struct ch348_port - per-port information + * @uartmode: UART port current mode + * @write_completion: completion event when the TX buffer has been written out + */ +struct ch348_port { + u8 uartmode; + struct completion write_completion; +}; + +/* + * struct ch348 - main container for all this driver information + * @udev: pointer to the CH348 USB device + * @ports: List of per-port information + * @serial: pointer to the serial structure + * @write_lock: protect against concurrent writes so we don't lose data + * @cmd_ep: endpoint number for configure operations + * @status_urb: URB for status + * @status_buffer: buffer used by status_urb + */ +struct ch348 { + struct usb_device *udev; + struct ch348_port ports[CH348_MAXPORT]; + struct usb_serial *serial; + + struct mutex write_lock; + + int cmd_ep; + + struct urb *status_urb; + u8 status_buffer[]; +}; + +struct ch348_magic { + u8 action; + u8 reg; + u8 control; +} __packed; + +struct ch348_status_entry { + u8 portnum:4; + u8 unused:4; + u8 reg_iir; + union { + u8 lsr_signal; + u8 modem_signal; + u8 init_data[10]; + }; +} __packed; + +static void ch348_process_status_urb(struct urb *urb) +{ + struct ch348_status_entry *status_entry; + struct ch348 *ch348 = urb->context; + int ret, status = urb->status; + struct usb_serial_port *port; + unsigned int i, status_len; + + switch (status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", + __func__, status); + return; + default: + dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", + __func__, status); + goto exit; + } + + if (urb->actual_length < 3) { + dev_warn(&ch348->udev->dev, + "Received too short status buffer with %u bytes\n", + urb->actual_length); + goto exit; + } + + for (i = 0; i < urb->actual_length;) { + status_entry = urb->transfer_buffer + i; + + if (status_entry->portnum >= CH348_MAXPORT) { + dev_warn(&ch348->udev->dev, + "Invalid port %d in status entry\n", + status_entry->portnum); + break; + } + + port = ch348->serial->port[status_entry->portnum]; + status_len = 3; + + if (!status_entry->reg_iir) { + dev_dbg(&port->dev, "Ignoring status with zero reg_iir\n"); + } else if (status_entry->reg_iir == R_INIT) { + status_len = 12; + } else if ((status_entry->reg_iir & 0x0f) == R_II_B1) { + if (status_entry->lsr_signal & CH348_LO) + port->icount.overrun++; + if (status_entry->lsr_signal & CH348_LP) + port->icount.parity++; + if (status_entry->lsr_signal & CH348_LF) + port->icount.frame++; + if (status_entry->lsr_signal & CH348_LF) + port->icount.brk++; + } else if ((status_entry->reg_iir & 0x0f) == R_II_B2) { + complete_all(&ch348->ports[status_entry->portnum].write_completion); + } else { + dev_warn(&port->dev, + "Unsupported status with reg_iir 0x%02x\n", + status_entry->reg_iir); + } + + usb_serial_debug_data(&port->dev, __func__, status_len, + urb->transfer_buffer + i); + + i += status_len; + } + +exit: + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + dev_err(&urb->dev->dev, "%s - usb_submit_urb failed; %d\n", + __func__, ret); +} + +/* + * Some values came from vendor tree, and we have no meaning for them, this + * function simply use them. + */ +static int ch348_do_magic(struct ch348 *ch348, int portnum, u8 action, u8 reg, u8 control) +{ + struct ch348_magic *buffer; + int ret, len; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + if (portnum < 4) + reg += 0x10 * portnum; + else + reg += 0x10 * (portnum - 4) + 0x08; + + buffer->action = action; + buffer->reg = reg; + buffer->control = control; + + ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, 3, &len, + CH348_CMD_TIMEOUT); + if (ret) + dev_err(&ch348->udev->dev, "Failed to write magic err=%d\n", ret); + + kfree(buffer); + + return ret; +} + +static int ch348_configure(struct ch348 *ch348, int portnum) +{ + int ret; + + ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C2, 0x87); + if (ret) + return ret; + + return ch348_do_magic(ch348, portnum, CMD_W_R, R_C4, 0x08); +} + +static void ch348_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct ch348 *ch348 = usb_get_serial_data(port->serial); + unsigned int portnum, usblen, i; + struct ch348_rxbuf *rxb; + + if (urb->actual_length < 2) { + dev_dbg(&ch348->udev->dev, "Empty rx buffer\n"); + return; + } + + for (i = 0; i < urb->actual_length; i += CH348_RX_PORT_CHUNK_LENGTH) { + rxb = urb->transfer_buffer + i; + portnum = rxb->port; + if (portnum >= CH348_MAXPORT) { + dev_dbg(&ch348->udev->dev, "Invalid port %d\n", portnum); + break; + } + + port = ch348->serial->port[portnum]; + + usblen = rxb->length; + if (usblen > CH348_RX_PORT_MAX_LENGTH) { + dev_dbg(&port->dev, "Invalid length %d for port %d\n", + usblen, portnum); + break; + } + + tty_insert_flip_string(&port->port, rxb->data, usblen); + tty_flip_buffer_push(&port->port); + port->icount.rx += usblen; + usb_serial_debug_data(&port->dev, __func__, usblen, rxb->data); + } +} + +static int ch348_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size) +{ + struct ch348_txbuf *rxt = dest; + int count; + + count = kfifo_out_locked(&port->write_fifo, rxt->data, + size - CH348_TX_HDRSIZE, &port->lock); + + rxt->port = port->port_number; + rxt->length = cpu_to_le16(count); + + return count + CH348_TX_HDRSIZE; +} + +static int ch348_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct ch348 *ch348 = usb_get_serial_data(port->serial); + struct ch348_port *ch348_port = &ch348->ports[port->port_number]; + int ret, max_tx_size; + + if (tty_get_baud_rate(tty) < 9600 && count >= 128) + /* + * Writing larger buffers can take longer than the hardware + * allows before discarding the write buffer. Limit the + * transfer size in such cases. + * These values have been found by empirical testing. + */ + max_tx_size = 128; + else + /* + * Only ingest as many bytes as we can transfer with one URB at + * a time. Once an URB has been written we need to wait for the + * R_II_B2 status event before we are allowed to send more data. + * If we ingest more data then usb_serial_generic_write() will + * internally try to process as much data as possible with any + * number of URBs without giving us the chance to wait in + * between transfers. + */ + max_tx_size = port->bulk_out_size - CH348_TX_HDRSIZE; + + reinit_completion(&ch348_port->write_completion); + + mutex_lock(&ch348->write_lock); + + /* + * For any (remaining) bytes that we did not transfer TTY core will + * call us again, with the buffer and count adjusted to the remaining + * data. + */ + ret = usb_serial_generic_write(tty, port, buf, min(count, max_tx_size)); + + mutex_unlock(&ch348->write_lock); + + if (ret <= 0) + return ret; + + if (!wait_for_completion_interruptible_timeout(&ch348_port->write_completion, + msecs_to_jiffies(CH348_CMD_TIMEOUT))) { + dev_err_console(port, "Failed to wait for TX buffer flush\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static int ch348_set_uartmode(struct ch348 *ch348, int portnum, u8 mode) +{ + int ret; + + if (ch348->ports[portnum].uartmode == M_NOR && mode == M_HF) { + ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x51); + if (ret) + return ret; + ch348->ports[portnum].uartmode = M_HF; + } + + if (ch348->ports[portnum].uartmode == M_HF && mode == M_NOR) { + ret = ch348_do_magic(ch348, portnum, CMD_W_BR, R_C4, 0x50); + if (ret) + return ret; + ch348->ports[portnum].uartmode = M_NOR; + } + return 0; +} + +static void ch348_set_termios(struct tty_struct *tty, struct usb_serial_port *port, + const struct ktermios *termios_old) +{ + struct ch348 *ch348 = usb_get_serial_data(port->serial); + struct ktermios *termios = &tty->termios; + int ret, portnum = port->port_number; + struct ch348_initbuf *buffer; + speed_t baudrate; + u8 format; + + if (termios_old && !tty_termios_hw_change(&tty->termios, termios_old)) + return; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + if (termios_old) + tty->termios = *termios_old; + return; + } + + /* + * The datasheet states that only baud rates in range of 1200..6000000 + * are supported. Tests however show that even baud rates as low as 50 + * and as high as 12000000 are working in practice. + */ + baudrate = clamp(tty_get_baud_rate(tty), 50, 12000000); + + format = termios->c_cflag & CSTOPB ? 2 : 1; + + buffer->paritytype = 0; + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + buffer->paritytype += 1; + else + buffer->paritytype += 2; + if (termios->c_cflag & CMSPAR) + buffer->paritytype += 2; + } + + switch (C_CSIZE(tty)) { + case CS5: + buffer->databits = 5; + break; + case CS6: + buffer->databits = 6; + break; + case CS7: + buffer->databits = 7; + break; + case CS8: + default: + buffer->databits = 8; + break; + } + buffer->cmd = CMD_WB_E | (portnum & 0x0F); + buffer->reg = R_INIT; + buffer->port = portnum; + buffer->baudrate = cpu_to_be32(baudrate); + + if (format == 2) + buffer->format = 0x02; + else if (format == 1) + buffer->format = 0x00; + + buffer->rate = max_t(speed_t, 5, (10000 * 15 / baudrate) + 1); + + ret = usb_bulk_msg(ch348->udev, ch348->cmd_ep, buffer, + sizeof(*buffer), NULL, CH348_CMD_TIMEOUT); + if (ret < 0) { + dev_err(&ch348->udev->dev, "Failed to change line settings: err=%d\n", + ret); + goto out; + } + + ret = ch348_do_magic(ch348, portnum, CMD_W_R, R_C1, 0x0F); + if (ret < 0) + goto out; + + if (C_CRTSCTS(tty)) + ret = ch348_set_uartmode(ch348, portnum, M_HF); + else + ret = ch348_set_uartmode(ch348, portnum, M_NOR); + +out: + kfree(buffer); +} + +static int ch348_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct ch348 *ch348 = usb_get_serial_data(port->serial); + int ret; + + if (tty) + ch348_set_termios(tty, port, NULL); + + ret = ch348_configure(ch348, port->port_number); + if (ret) { + dev_err(&ch348->udev->dev, "Fail to configure err=%d\n", ret); + return ret; + } + + return usb_serial_generic_open(tty, port); +} + +static int ch348_attach(struct usb_serial *serial) +{ + struct usb_endpoint_descriptor *epcmd, *epstatus; + struct usb_serial_port *port0 = serial->port[1]; + struct usb_device *usb_dev = serial->dev; + int status_buffer_size, i, ret; + struct usb_interface *intf; + struct ch348 *ch348; + + intf = usb_ifnum_to_if(usb_dev, 0); + epstatus = &intf->cur_altsetting->endpoint[2].desc; + epcmd = &intf->cur_altsetting->endpoint[3].desc; + + status_buffer_size = usb_endpoint_maxp(epstatus); + + ch348 = kzalloc(struct_size(ch348, status_buffer, status_buffer_size), + GFP_KERNEL); + if (!ch348) + return -ENOMEM; + + usb_set_serial_data(serial, ch348); + + ch348->udev = serial->dev; + ch348->serial = serial; + mutex_init(&ch348->write_lock); + + for (i = 0; i < CH348_MAXPORT; i++) + init_completion(&ch348->ports[i].write_completion); + + ch348->status_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ch348->status_urb) { + ret = -ENOMEM; + goto err_free_ch348; + } + + usb_fill_bulk_urb(ch348->status_urb, ch348->udev, + usb_rcvbulkpipe(ch348->udev, epstatus->bEndpointAddress), + ch348->status_buffer, status_buffer_size, + ch348_process_status_urb, ch348); + + ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL); + if (ret) { + dev_err(&ch348->udev->dev, + "%s - failed to submit status/interrupt urb %i\n", + __func__, ret); + goto err_free_status_urb; + } + + ret = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL); + if (ret) + goto err_kill_status_urb; + + ch348->cmd_ep = usb_sndbulkpipe(usb_dev, epcmd->bEndpointAddress); + + return 0; + +err_kill_status_urb: + usb_kill_urb(ch348->status_urb); +err_free_status_urb: + usb_free_urb(ch348->status_urb); +err_free_ch348: + kfree(ch348); + return ret; +} + +static void ch348_release(struct usb_serial *serial) +{ + struct ch348 *ch348 = usb_get_serial_data(serial); + + usb_kill_urb(ch348->status_urb); + usb_free_urb(ch348->status_urb); + + kfree(ch348); +} + +static void ch348_print_version(struct usb_serial *serial) +{ + u8 *version_buf; + int ret; + + version_buf = kzalloc(4, GFP_KERNEL); + if (!version_buf) + return; + + ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + CMD_VER, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0, 0, version_buf, 4, CH348_CMD_TIMEOUT); + if (ret < 0) + dev_dbg(&serial->dev->dev, "Failed to read CMD_VER: %d\n", ret); + else + dev_info(&serial->dev->dev, "Found WCH CH348%s\n", + (version_buf[1] & 0x80) ? "Q" : "L"); + + kfree(version_buf); +} + +static int ch348_probe(struct usb_serial *serial, const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *epread, *epwrite, *epstatus, *epcmd; + struct usb_device *usb_dev = serial->dev; + struct usb_interface *intf; + int ret; + + intf = usb_ifnum_to_if(usb_dev, 0); + + ret = usb_find_common_endpoints(intf->cur_altsetting, &epread, &epwrite, + NULL, NULL); + if (ret) { + dev_err(&serial->dev->dev, "Failed to find basic endpoints ret=%d\n", ret); + return ret; + } + + epstatus = &intf->cur_altsetting->endpoint[2].desc; + if (!usb_endpoint_is_bulk_in(epstatus)) { + dev_err(&serial->dev->dev, "Missing second bulk in (STATUS/INT)\n"); + return -ENODEV; + } + + epcmd = &intf->cur_altsetting->endpoint[3].desc; + if (!usb_endpoint_is_bulk_out(epcmd)) { + dev_err(&serial->dev->dev, "Missing second bulk out (CMD)\n"); + return -ENODEV; + } + + ch348_print_version(serial); + + return 0; +} + +static int ch348_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + int i; + + for (i = 1; i < CH348_MAXPORT; ++i) { + epds->bulk_out[i] = epds->bulk_out[0]; + epds->bulk_in[i] = epds->bulk_in[0]; + } + + epds->num_bulk_out = CH348_MAXPORT; + epds->num_bulk_in = CH348_MAXPORT; + + return CH348_MAXPORT; +} + +static int ch348_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct ch348 *ch348 = usb_get_serial_data(serial); + + usb_kill_urb(ch348->status_urb); + + return 0; +} + +static int ch348_resume(struct usb_serial *serial) +{ + struct ch348 *ch348 = usb_get_serial_data(serial); + int ret; + + ret = usb_submit_urb(ch348->status_urb, GFP_KERNEL); + if (ret) { + dev_err(&ch348->udev->dev, + "%s - failed to submit status/interrupt urb %i\n", + __func__, ret); + return ret; + } + + ret = usb_serial_generic_resume(serial); + if (ret) + usb_kill_urb(ch348->status_urb); + + return ret; +} + +static const struct usb_device_id ch348_ids[] = { + { USB_DEVICE(0x1a86, 0x55d9), }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(usb, ch348_ids); + +static struct usb_serial_driver ch348_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ch348", + }, + .id_table = ch348_ids, + .num_ports = CH348_MAXPORT, + .num_bulk_in = 1, + .num_bulk_out = 1, + .open = ch348_open, + .set_termios = ch348_set_termios, + .process_read_urb = ch348_process_read_urb, + .prepare_write_buffer = ch348_prepare_write_buffer, + .write = ch348_write, + .probe = ch348_probe, + .calc_num_ports = ch348_calc_num_ports, + .attach = ch348_attach, + .release = ch348_release, + .suspend = ch348_suspend, + .resume = ch348_resume, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &ch348_device, NULL +}; + +module_usb_serial_driver(serial_drivers, ch348_ids); + +MODULE_AUTHOR("Corentin Labbe "); +MODULE_DESCRIPTION("USB CH348 Octo port serial converter driver"); +MODULE_LICENSE("GPL"); -- 2.51.0 From 7425a0d41434f00f9190aeee0fbbe6c94315589b Mon Sep 17 00:00:00 2001 From: Vicentiu Galanopulo Date: Wed, 18 Dec 2024 18:33:58 +0000 Subject: [PATCH 326/517] dt-bindings: leds: Add LED1202 LED Controller The LED1202 is a 12-channel low quiescent current LED driver with: * Supply range from 2.6 V to 5 V * 20 mA current capability per channel * 1.8 V compatible I2C control interface * 8-bit analog dimming individual control * 12-bit local PWM resolution * 8 programmable patterns If the led node is present in the controller then the channel is set to active. Signed-off-by: Vicentiu Galanopulo Reviewed-by: Krzysztof Kozlowski --- .../devicetree/bindings/leds/st,led1202.yaml | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/st,led1202.yaml diff --git a/Documentation/devicetree/bindings/leds/st,led1202.yaml b/Documentation/devicetree/bindings/leds/st,led1202.yaml new file mode 100644 index 000000000000..f1e5e4efaa3a --- /dev/null +++ b/Documentation/devicetree/bindings/leds/st,led1202.yaml @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/st,led1202.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ST LED1202 LED controllers + +maintainers: + - Vicentiu Galanopulo + +description: | + The LED1202 is a 12-channel low quiescent current LED controller + programmable via I2C; The output current can be adjusted separately + for each channel by 8-bit analog and 12-bit digital dimming control. + Datasheet available at + https://www.st.com/en/power-management/led1202.html + +properties: + compatible: + const: st,led1202 + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-9a-f]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 11 + + required: + - reg + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@58 { + compatible = "st,led1202"; + reg = <0x58>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0x0>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <1>; + }; + + led@1 { + reg = <0x1>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <2>; + }; + + led@2 { + reg = <0x2>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <3>; + }; + + led@3 { + reg = <0x3>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <4>; + }; + + led@4 { + reg = <0x4>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <5>; + }; + + led@5 { + reg = <0x5>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <6>; + }; + + led@6 { + reg = <0x6>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <7>; + }; + + led@7 { + reg = <0x7>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <8>; + }; + + led@8 { + reg = <0x8>; + function = LED_FUNCTION_STATUS; + color = ; + function-enumerator = <9>; + }; + }; + }; +... -- 2.51.0 From 266622ae5a057e31d2539cf532af4287df3aa656 Mon Sep 17 00:00:00 2001 From: Vicentiu Galanopulo Date: Wed, 18 Dec 2024 18:33:59 +0000 Subject: [PATCH 327/517] leds: Add LED1202 I2C driver The output current can be adjusted separately for each channel by 8-bit analog (current sink input) and 12-bit digital (PWM) dimming control. The LED1202 implements 12 low-side current generators with independent dimming control. Internal volatile memory allows the user to store up to 8 different patterns, each pattern is a particular output configuration in terms of PWM duty-cycle (on 4096 steps). Analog dimming (on 256 steps) is per channel but common to all patterns. Each device tree LED node will have a corresponding entry in /sys/class/leds with the label name. The brightness property corresponds to the per channel analog dimming, while the patterns[1-8] to the PWM dimming control. Signed-off-by: Vicentiu Galanopulo --- drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-st1202.c | 416 +++++++++++++++++++++++++++++++++++++ 3 files changed, 427 insertions(+) create mode 100644 drivers/leds/leds-st1202.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index b784bb74a837..c275963c498c 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -931,6 +931,16 @@ config LEDS_LM36274 Say Y to enable the LM36274 LED driver for TI LMU devices. This supports the LED device LM36274. +config LEDS_ST1202 + tristate "LED Support for STMicroelectronics LED1202 I2C chips" + depends on LEDS_CLASS + depends on I2C + depends on OF + select LEDS_TRIGGERS + help + Say Y to enable support for LEDs connected to LED1202 + LED driver chips accessed via the I2C bus. + config LEDS_TPS6105X tristate "LED support for TI TPS6105X" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 18afbb5a23ee..32241451b805 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o +obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c new file mode 100644 index 000000000000..b691c4886993 --- /dev/null +++ b/drivers/leds/leds-st1202.c @@ -0,0 +1,416 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LED driver for STMicroelectronics LED1202 chip + * + * Copyright (C) 2024 Remote-Tech Ltd. UK + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ST1202_CHAN_DISABLE_ALL 0x00 +#define ST1202_CHAN_ENABLE_HIGH 0x03 +#define ST1202_CHAN_ENABLE_LOW 0x02 +#define ST1202_CONFIG_REG 0x04 +/* PATS: Pattern sequence feature enable */ +#define ST1202_CONFIG_REG_PATS BIT(7) +/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */ +#define ST1202_CONFIG_REG_PATSR BIT(6) +#define ST1202_CONFIG_REG_SHFT BIT(3) +#define ST1202_DEV_ENABLE 0x01 +#define ST1202_DEV_ENABLE_ON BIT(0) +#define ST1202_DEV_ENABLE_RESET BIT(7) +#define ST1202_DEVICE_ID 0x00 +#define ST1202_ILED_REG0 0x09 +#define ST1202_MAX_LEDS 12 +#define ST1202_MAX_PATTERNS 8 +#define ST1202_MILLIS_PATTERN_DUR_MAX 5660 +#define ST1202_MILLIS_PATTERN_DUR_MIN 22 +#define ST1202_PATTERN_DUR 0x16 +#define ST1202_PATTERN_PWM 0x1E +#define ST1202_PATTERN_REP 0x15 + +struct st1202_led { + struct fwnode_handle *fwnode; + struct led_classdev led_cdev; + struct st1202_chip *chip; + bool is_active; + int led_num; +}; + +struct st1202_chip { + struct i2c_client *client; + struct mutex lock; + struct st1202_led leds[ST1202_MAX_LEDS]; +}; + +static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev) +{ + return container_of(cdev, struct st1202_led, led_cdev); +} + +static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val) +{ + struct device *dev = &chip->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(chip->client, reg); + if (ret < 0) { + dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret); + return ret; + } + + *val = (uint8_t)ret; + return 0; +} + +static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val) +{ + struct device *dev = &chip->client->dev; + int ret; + + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + if (ret != 0) + dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret); + + return ret; +} + +static uint8_t st1202_prescalar_to_miliseconds(unsigned int value) +{ + return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1; +} + +static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num, + int pattern, unsigned int value) +{ + u8 value_l, value_h; + int ret; + + value_l = (u8)value; + value_h = (u8)(value >> 8); + + /* + * Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh), + * where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh) + * and y is the pattern number in hexadecimal (y = 00h .. 07h) + */ + ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern), + value_l); + if (ret != 0) + return ret; + + /* + * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh), + * where x is the channel number in hexadecimal (x = 00h .. 0Bh) + * and y is the pattern number in hexadecimal (y = 00h .. 07h) + */ + ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern), + value_h); + if (ret != 0) + return ret; + + return 0; +} + +static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern, + unsigned int value) +{ + return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern), + st1202_prescalar_to_miliseconds(value)); +} + +static void st1202_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct st1202_led *led = cdev_to_st1202_led(led_cdev); + struct st1202_chip *chip = led->chip; + + guard(mutex)(&chip->lock); + + st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value); +} + +static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev) +{ + struct st1202_led *led = cdev_to_st1202_led(led_cdev); + struct st1202_chip *chip = led->chip; + u8 value = 0; + + guard(mutex)(&chip->lock); + + st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value); + + return value; +} + +static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active) +{ + u8 chan_low, chan_high; + int ret; + + guard(mutex)(&chip->lock); + + if (led_num <= 7) { + ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low); + if (ret < 0) + return ret; + + chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num); + + ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low); + if (ret < 0) + return ret; + + } else { + ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high); + if (ret < 0) + return ret; + + chan_high = active ? chan_high | (BIT(led_num) >> 8) : + chan_high & ~(BIT(led_num) >> 8); + + ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high); + if (ret < 0) + return ret; + } + + return 0; +} + +static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value) +{ + struct st1202_led *led = cdev_to_st1202_led(ldev); + struct st1202_chip *chip = led->chip; + + return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true); +} + +static int st1202_led_pattern_clear(struct led_classdev *ldev) +{ + struct st1202_led *led = cdev_to_st1202_led(ldev); + struct st1202_chip *chip = led->chip; + int ret; + + guard(mutex)(&chip->lock); + + for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) { + ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF); + if (ret != 0) + return ret; + + ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN); + if (ret != 0) + return ret; + } + + return 0; +} + +static int st1202_led_pattern_set(struct led_classdev *ldev, + struct led_pattern *pattern, + u32 len, int repeat) +{ + struct st1202_led *led = cdev_to_st1202_led(ldev); + struct st1202_chip *chip = led->chip; + int ret; + + if (len > ST1202_MAX_PATTERNS) + return -EINVAL; + + guard(mutex)(&chip->lock); + + for (int patt = 0; patt < len; patt++) { + if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN || + pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX) + return -EINVAL; + + ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness); + if (ret != 0) + return ret; + + ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t); + if (ret != 0) + return ret; + } + + ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat); + if (ret != 0) + return ret; + + ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR | + ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT)); + if (ret != 0) + return ret; + + return 0; +} + +static int st1202_dt_init(struct st1202_chip *chip) +{ + struct device *dev = &chip->client->dev; + struct st1202_led *led; + int err, reg; + + for_each_available_child_of_node_scoped(dev_of_node(dev), child) { + struct led_init_data init_data = {}; + + err = of_property_read_u32(child, "reg", ®); + if (err) + return dev_err_probe(dev, err, "Invalid register\n"); + + led = &chip->leds[reg]; + led->is_active = true; + led->fwnode = of_fwnode_handle(child); + + led->led_cdev.max_brightness = U8_MAX; + led->led_cdev.brightness_set_blocking = st1202_led_set; + led->led_cdev.pattern_set = st1202_led_pattern_set; + led->led_cdev.pattern_clear = st1202_led_pattern_clear; + led->led_cdev.default_trigger = "pattern"; + + init_data.fwnode = led->fwnode; + init_data.devicename = "st1202"; + init_data.default_label = ":"; + + err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); + if (err < 0) + return dev_err_probe(dev, err, "Failed to register LED class device\n"); + + led->led_cdev.brightness_set = st1202_brightness_set; + led->led_cdev.brightness_get = st1202_brightness_get; + } + + return 0; +} + +static int st1202_setup(struct st1202_chip *chip) +{ + int ret; + + guard(mutex)(&chip->lock); + + /* + * Once the supply voltage is applied, the LED1202 executes some internal checks, + * afterwords it stops the oscillator and puts the internal LDO in quiescent mode. + * To start the device, EN bit must be set inside the “Device Enable” register at + * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters + * from the internal non-volatile memory and performs an auto-calibration procedure + * in order to increase the output current precision. + * Such initialization lasts about 6.5 ms. + */ + + /* Reset the chip during setup */ + ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET); + if (ret < 0) + return ret; + + /* Enable phase-shift delay feature */ + ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT); + if (ret < 0) + return ret; + + /* Enable the device */ + ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON); + if (ret < 0) + return ret; + + /* Duration of initialization */ + usleep_range(6500, 10000); + + /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */ + ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL); + if (ret < 0) + return ret; + + ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL); + if (ret < 0) + return ret; + + ret = st1202_write_reg(chip, ST1202_CONFIG_REG, + ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR); + if (ret < 0) + return ret; + + return 0; +} + +static int st1202_probe(struct i2c_client *client) +{ + struct st1202_chip *chip; + struct st1202_led *led; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n"); + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + devm_mutex_init(&client->dev, &chip->lock); + chip->client = client; + + ret = st1202_dt_init(chip); + if (ret < 0) + return ret; + + ret = st1202_setup(chip); + if (ret < 0) + return ret; + + for (int i = 0; i < ST1202_MAX_LEDS; i++) { + led = &chip->leds[i]; + led->chip = chip; + led->led_num = i; + + if (!led->is_active) + continue; + + ret = st1202_channel_set(led->chip, led->led_num, true); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to activate LED channel\n"); + + ret = st1202_led_pattern_clear(&led->led_cdev); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to clear LED pattern\n"); + } + + return 0; +} + +static const struct i2c_device_id st1202_id[] = { + { "st1202-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, st1202_id); + +static const struct of_device_id st1202_dt_ids[] = { + { .compatible = "st,led1202" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, st1202_dt_ids); + +static struct i2c_driver st1202_driver = { + .driver = { + .name = "leds-st1202", + .of_match_table = of_match_ptr(st1202_dt_ids), + }, + .probe = st1202_probe, + .id_table = st1202_id, +}; +module_i2c_driver(st1202_driver); + +MODULE_AUTHOR("Remote Tech LTD"); +MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver"); +MODULE_LICENSE("GPL"); -- 2.51.0 From d379a1ad8f3ca2546f188f019764f46e06fdf24e Mon Sep 17 00:00:00 2001 From: Manuel Fombuena Date: Fri, 17 Jan 2025 12:31:49 +0000 Subject: [PATCH 328/517] leds: leds-st1202: fix NULL pointer access on race condition st1202_dt_init() calls devm_led_classdev_register_ext() before the internal data structures are properly setup, so the leds become visible to user space while being partially initialized, leading to a window where trying to access them causes a NULL pointer access. This change moves devm_led_classdev_register_ext() to the last thing to happen during initialization to eliminate it. Signed-off-by: Manuel Fombuena --- drivers/leds/leds-st1202.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c index b691c4886993..e894b3f9a0f4 100644 --- a/drivers/leds/leds-st1202.c +++ b/drivers/leds/leds-st1202.c @@ -261,8 +261,6 @@ static int st1202_dt_init(struct st1202_chip *chip) int err, reg; for_each_available_child_of_node_scoped(dev_of_node(dev), child) { - struct led_init_data init_data = {}; - err = of_property_read_u32(child, "reg", ®); if (err) return dev_err_probe(dev, err, "Invalid register\n"); @@ -276,15 +274,6 @@ static int st1202_dt_init(struct st1202_chip *chip) led->led_cdev.pattern_set = st1202_led_pattern_set; led->led_cdev.pattern_clear = st1202_led_pattern_clear; led->led_cdev.default_trigger = "pattern"; - - init_data.fwnode = led->fwnode; - init_data.devicename = "st1202"; - init_data.default_label = ":"; - - err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data); - if (err < 0) - return dev_err_probe(dev, err, "Failed to register LED class device\n"); - led->led_cdev.brightness_set = st1202_brightness_set; led->led_cdev.brightness_get = st1202_brightness_get; } @@ -368,6 +357,7 @@ static int st1202_probe(struct i2c_client *client) return ret; for (int i = 0; i < ST1202_MAX_LEDS; i++) { + struct led_init_data init_data = {}; led = &chip->leds[i]; led->chip = chip; led->led_num = i; @@ -384,6 +374,15 @@ static int st1202_probe(struct i2c_client *client) if (ret < 0) return dev_err_probe(&client->dev, ret, "Failed to clear LED pattern\n"); + + init_data.fwnode = led->fwnode; + init_data.devicename = "st1202"; + init_data.default_label = ":"; + + ret = devm_led_classdev_register_ext(&client->dev, &led->led_cdev, &init_data); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to register LED class device\n"); } return 0; -- 2.51.0 From 563309444342b92bf2a677a057a3ed0753c5a2d6 Mon Sep 17 00:00:00 2001 From: Oskari Lemmela Date: Sat, 13 Jul 2024 18:56:59 +0300 Subject: [PATCH 329/517] net: ag71xx: fix qca9530 and qca9550 mdio probe Newer QCA9530 and QCA9550 devices should use same div table as AR933X. Fixes: d51b6ce441d3 ("net: ethernet: add ag71xx driver") Signed-off-by: Oskari Lemmela --- drivers/net/ethernet/atheros/ag71xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index bccc7e7b2a84..adac0a9e0ceb 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -641,7 +641,8 @@ static int ag71xx_mdio_get_divider(struct ag71xx *ag, u32 *div) if (!ref_clock) return -EINVAL; - if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340)) { + if (ag71xx_is(ag, AR9330) || ag71xx_is(ag, AR9340) || + ag71xx_is(ag, QCA9530) || ag71xx_is(ag, QCA9550)) { table = ar933x_mdio_div_table; ndivs = ARRAY_SIZE(ar933x_mdio_div_table); } else if (ag71xx_is(ag, AR7240)) { -- 2.51.0 From d35ab9470d3d007cfbae608b5c50dabc29299843 Mon Sep 17 00:00:00 2001 From: Imre Kaloz Date: Mon, 3 Nov 2025 15:50:14 +0100 Subject: [PATCH 330/517] init: add CONFIG_MANGLE_BOOTARGS and disable it by default Enabling this option renames the bootloader supplied root= and rootfstype= variables, which might have to be know but would break the automatisms OpenWrt uses. Signed-off-by: Imre Kaloz --- init/Kconfig | 9 +++++++++ init/main.c | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/init/Kconfig b/init/Kconfig index 9b04e413be82..0de264f33b49 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1888,6 +1888,15 @@ config ARCH_HAS_MEMBARRIER_CALLBACKS config ARCH_HAS_MEMBARRIER_SYNC_CORE bool +config MANGLE_BOOTARGS + bool "Rename offending bootargs" + depends on EXPERT + help + Sometimes the bootloader passed bogus root= and rootfstype= + parameters to the kernel, and while you want to ignore them, + you need to know the values f.e. to support dual firmware + layouts on the flash. + config HAVE_PERF_EVENTS bool help diff --git a/init/main.c b/init/main.c index 821df1f05e9c..13fdc3236647 100644 --- a/init/main.c +++ b/init/main.c @@ -633,6 +633,29 @@ static inline void setup_nr_cpu_ids(void) { } static inline void smp_prepare_cpus(unsigned int maxcpus) { } #endif +#ifdef CONFIG_MANGLE_BOOTARGS +static void __init mangle_bootargs(char *command_line) +{ + char *rootdev; + char *rootfs; + + rootdev = strstr(command_line, "root=/dev/mtdblock"); + + if (rootdev) + strncpy(rootdev, "mangled_rootblock=", 18); + + rootfs = strstr(command_line, "rootfstype"); + + if (rootfs) + strncpy(rootfs, "mangled_fs", 10); + +} +#else +static void __init mangle_bootargs(char *command_line) +{ +} +#endif + /* * We need to store the untouched command line for future reference. * We also need to store the touched command line since the parameter @@ -939,6 +962,7 @@ void start_kernel(void) jump_label_init(); static_call_init(); early_security_init(); + mangle_bootargs(command_line); setup_boot_config(); setup_command_line(command_line); setup_nr_cpu_ids(); -- 2.51.0 From 8ffc66f125f867d5a7b40ab3b1e0735ec30b7e2f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 7 May 2024 12:22:15 +0200 Subject: [PATCH 331/517] kernel: fix tools build breakage on macos with x86 Signed-off-by: Felix Fietkau --- tools/arch/x86/include/asm/insn.h | 2 +- tools/arch/x86/include/asm/orc_types.h | 10 ++++++++++ tools/arch/x86/lib/insn.c | 4 ++++ tools/include/asm-generic/bitops/fls.h | 3 +++ tools/include/linux/rbtree.h | 1 - tools/include/linux/types.h | 1 + tools/lib/string.c | 2 ++ tools/lib/subcmd/exec-cmd.c | 3 +++ tools/objtool/Makefile | 2 ++ tools/objtool/include/objtool/objtool.h | 1 + tools/scripts/Makefile.include | 10 ++++++---- 11 files changed, 33 insertions(+), 6 deletions(-) diff --git a/tools/arch/x86/include/asm/insn.h b/tools/arch/x86/include/asm/insn.h index 0e5abd896ad4..f65f0f2a5466 100644 --- a/tools/arch/x86/include/asm/insn.h +++ b/tools/arch/x86/include/asm/insn.h @@ -7,7 +7,7 @@ * Copyright (C) IBM Corporation, 2009 */ -#include +#include /* insn_attr_t is defined in inat.h */ #include "inat.h" /* __ignore_sync_check__ */ diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/include/asm/orc_types.h index 46d7e06763c9..6e4afd2ec247 100644 --- a/tools/arch/x86/include/asm/orc_types.h +++ b/tools/arch/x86/include/asm/orc_types.h @@ -46,7 +46,17 @@ #define ORC_TYPE_REGS_PARTIAL 4 #ifndef __ASSEMBLY__ +#ifdef __APPLE__ +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define __LITTLE_ENDIAN_BITFIELD +#elif __BYTE_ORDER == __BIG_ENDIAN +#define __BIG_ENDIAN_BITFIELD +#endif +#else #include +#endif /* * This struct is more or less a vastly simplified version of the DWARF Call diff --git a/tools/arch/x86/lib/insn.c b/tools/arch/x86/lib/insn.c index e91d4c4e1c16..613539c3b015 100644 --- a/tools/arch/x86/lib/insn.c +++ b/tools/arch/x86/lib/insn.c @@ -15,7 +15,11 @@ #include "../include/asm/insn.h" /* __ignore_sync_check__ */ #include /* __ignore_sync_check__ */ +#ifdef __KERNEL__ #include +#else +#include +#endif #include #include "../include/asm/emulate_prefix.h" /* __ignore_sync_check__ */ diff --git a/tools/include/asm-generic/bitops/fls.h b/tools/include/asm-generic/bitops/fls.h index 26f3ce1dd6e4..d028c2eab89b 100644 --- a/tools/include/asm-generic/bitops/fls.h +++ b/tools/include/asm-generic/bitops/fls.h @@ -2,6 +2,8 @@ #ifndef _ASM_GENERIC_BITOPS_FLS_H_ #define _ASM_GENERIC_BITOPS_FLS_H_ +#include + /** * generic_fls - find last (most-significant) bit set * @x: the word to search @@ -10,6 +12,7 @@ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. */ +#define generic_fls __linux_fls static __always_inline int generic_fls(unsigned int x) { int r = 32; diff --git a/tools/include/linux/rbtree.h b/tools/include/linux/rbtree.h index 2680f2edb837..656890130ffd 100644 --- a/tools/include/linux/rbtree.h +++ b/tools/include/linux/rbtree.h @@ -18,7 +18,6 @@ #define __TOOLS_LINUX_PERF_RBTREE_H #include -#include struct rb_node { unsigned long __rb_parent_color; diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 8519386acd23..be6804eb9f82 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -56,6 +56,7 @@ typedef __s8 s8; #define __user #endif #define __must_check +#undef __cold #define __cold typedef __u16 __bitwise __le16; diff --git a/tools/lib/string.c b/tools/lib/string.c index 3126d2cff716..5016d4ccae24 100644 --- a/tools/lib/string.c +++ b/tools/lib/string.c @@ -96,6 +96,7 @@ int strtobool(const char *s, bool *res) * If libc has strlcpy() then that version will override this * implementation: */ +#ifndef __APPLE__ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wignored-attributes" @@ -114,6 +115,7 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) #ifdef __clang__ #pragma clang diagnostic pop #endif +#endif /** * skip_spaces - Removes leading whitespace from @str. diff --git a/tools/lib/subcmd/exec-cmd.c b/tools/lib/subcmd/exec-cmd.c index 7739b5217cf6..dc82cacd82cb 100644 --- a/tools/lib/subcmd/exec-cmd.c +++ b/tools/lib/subcmd/exec-cmd.c @@ -12,7 +12,10 @@ #include "subcmd-config.h" #define MAX_ARGS 32 + +#ifndef PATH_MAX #define PATH_MAX 4096 +#endif static const char *argv_exec_path; static const char *argv0_path; diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index bf7f7f84ac62..aa6deced92d2 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -39,6 +39,8 @@ OBJTOOL_LDFLAGS := $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) elfshdr := $(shell echo '$(pound)include ' | $(HOSTCC) $(OBJTOOL_CFLAGS) -x c -E - | grep elf_getshdr) OBJTOOL_CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) +OBJTOOL_CFLAGS += $(HOST_EXTRACFLAGS) + # Always want host compilation. HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index 94a33ee7b363..f34332e00155 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -12,6 +12,7 @@ #include +#undef __weak #define __weak __attribute__((weak)) struct pv_state { diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 5f2afd95de43..dd3369624bdb 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -72,8 +72,6 @@ $(call allow-override,CXX,$(CROSS_COMPILE)g++) $(call allow-override,STRIP,$(CROSS_COMPILE)strip) endif -CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) - ifneq ($(LLVM),) HOSTAR ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX) HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX) @@ -84,6 +82,9 @@ HOSTCC ?= gcc HOSTLD ?= ld endif +CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) +HOSTCC_NO_CLANG := $(shell $(HOSTCC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) + # Some tools require Clang, LLC and/or LLVM utils CLANG ?= clang LLC ?= llc @@ -92,8 +93,9 @@ LLVM_OBJCOPY ?= llvm-objcopy LLVM_STRIP ?= llvm-strip ifeq ($(CC_NO_CLANG), 1) -EXTRA_WARNINGS += -Wstrict-aliasing=3 - + ifeq ($(HOSTCC_NO_CLANG), 1) + EXTRA_WARNINGS += -Wstrict-aliasing=3 + endif else ifneq ($(CROSS_COMPILE),) # Allow userspace to override CLANG_CROSS_FLAGS to specify their own # sysroots and flags or to avoid the GCC call in pure Clang builds. -- 2.51.0 From c9d439a6002e088e00dda40c83df1e5fcd956ae4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 16:56:48 +0200 Subject: [PATCH 332/517] build: add a hack for removing non-essential module info Signed-off-by: Felix Fietkau --- include/linux/module.h | 13 ++++++++----- include/linux/moduleparam.h | 12 +++++++++++- kernel/module/Kconfig | 7 +++++++ kernel/module/main.c | 7 ++++++- scripts/mod/modpost.c | 10 ++++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 7886217c9988..22566f9aa0ee 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -166,6 +166,7 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name); /* Generic info of form tag = "info" */ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) +#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) /* For userspace: you can also call me... */ #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) @@ -241,12 +242,12 @@ struct module_kobject *lookup_or_create_module_kobject(const char *name); * Author(s), use "Name " or just "Name", for multiple * authors use multiple MODULE_AUTHOR() statements/lines. */ -#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) +#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) /* What your module does. */ -#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) +#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) -#ifdef MODULE +#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) /* Creates an alias so file2alias.c can find device table. */ #define MODULE_DEVICE_TABLE(type, name) \ extern typeof(name) __mod_##type##__##name##_device_table \ @@ -273,7 +274,9 @@ extern typeof(name) __mod_##type##__##name##_device_table \ */ #if defined(MODULE) || !defined(CONFIG_SYSFS) -#define MODULE_VERSION(_version) MODULE_INFO(version, _version) +#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) +#elif defined(CONFIG_MODULE_STRIPPED) +#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) #else #define MODULE_VERSION(_version) \ MODULE_INFO(version, _version); \ @@ -296,7 +299,7 @@ extern typeof(name) __mod_##type##__##name##_device_table \ /* Optional firmware file (or files) needed by the module * format is simply firmware file name. Multiple firmware * files require multiple MODULE_FIRMWARE() specifiers */ -#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) +#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, __stringify(ns)) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 110e9d09de24..198f715e7bcc 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -20,6 +20,16 @@ /* Chosen so that structs with an unsigned long line up. */ #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) +/* This struct is here for syntactic coherency, it is not used */ +#define __MODULE_INFO_DISABLED(name) \ + struct __UNIQUE_ID(name) {} + +#ifdef CONFIG_MODULE_STRIPPED +#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) +#else +#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) +#endif + #define __MODULE_INFO(tag, name, info) \ static const char __UNIQUE_ID(name)[] \ __used __section(".modinfo") __aligned(1) \ @@ -31,7 +41,7 @@ /* One for each parameter, describing how to use it. Some files do multiple of these per line, so can't just use MODULE_INFO. */ #define MODULE_PARM_DESC(_parm, desc) \ - __MODULE_INFO(parm, _parm, #_parm ":" desc) + __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) struct kernel_param; diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig index 0c746a150e34..ccc20082d0f0 100644 --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig @@ -402,4 +402,11 @@ config MODULES_TREE_LOOKUP def_bool y depends on PERF_EVENTS || TRACING || CFI_CLANG +config MODULE_STRIPPED + bool "Reduce module size" + depends on MODULES + help + Remove module parameter descriptions, author info, version, aliases, + device tables, etc. + endif # MODULES diff --git a/kernel/module/main.c b/kernel/module/main.c index 4511d0a4762a..2122fab827f1 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1001,6 +1001,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs); static const char vermagic[] = VERMAGIC_STRING; +#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED) int try_to_force_load(struct module *mod, const char *reason) { #ifdef CONFIG_MODULE_FORCE_LOAD @@ -1012,6 +1013,7 @@ int try_to_force_load(struct module *mod, const char *reason) return -ENOEXEC; #endif } +#endif /* Parse tag=value strings from .modinfo section */ char *module_next_tag_pair(char *string, unsigned long *secsize) @@ -2095,9 +2097,11 @@ static void module_augment_kernel_taints(struct module *mod, struct load_info *i static int check_modinfo(struct module *mod, struct load_info *info, int flags) { - const char *modmagic = get_modinfo(info, "vermagic"); int err; +#ifndef CONFIG_MODULE_STRIPPED + const char *modmagic = get_modinfo(info, "vermagic"); + if (flags & MODULE_INIT_IGNORE_VERMAGIC) modmagic = NULL; @@ -2111,6 +2115,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) info->name, modmagic, vermagic); return -ENOEXEC; } +#endif err = check_modinfo_livepatch(mod, info); if (err) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 971eda0c6ba7..f90320fdea74 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1601,7 +1601,9 @@ static void read_symbols(const char *modname) symname = remove_dot(info.strtab + sym->st_name); handle_symbol(mod, &info, sym, symname); +#ifndef CONFIG_MODULE_STRIPPED handle_moddevtable(mod, &info, sym, symname); +#endif } check_sec_ref(mod, &info); @@ -1758,7 +1760,9 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); +#ifndef CONFIG_MODULE_STRIPPED buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); +#endif buf_printf(b, "\n"); buf_printf(b, "__visible struct module __this_module\n"); buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); @@ -1772,11 +1776,13 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); +#ifndef CONFIG_MODULE_STRIPPED if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); if (strstarts(mod->name, "drivers/staging")) buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); +#endif if (strstarts(mod->name, "tools/testing")) buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); @@ -1886,11 +1892,13 @@ static void add_depends(struct buffer *b, struct module *mod) static void add_srcversion(struct buffer *b, struct module *mod) { +#ifndef CONFIG_MODULE_STRIPPED if (mod->srcversion[0]) { buf_printf(b, "\n"); buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", mod->srcversion); } +#endif } static void write_buf(struct buffer *b, const char *fname) @@ -1973,7 +1981,9 @@ static void write_mod_c_file(struct module *mod) add_exported_symbols(&buf, mod); add_versions(&buf, mod); add_depends(&buf, mod); +#ifndef CONFIG_MODULE_STRIPPED add_moddevtable(&buf, mod); +#endif add_srcversion(&buf, mod); ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); -- 2.51.0 From b3b18ef0e01eaa79077ae5c4f669df7d62d59695 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 11 Nov 2022 13:33:44 +0100 Subject: [PATCH 333/517] kconfig: abort configuration on unset symbol When a target configuration has unset Kconfig symbols, the build will fail when OpenWrt is compiled with V=s and stdin is connected to a tty. In case OpenWrt is compiled without either of these preconditions, the build will succeed with the symbols in question being unset. Modify the kernel configuration in a way it fails on unset symbols regardless of the aforementioned preconditions. Signed-off-by: David Bauer --- scripts/kconfig/conf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 3d7d454c54da..d260f1519722 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -312,6 +312,9 @@ static int conf_askvalue(struct symbol *sym, const char *def) } /* fall through */ default: + if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { + exit(1); + } fflush(stdout); xfgets(line, sizeof(line), stdin); break; @@ -470,6 +473,9 @@ static void conf_choice(struct menu *menu) } /* fall through */ case oldaskconfig: + if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { + exit(1); + } fflush(stdout); xfgets(line, sizeof(line), stdin); strip(line); -- 2.51.0 From e94565caa2778a2c0a56e359b47169cea8111d3f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 7 Jul 2017 17:00:49 +0200 Subject: [PATCH 334/517] Add an OSX specific patch to make the kernel be compiled lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526 Signed-off-by: Florian Fainelli --- scripts/mod/elf.h | 3007 ++++++++++++++++++++++++++++++++++++ scripts/mod/mk_elfconfig.c | 4 + scripts/mod/modpost.h | 4 + 3 files changed, 3015 insertions(+) create mode 100644 scripts/mod/elf.h diff --git a/scripts/mod/elf.h b/scripts/mod/elf.h new file mode 100644 index 000000000000..036a176345eb --- /dev/null +++ b/scripts/mod/elf.h @@ -0,0 +1,3007 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ELF_H +#define _ELF_H 1 + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_NUM 192 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ + +#define PN_XNUM 0xffff + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ + +#define AT_RANDOM 25 /* Address of 16 random bytes. */ + +#define AT_EXECFN 31 /* Filename of executable. */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ + +/* Known OSes. These values can appear in word 0 of an + NT_GNU_ABI_TAG note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +/* Synthetic hwcap information. The descriptor begins with two words: + word 0: number of entries + word 1: bitmask of enabled entries + Then follow variable-length entries, one byte followed by a + '\0'-terminated hwcap name string. The byte gives the bit + number to test if enabled, (1U << bit) & bitmask. */ +#define NT_GNU_HWCAP 2 + +/* Build ID bits as generated by ld --build-id. + The descriptor consists of any nonzero number of bytes. */ +#define NT_GNU_BUILD_ID 3 + +/* Version note generated by GNU gold containing a version string. */ +#define NT_GNU_GOLD_VERSION 4 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ +#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ +#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ +#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ +#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ +#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ +#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ +#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ +#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ +#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ +#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ +#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ +#define R_68K_TLS_LE32 37 /* 32 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE16 38 /* 16 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE8 39 /* 8 bit offset relative to + static TLS block */ +#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ +#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ +#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ +/* Keep this the last entry. */ +#define R_68K_NUM 43 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* 38? */ +#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ +#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS + descriptor for + relaxation. */ +#define R_386_TLS_DESC 41 /* TLS descriptor containing + pointer to code and to + argument, returning the TLS + offset for the symbol. */ +#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ +/* Keep this the last entry. */ +#define R_386_NUM 43 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_WDISP10 88 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 +/* Keep this the last entry. */ +#define R_SPARC_NUM 253 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +/* Keep this the last entry. */ +#define R_MIPS_NUM 128 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +/* The address of .got.plt in an executable using the new non-PIC ABI. */ +#define DT_MIPS_PLTGOT 0x70000032 +/* The base of the PLT in an executable using the new non-PIC ABI if that + PLT is writable. For a non-writable PLT, this is omitted or has a zero + value. */ +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_NUM 0x35 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ +#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ +#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ +#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ +#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ +#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ +#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ +#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ +#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ +#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ +#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ +#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +/* Legal values for d_tag of Elf64_Dyn. */ +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* GNU extension to support local ifunc. */ +#define R_PPC_IRELATIVE 248 + +/* GNU relocs used in PIC code sequences. */ +#define R_PPC_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +/* PowerPC specific values for the Dyn d_tag field. */ +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_NUM 1 + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* GNU extension to support local ifunc. */ +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step. */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 /* Obsolete static relocation. */ +#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic + thread local data */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic + thread local data */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS + block */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of + static TLS block offset */ +#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static + TLS block */ +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* S/390 specific definitions. */ + +/* Valid values for the e_flags field. */ + +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ +#define R_390_20 57 /* Direct 20 bit. */ +#define R_390_GOT20 58 /* 20 bit GOT offset. */ +#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ +#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS + block offset. */ +#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_390_NUM 62 + + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ +#define R_X86_64_PC64 24 /* PC relative 64 bit */ +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ +#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset + to GOT entry */ +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset + to PLT entry */ +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS + descriptor. */ +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ + +#define R_X86_64_NUM 39 + + +/* AM33 relocations. */ +#define R_MN10300_NONE 0 /* No reloc. */ +#define R_MN10300_32 1 /* Direct 32 bit. */ +#define R_MN10300_16 2 /* Direct 16 bit. */ +#define R_MN10300_8 3 /* Direct 8 bit. */ +#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ +#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ +#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ +#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ +#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ +#define R_MN10300_24 9 /* Direct 24 bit. */ +#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ +#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ +#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ +#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ +#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ +#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ +#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ +#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ +#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ +#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ +#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ +#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ +#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ +#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ + +#define R_MN10300_NUM 24 + + +/* M32R relocs. */ +#define R_M32R_NONE 0 /* No reloc. */ +#define R_M32R_16 1 /* Direct 16 bit. */ +#define R_M32R_32 2 /* Direct 32 bit. */ +#define R_M32R_24 3 /* Direct 24 bit. */ +#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ +#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ +#define R_M32R_LO16 9 /* Low 16 bit. */ +#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/* M32R relocs use SHT_RELA. */ +#define R_M32R_16_RELA 33 /* Direct 16 bit. */ +#define R_M32R_32_RELA 34 /* Direct 32 bit. */ +#define R_M32R_24_RELA 35 /* Direct 24 bit. */ +#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ +#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ +#define R_M32R_LO16_RELA 41 /* Low 16 bit */ +#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 /* PC relative 32 bit. */ + +#define R_M32R_GOT24 48 /* 24 bit GOT entry */ +#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ +#define R_M32R_COPY 50 /* Copy symbol at runtime */ +#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ +#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ +#define R_M32R_RELATIVE 53 /* Adjust by program base */ +#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ +#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ +#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned + low */ +#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed + low */ +#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ +#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to + GOT with unsigned low */ +#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to + GOT with signed low */ +#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to + GOT */ +#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT + with unsigned low */ +#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT + with signed low */ +#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ +#define R_M32R_NUM 256 /* Keep this the last entry. */ + + +/* TILEPro relocations. */ +#define R_TILEPRO_NONE 0 /* No reloc */ +#define R_TILEPRO_32 1 /* Direct 32 bit */ +#define R_TILEPRO_16 2 /* Direct 16 bit */ +#define R_TILEPRO_8 3 /* Direct 8 bit */ +#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ +#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ +#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ +#define R_TILEPRO_LO16 7 /* Low 16 bit */ +#define R_TILEPRO_HI16 8 /* High 16 bit */ +#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ +#define R_TILEPRO_COPY 10 /* Copy relocation */ +#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ +#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ +#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ +#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ +#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ +#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ +#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ +#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ +#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ +#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ +#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ +#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ +#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ +#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ +#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ +#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ +#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ +#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ +#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ +/* Relocs 56-59 are currently not defined. */ +#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ +#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ +#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ +#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ +#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ +#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ + +#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEPRO_NUM 130 + + +/* TILE-Gx relocations. */ +#define R_TILEGX_NONE 0 /* No reloc */ +#define R_TILEGX_64 1 /* Direct 64 bit */ +#define R_TILEGX_32 2 /* Direct 32 bit */ +#define R_TILEGX_16 3 /* Direct 16 bit */ +#define R_TILEGX_8 4 /* Direct 8 bit */ +#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ +#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ +#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ +#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ +#define R_TILEGX_HW0 9 /* hword 0 16-bit */ +#define R_TILEGX_HW1 10 /* hword 1 16-bit */ +#define R_TILEGX_HW2 11 /* hword 2 16-bit */ +#define R_TILEGX_HW3 12 /* hword 3 16-bit */ +#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ +#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ +#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ +#define R_TILEGX_COPY 16 /* Copy relocation */ +#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ +#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ +#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ +#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ +#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ +#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ +#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ +#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ +#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ +#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ +#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ +#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ +#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ +#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ +#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ +#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ +#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ +#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ +#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ +#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ +#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ +#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ +#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ +#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ +#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ +#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ +#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ +/* Relocs 66-71 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ +/* Relocs 76-77 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ +/* Relocs 90-91 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ +/* Relocs 94-99 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ +/* Relocs 104-105 are currently not defined. */ +#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ +#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ +#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ +#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ +#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ + +#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEGX_NUM 130 + +#endif /* elf.h */ diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index e8cee4e4bc73..bba672c0ac8d 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -2,7 +2,11 @@ #include #include #include +#ifndef __APPLE__ #include +#else +#include "elf.h" +#endif int main(int argc, char **argv) diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index ada3a36cc4bc..b77c2b100c1c 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -10,7 +10,11 @@ #include #include #include +#if !(defined(__APPLE__) || defined(__CYGWIN__)) #include +#else +#include "elf.h" +#endif #include "../../include/linux/module_symbol.h" #include -- 2.51.0 From ce8e117a6d444db0417063bea67049d2a685dac8 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Wed, 5 Feb 2020 18:36:43 +0000 Subject: [PATCH 335/517] file2alias: build on macos Signed-off-by: Kevin Darbyshire-Bryant --- scripts/mod/file2alias.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 721e0e9f17ca..70d9013cad52 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -35,6 +35,9 @@ typedef uint32_t __u32; typedef uint16_t __u16; typedef unsigned char __u8; +#ifdef __APPLE__ +#define uuid_t compat_uuid_t +#endif /* UUID types for backward compatibility, don't use in new code */ typedef struct { __u8 b[16]; -- 2.51.0 From 85b0cd39287de717d1d7b9165119a1ab54d8429c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 17:04:08 +0200 Subject: [PATCH 336/517] kernel: fix linux/spi/spidev.h portability issues with musl Felix will try to get this define included into musl lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff Signed-off-by: Felix Fietkau --- include/uapi/linux/spi/spidev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h index 0c3da08f2aff..2a6d51008256 100644 --- a/include/uapi/linux/spi/spidev.h +++ b/include/uapi/linux/spi/spidev.h @@ -93,7 +93,7 @@ struct spi_ioc_transfer { /* not all platforms use or _IOC_TYPECHECK() ... */ #define SPI_MSGSIZE(N) \ - ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ + ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) -- 2.51.0 From e29ddf5fd71094fc52c65223084759947c6bd3a3 Mon Sep 17 00:00:00 2001 From: Imre Kaloz Date: Fri, 7 Jul 2017 17:06:55 +0200 Subject: [PATCH 337/517] use the openwrt lzma options for now lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c Signed-off-by: Imre Kaloz --- lib/decompress.c | 1 + scripts/Makefile.lib | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/decompress.c b/lib/decompress.c index ab3fc90ffc64..b9c1e51e4ebb 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -53,6 +53,7 @@ static const struct compress_format compressed_formats[] __initconst = { { {0x1f, 0x9e}, "gzip", gunzip }, { {0x42, 0x5a}, "bzip2", bunzip2 }, { {0x5d, 0x00}, "lzma", unlzma }, + { {0x6d, 0x00}, "lzma-openwrt", unlzma }, { {0xfd, 0x37}, "xz", unxz }, { {0x89, 0x4c}, "lzo", unlzo }, { {0x02, 0x21}, "lz4", unlz4 }, diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 85e41c68c2c5..cc6992a801a7 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -359,10 +359,10 @@ quiet_cmd_bzip2_with_size = BZIP2 $@ # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ - cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@ + cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@ quiet_cmd_lzma_with_size = LZMA $@ - cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ + cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ quiet_cmd_lzo = LZO $@ cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@ -- 2.51.0 From c6d1cf47863c85f7ae9be28da8fac7c491fe4ecd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 3 Nov 2025 15:50:16 +0100 Subject: [PATCH 338/517] hack: net: remove bogus netfilter dependencies lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6 Signed-off-by: Felix Fietkau --- net/netfilter/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index df2dc21304ef..f7cde787a680 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -259,7 +259,6 @@ config NF_CONNTRACK_FTP config NF_CONNTRACK_H323 tristate "H.323 protocol support" - depends on IPV6 || IPV6=n depends on NETFILTER_ADVANCED help H.323 is a VoIP signalling protocol from ITU-T. As one of the most @@ -1120,7 +1119,6 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_TCPMSS tristate '"TCPMSS" target support' - depends on IPV6 || IPV6=n default m if NETFILTER_ADVANCED=n help This option adds a `TCPMSS' target, which allows you to alter the -- 2.51.0 From d3f50001d74545ae24daed6e79a96c24cb8823ac Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 7 Jul 2017 17:09:21 +0200 Subject: [PATCH 339/517] kconfig: owrt specifc dependencies Signed-off-by: John Crispin --- crypto/Kconfig | 10 +++++----- drivers/bcma/Kconfig | 1 + drivers/ssb/Kconfig | 3 ++- lib/Kconfig | 8 ++++---- net/Kconfig | 2 +- net/netfilter/Kconfig | 2 +- sound/core/Kconfig | 4 ++-- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index e7528986e94f..79fc693086b7 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION By default the KERNELRELEASE value is used. config CRYPTO_ALGAPI - tristate + tristate "ALGAPI" select CRYPTO_ALGAPI2 help This option provides the API for cryptographic algorithms. @@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2 tristate config CRYPTO_AEAD - tristate + tristate "AEAD" select CRYPTO_AEAD2 select CRYPTO_ALGAPI @@ -82,7 +82,7 @@ config CRYPTO_SIG2 select CRYPTO_ALGAPI2 config CRYPTO_SKCIPHER - tristate + tristate "SKCIPHER" select CRYPTO_SKCIPHER2 select CRYPTO_ALGAPI select CRYPTO_ECB @@ -92,7 +92,7 @@ config CRYPTO_SKCIPHER2 select CRYPTO_ALGAPI2 config CRYPTO_HASH - tristate + tristate "HASH" select CRYPTO_HASH2 select CRYPTO_ALGAPI @@ -101,7 +101,7 @@ config CRYPTO_HASH2 select CRYPTO_ALGAPI2 config CRYPTO_RNG - tristate + tristate "RNG" select CRYPTO_RNG2 select CRYPTO_ALGAPI diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index b9558ff20830..2e9732e5c565 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -16,6 +16,7 @@ if BCMA # Support for Block-I/O. SELECT this from the driver that needs it. config BCMA_BLOCKIO bool + default y config BCMA_HOST_PCI_POSSIBLE bool diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 1cf1a98952fa..2bcf62e64f6f 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -29,6 +29,7 @@ config SSB_SPROM config SSB_BLOCKIO bool depends on SSB + default y config SSB_PCIHOST_POSSIBLE bool @@ -49,7 +50,7 @@ config SSB_PCIHOST config SSB_B43_PCI_BRIDGE bool depends on SSB_PCIHOST - default n + default y config SSB_PCMCIAHOST_POSSIBLE bool diff --git a/lib/Kconfig b/lib/Kconfig index e9088bd10a6c..1ddb823c425e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -457,16 +457,16 @@ config BCH_CONST_T # Textsearch support is select'ed if needed # config TEXTSEARCH - bool + bool "Textsearch support" config TEXTSEARCH_KMP - tristate + tristate "Textsearch KMP" config TEXTSEARCH_BM - tristate + tristate "Textsearch BM" config TEXTSEARCH_FSM - tristate + tristate "Textsearch FSM" config BTREE bool diff --git a/net/Kconfig b/net/Kconfig index a629f92dc86b..6744f55d9683 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -484,7 +484,7 @@ config NET_DEVLINK default n config PAGE_POOL - bool + bool "Page pool support" config PAGE_POOL_STATS default n diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index f7cde787a680..944a47d0e2fd 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB) config NETFILTER_NETLINK - tristate + tristate "Netfilter NFNETLINK interface" config NETFILTER_FAMILY_BRIDGE bool diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 2c5b9f964703..e2e942179a09 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM tristate config SND_HWDEP - tristate + tristate "Sound hardware support" config SND_SEQ_DEVICE tristate @@ -57,7 +57,7 @@ config SND_CORE_TEST config SND_COMPRESS_OFFLOAD - tristate + tristate "Compression offloading support" config SND_JACK bool -- 2.51.0 From 96c73d623607c4b0d07e488648bc48d1b4297872 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:33:30 +0200 Subject: [PATCH 340/517] Kconfig: add tristate for OID and ASNI string --- init/Kconfig | 2 +- lib/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index 0de264f33b49..dfc689f2a766 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2063,7 +2063,7 @@ config PADATA bool config ASN1 - tristate + tristate "ASN1" help Build a simple ASN.1 grammar compiler that produces a bytecode output that can be interpreted by the ASN.1 stream decoder and used to diff --git a/lib/Kconfig b/lib/Kconfig index 1ddb823c425e..c8cc10b1f163 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -642,7 +642,7 @@ config LIBFDT bool config OID_REGISTRY - tristate + tristate "OID" help Enable fast lookup object identifier registry. -- 2.51.0 From 8aaddb765893f392454753b44f0a4de7fe456788 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 15 Jul 2017 21:12:38 +0200 Subject: [PATCH 341/517] kernel: move regmap bloat out of the kernel image if it is only being used in modules lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998 Signed-off-by: Felix Fietkau --- drivers/base/regmap/Kconfig | 21 ++++++++++++++++++--- drivers/base/regmap/Makefile | 8 +++++--- drivers/base/regmap/regmap.c | 3 +++ include/linux/regmap.h | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index b1affac70d5d..4a6c93b51767 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,8 +4,7 @@ # subsystems should select the appropriate symbols. config REGMAP - bool - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI) + tristate select IRQ_DOMAIN if REGMAP_IRQ select MDIO_BUS if REGMAP_MDIO help @@ -19,7 +18,7 @@ config REGMAP config REGMAP_KUNIT tristate "KUnit tests for regmap" - depends on KUNIT && REGMAP + depends on KUNIT default KUNIT_ALL_TESTS select REGMAP_RAM @@ -34,60 +33,76 @@ config REGMAP_BUILD normally enabled. config REGMAP_AC97 + select REGMAP tristate config REGMAP_I2C + select REGMAP tristate depends on I2C config REGMAP_SLIMBUS + select REGMAP tristate depends on SLIMBUS config REGMAP_SPI + select REGMAP tristate depends on SPI config REGMAP_SPMI + select REGMAP tristate depends on SPMI config REGMAP_W1 + select REGMAP tristate depends on W1 config REGMAP_MDIO + select REGMAP tristate config REGMAP_MMIO + select REGMAP tristate config REGMAP_IRQ + select REGMAP bool config REGMAP_RAM + select REGMAP tristate config REGMAP_SOUNDWIRE + select REGMAP tristate depends on SOUNDWIRE config REGMAP_SOUNDWIRE_MBQ + select REGMAP tristate depends on SOUNDWIRE config REGMAP_SCCB + select REGMAP tristate depends on I2C config REGMAP_I3C + select REGMAP tristate depends on I3C config REGMAP_SPI_AVMM + select REGMAP tristate depends on SPI config REGMAP_FSI + select REGMAP tristate depends on FSI diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 5fdd0845b45e..f171215a71f7 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -2,9 +2,11 @@ # For include/trace/define_trace.h to include trace.h CFLAGS_regmap.o := -I$(src) -obj-$(CONFIG_REGMAP) += regmap.o regcache.o -obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o regcache-maple.o -obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o +regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o regcache-maple.o +ifdef CONFIG_DEBUG_FS +regmap-core-objs += regmap-debugfs.o +endif +obj-$(CONFIG_REGMAP) += regmap-core.o obj-$(CONFIG_REGMAP_KUNIT) += regmap-kunit.o obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 66b3840bd96e..93d26238811d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -3521,3 +3522,5 @@ static int __init regmap_initcall(void) return 0; } postcore_initcall(regmap_initcall); + +MODULE_LICENSE("GPL"); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index f9ccad32fc5c..bb3765f8984d 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -197,7 +197,7 @@ struct reg_sequence { __ret ?: __tmp; \ }) -#ifdef CONFIG_REGMAP +#if IS_REACHABLE(CONFIG_REGMAP) enum regmap_endian { /* Unspecified -> 0 -> Backwards compatible default */ -- 2.51.0 From d4c446b3081ba313c2fd5eba17b542e3beda61c6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 17:12:51 +0200 Subject: [PATCH 342/517] kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run Reduces kernel size after LZMA by about 5k on MIPS lede-commit: 044c316167e076479a344c59905e5b435b84a77f Signed-off-by: Felix Fietkau --- crypto/Kconfig | 18 +++++++++--------- crypto/algboss.c | 4 ++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 79fc693086b7..0f9a815d0b5e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -149,15 +149,15 @@ config CRYPTO_MANAGER cbc(aes). config CRYPTO_MANAGER2 - def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) - select CRYPTO_ACOMP2 - select CRYPTO_AEAD2 - select CRYPTO_AKCIPHER2 - select CRYPTO_SIG2 - select CRYPTO_HASH2 - select CRYPTO_KPP2 - select CRYPTO_RNG2 - select CRYPTO_SKCIPHER2 + def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS) + select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_SIG2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_RNG2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS config CRYPTO_USER tristate "Userspace cryptographic algorithm configuration" diff --git a/crypto/algboss.c b/crypto/algboss.c index a20926bfd34e..3ac655fa7b94 100644 --- a/crypto/algboss.c +++ b/crypto/algboss.c @@ -203,6 +203,10 @@ static int cryptomgr_schedule_test(struct crypto_alg *alg) memcpy(param->alg, alg->cra_name, sizeof(param->alg)); param->type = alg->cra_flags; +#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS + param->type |= CRYPTO_ALG_TESTED; +#endif + thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); if (IS_ERR(thread)) goto err_free_param; -- 2.51.0 From c59c9285d6b0e298be700e8d067881d4f0804f26 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:35:18 +0200 Subject: [PATCH 343/517] lib/crypto: add tristate string for ARC4 This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We need this to be able to compile this into the kernel and make use of it from backports. --- lib/crypto/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index b09e78da959a..6bd7c7ba58e6 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -20,7 +20,7 @@ config CRYPTO_LIB_AESGCM select CRYPTO_LIB_UTILS config CRYPTO_LIB_ARC4 - tristate + tristate "ARC4 cipher library" config CRYPTO_LIB_GF128MUL tristate -- 2.51.0 From 995f1f0db5478d75487df6df85dc4a2be4949a77 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 7 Jul 2017 17:13:44 +0200 Subject: [PATCH 344/517] rfkill: add fake rfkill support allow building of modules depending on RFKILL even if RFKILL is not enabled. Signed-off-by: John Crispin --- include/linux/rfkill.h | 2 +- net/Makefile | 2 +- net/rfkill/Kconfig | 12 ++++++++---- net/rfkill/Makefile | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 997b34197385..9ec57a9e7c9f 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -64,7 +64,7 @@ struct rfkill_ops { int (*set_block)(void *data, bool blocked); }; -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE) /** * rfkill_alloc - Allocate rfkill structure * @name: name of the struct -- the string is not copied internally diff --git a/net/Makefile b/net/Makefile index 65bb8c72a35e..d67f93b150e5 100644 --- a/net/Makefile +++ b/net/Makefile @@ -51,7 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/ obj-$(CONFIG_NETLABEL) += netlabel/ obj-$(CONFIG_IUCV) += iucv/ obj-$(CONFIG_SMC) += smc/ -obj-$(CONFIG_RFKILL) += rfkill/ +obj-$(CONFIG_RFKILL_FULL) += rfkill/ obj-$(CONFIG_NET_9P) += 9p/ obj-$(CONFIG_CAIF) += caif/ obj-$(CONFIG_DCB) += dcb/ diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig index 83a7af8982bb..d05d6ae15032 100644 --- a/net/rfkill/Kconfig +++ b/net/rfkill/Kconfig @@ -2,7 +2,11 @@ # # RF switch subsystem configuration # -menuconfig RFKILL +config RFKILL + bool + default y + +menuconfig RFKILL_FULL tristate "RF switch subsystem support" help Say Y here if you want to have control over RF switches @@ -14,19 +18,19 @@ menuconfig RFKILL # LED trigger support config RFKILL_LEDS bool - depends on RFKILL + depends on RFKILL_FULL depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS default y config RFKILL_INPUT bool "RF switch input support" if EXPERT - depends on RFKILL + depends on RFKILL_FULL depends on INPUT = y || RFKILL = INPUT default y if !EXPERT config RFKILL_GPIO tristate "GPIO RFKILL driver" - depends on RFKILL + depends on RFKILL_FULL depends on GPIOLIB || COMPILE_TEST default n help diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile index dc47b6174ec5..be58b4119dac 100644 --- a/net/rfkill/Makefile +++ b/net/rfkill/Makefile @@ -5,5 +5,5 @@ rfkill-y += core.o rfkill-$(CONFIG_RFKILL_INPUT) += input.o -obj-$(CONFIG_RFKILL) += rfkill.o +obj-$(CONFIG_RFKILL_FULL) += rfkill.o obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o -- 2.51.0 From 8e80abd396bc37470970931944b289314c894e81 Mon Sep 17 00:00:00 2001 From: Ben Menchaca Date: Fri, 7 Jun 2013 18:35:22 -0500 Subject: [PATCH 345/517] MIPS: r4k_cache: use more efficient cache blast Optimize the compiler output for larger cache blast cases that are common for DMA-based networking. Signed-off-by: Ben Menchaca Signed-off-by: Felix Fietkau --- arch/mips/include/asm/r4kcache.h | 42 ++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index da1cd1bbdbc5..1624b578a157 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -290,14 +290,46 @@ static inline void prot##extra##blast_##pfx##cache##_range(unsigned long start, unsigned long end) \ { \ unsigned long lsize = cpu_##desc##_line_size(); \ + unsigned long lsize_2 = lsize * 2; \ + unsigned long lsize_3 = lsize * 3; \ + unsigned long lsize_4 = lsize * 4; \ + unsigned long lsize_5 = lsize * 5; \ + unsigned long lsize_6 = lsize * 6; \ + unsigned long lsize_7 = lsize * 7; \ + unsigned long lsize_8 = lsize * 8; \ unsigned long addr = start & ~(lsize - 1); \ - unsigned long aend = (end - 1) & ~(lsize - 1); \ + unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \ + int lines = (aend - addr) / lsize; \ \ - while (1) { \ + while (lines >= 8) { \ + prot##cache_op(hitop, addr); \ + prot##cache_op(hitop, addr + lsize); \ + prot##cache_op(hitop, addr + lsize_2); \ + prot##cache_op(hitop, addr + lsize_3); \ + prot##cache_op(hitop, addr + lsize_4); \ + prot##cache_op(hitop, addr + lsize_5); \ + prot##cache_op(hitop, addr + lsize_6); \ + prot##cache_op(hitop, addr + lsize_7); \ + addr += lsize_8; \ + lines -= 8; \ + } \ + \ + if (lines & 0x4) { \ + prot##cache_op(hitop, addr); \ + prot##cache_op(hitop, addr + lsize); \ + prot##cache_op(hitop, addr + lsize_2); \ + prot##cache_op(hitop, addr + lsize_3); \ + addr += lsize_4; \ + } \ + \ + if (lines & 0x2) { \ + prot##cache_op(hitop, addr); \ + prot##cache_op(hitop, addr + lsize); \ + addr += lsize_2; \ + } \ + \ + if (lines & 0x1) { \ prot##cache_op(hitop, addr); \ - if (addr == aend) \ - break; \ - addr += lsize; \ } \ } -- 2.51.0 From fb6db57e6a54fc221b942ee771066ade1318a27a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 14 Apr 2025 18:04:25 +0200 Subject: [PATCH 346/517] mm: permit to declare custom execmem alloc/free function Permit to declare custom execmem alloc/free function that bypass the execmem API. This works by making the alloc/free function weak permitting an arch to declare a replacement for them. Signed-off-by: Christian Marangi Co-authored-by: Shiji Yang --- include/linux/moduleloader.h | 4 ++++ mm/execmem.c | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index e395461d59e5..ee24ba60f51a 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -122,4 +122,8 @@ void module_arch_cleanup(struct module *mod); /* Any cleanup before freeing mod->module_init */ void module_arch_freeing_init(struct module *mod); +enum execmem_type; +void *arch_execmem_alloc(enum execmem_type type, size_t size); +void arch_execmem_free(void *ptr); + #endif diff --git a/mm/execmem.c b/mm/execmem.c index 0c4b36bc6d10..3b21780a196b 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -52,14 +52,19 @@ static void *__execmem_alloc(struct execmem_range *range, size_t size) return kasan_reset_tag(p); } -void *execmem_alloc(enum execmem_type type, size_t size) +void *__weak arch_execmem_alloc(enum execmem_type type, size_t size) { struct execmem_range *range = &execmem_info->ranges[type]; return __execmem_alloc(range, size); } -void execmem_free(void *ptr) +void *execmem_alloc(enum execmem_type type, size_t size) +{ + return arch_execmem_alloc(type, size); +} + +void __weak arch_execmem_free(void *ptr) { /* * This memory may be RO, and freeing RO memory in an interrupt is not @@ -69,6 +74,11 @@ void execmem_free(void *ptr) vfree(ptr); } +void execmem_free(void *ptr) +{ + arch_execmem_free(ptr); +} + static bool execmem_validate(struct execmem_info *info) { struct execmem_range *r = &info->ranges[EXECMEM_DEFAULT]; -- 2.51.0 From a72909bbbd432df45021d446dd0983251229c5a4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 14 Apr 2025 18:05:45 +0200 Subject: [PATCH 347/517] mips: replace -mlong-calls with -mno-long-calls if possible This is a really old patch ported from MikroTik. It needs a an additional patch to actually be implemented and both this and the old one are considered HACK as they bypass normal kernel linux to make it work. The original message quote: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to load kernel modules to KSEG0 and if that doesn't work, use vmalloc and fix up relocations with a jump table based on code from a kernel patch by MikroTik. SVN-Revision: 16772 lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c Signed-off-by: Felix Fietkau Signed-off-by: Christian Marangi --- arch/mips/Makefile | 10 ++ arch/mips/include/asm/module.h | 5 + arch/mips/kernel/module.c | 281 ++++++++++++++++++++++++++++++++- 3 files changed, 292 insertions(+), 4 deletions(-) diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 2a770f13a0cc..29a7c9a55358 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely cflags-y += -msoft-float -Wa,-msoft-float LDFLAGS_vmlinux += -G 0 -static -n -nostdlib +ifdef CONFIG_64BIT KBUILD_AFLAGS_MODULE += -mlong-calls KBUILD_CFLAGS_MODULE += -mlong-calls +else + ifdef CONFIG_DYNAMIC_FTRACE + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls + else + KBUILD_AFLAGS_MODULE += -mno-long-calls + KBUILD_CFLAGS_MODULE += -mno-long-calls + endif +endif ifeq ($(CONFIG_RELOCATABLE),y) LDFLAGS_vmlinux += --emit-relocs diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index 724a0882576b..9dfc597be586 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -12,6 +12,11 @@ struct mod_arch_specific { const struct exception_table_entry *dbe_start; const struct exception_table_entry *dbe_end; struct mips_hi16 *r_mips_hi16_list; + + void *phys_plt_tbl; + void *virt_plt_tbl; + unsigned int phys_plt_offset; + unsigned int virt_plt_offset; }; typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index ba0f62d8eff5..bd731174b01e 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -8,6 +8,7 @@ #undef DEBUG +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include struct mips_hi16 { @@ -30,14 +32,254 @@ struct mips_hi16 { static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); +/* + * Get the potential max trampolines size required of the init and + * non-init sections. Only used if we cannot find enough contiguous + * physically mapped memory to put the module into. + */ +static unsigned int +get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + const char *secstrings, unsigned int symindex, bool is_init) +{ + unsigned long ret = 0; + unsigned int i, j; + Elf_Sym *syms; + + /* Everything marked ALLOC (this includes the exported symbols) */ + for (i = 1; i < hdr->e_shnum; ++i) { + unsigned int info = sechdrs[i].sh_info; + + if (sechdrs[i].sh_type != SHT_REL + && sechdrs[i].sh_type != SHT_RELA) + continue; + + /* Not a valid relocation section? */ + if (info >= hdr->e_shnum) + continue; + + /* Don't bother with non-allocated sections */ + if (!(sechdrs[info].sh_flags & SHF_ALLOC)) + continue; + + /* If it's called *.init*, and we're not init, we're + not interested */ + if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) + != is_init) + continue; + + syms = (Elf_Sym *) sechdrs[symindex].sh_addr; + if (sechdrs[i].sh_type == SHT_REL) { + Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; + unsigned int size = sechdrs[i].sh_size / sizeof(*rel); + + for (j = 0; j < size; ++j) { + Elf_Sym *sym; + + if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) + continue; + + sym = syms + ELF_MIPS_R_SYM(rel[j]); + if (!is_init && sym->st_shndx != SHN_UNDEF) + continue; + + ret += 4 * sizeof(int); + } + } else { + Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; + unsigned int size = sechdrs[i].sh_size / sizeof(*rela); + + for (j = 0; j < size; ++j) { + Elf_Sym *sym; + + if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) + continue; + + sym = syms + ELF_MIPS_R_SYM(rela[j]); + if (!is_init && sym->st_shndx != SHN_UNDEF) + continue; + + ret += 4 * sizeof(int); + } + } + } + + return ret; +} + +#ifndef MODULES_VADDR +static void *alloc_phys(unsigned long size) +{ + unsigned order; + struct page *page; + struct page *p; + + size = PAGE_ALIGN(size); + order = get_order(size); + + page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | + __GFP_THISNODE, order); + if (!page) + return NULL; + + split_page(page, order); + + /* mark all pages except for the last one */ + for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) + set_bit(PG_owner_priv_1, &p->flags); + + for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) + __free_page(p); + + return page_address(page); +} + +static void free_phys(void *ptr) +{ + struct page *page; + bool free; + + page = virt_to_page(ptr); + do { + free = test_and_clear_bit(PG_owner_priv_1, &page->flags); + __free_page(page); + page++; + } while (free); +} + +void *arch_execmem_alloc(enum execmem_type type, + size_t size) +{ + void *ptr; + + ptr = alloc_phys(size); + + /* If we failed to allocate physically contiguous memory, + * fall back to regular vmalloc. The module loader code will + * create jump tables to handle long jumps */ + if (!ptr) + return vmalloc(size); + + return ptr; +} +#endif + +static inline bool is_phys_addr(void *ptr) +{ +#ifdef CONFIG_64BIT + return (KSEGX((unsigned long)ptr) == CKSEG0); +#else + return (KSEGX(ptr) == KSEG0); +#endif +} + +#ifndef MODULES_VADDR +/* Free memory returned from module_alloc */ +void arch_execmem_free(void *ptr) +{ + if (is_phys_addr(ptr)) + free_phys(ptr); + else + vfree(ptr); +} +#endif + +static void *__module_alloc(int size, bool phys) +{ + void *ptr; + + if (phys) + ptr = kmalloc(size, GFP_KERNEL); + else + ptr = vmalloc(size); + return ptr; +} + +static void __module_free(void *ptr) +{ + if (is_phys_addr(ptr)) + kfree(ptr); + else + vfree(ptr); +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + unsigned int symindex = 0; + unsigned int core_size, init_size; + int i; + + mod->arch.phys_plt_offset = 0; + mod->arch.virt_plt_offset = 0; + mod->arch.phys_plt_tbl = NULL; + mod->arch.virt_plt_tbl = NULL; + + if (IS_ENABLED(CONFIG_64BIT)) + return 0; + + for (i = 1; i < hdr->e_shnum; i++) + if (sechdrs[i].sh_type == SHT_SYMTAB) + symindex = i; + + core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); + init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); + + if ((core_size + init_size) == 0) + return 0; + + mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); + if (!mod->arch.phys_plt_tbl) + return -ENOMEM; + + mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); + if (!mod->arch.virt_plt_tbl) { + __module_free(mod->arch.phys_plt_tbl); + mod->arch.phys_plt_tbl = NULL; + return -ENOMEM; + } + + return 0; +} + static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v) { *location = base + v; } +static Elf_Addr add_plt_entry_to(unsigned *plt_offset, + void *start, Elf_Addr v) +{ + unsigned *tramp = start + *plt_offset; + *plt_offset += 4 * sizeof(int); + + /* adjust carry for addiu */ + if (v & 0x00008000) + v += 0x10000; + + tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ + tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ + tramp[2] = 0x03200008; /* jr t9 */ + tramp[3] = 0x00000000; /* nop */ + + return (Elf_Addr) tramp; +} + +static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) +{ + if (is_phys_addr(location)) + return add_plt_entry_to(&me->arch.phys_plt_offset, + me->arch.phys_plt_tbl, v); + else + return add_plt_entry_to(&me->arch.virt_plt_offset, + me->arch.virt_plt_tbl, v); + +} + static int apply_r_mips_26(struct module *me, u32 *location, u32 base, Elf_Addr v) { + u32 ofs = base & 0x03ffffff; + if (v % 4) { pr_err("module %s: dangerous R_MIPS_26 relocation\n", me->name); @@ -45,13 +287,17 @@ static int apply_r_mips_26(struct module *me, u32 *location, u32 base, } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - pr_err("module %s: relocation overflow\n", - me->name); - return -ENOEXEC; + v = add_plt_entry(me, location, v + (ofs << 2)); + if (!v) { + pr_err("module %s: relocation overflow\n", + me->name); + return -ENOEXEC; + } + ofs = 0; } *location = (*location & ~0x03ffffff) | - ((base + (v >> 2)) & 0x03ffffff); + ((ofs + (v >> 2)) & 0x03ffffff); return 0; } @@ -431,9 +677,36 @@ int module_finalize(const Elf_Ehdr *hdr, list_add(&me->arch.dbe_list, &dbe_list); spin_unlock_irq(&dbe_lock); } + + /* Get rid of the fixup trampoline if we're running the module + * from physically mapped address space */ + if (me->arch.phys_plt_offset == 0) { + __module_free(me->arch.phys_plt_tbl); + me->arch.phys_plt_tbl = NULL; + } + if (me->arch.virt_plt_offset == 0) { + __module_free(me->arch.virt_plt_tbl); + me->arch.virt_plt_tbl = NULL; + } + return 0; } +void module_arch_freeing_init(struct module *mod) +{ + if (mod->state == MODULE_STATE_LIVE) + return; + + if (mod->arch.phys_plt_tbl) { + __module_free(mod->arch.phys_plt_tbl); + mod->arch.phys_plt_tbl = NULL; + } + if (mod->arch.virt_plt_tbl) { + __module_free(mod->arch.virt_plt_tbl); + mod->arch.virt_plt_tbl = NULL; + } +} + void module_arch_cleanup(struct module *mod) { spin_lock_irq(&dbe_lock); -- 2.51.0 From 016d53c3a76a0abd9c3a5f88b080ee9ebeee8a3e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 7 Apr 2021 22:45:54 +0100 Subject: [PATCH 348/517] mtd: blktrans: call add disks after mtd device Calling device_add_disk while holding mtd_table_mutex leads to deadlock in case part_bits!=0 as block partition parsers will try to open the newly created disks, trying to acquire mutex once again. Move device_add_disk to additional function called after add partitions of an MTD device have been added and locks have been released. Signed-off-by: Daniel Golle --- drivers/mtd/mtd_blkdevs.c | 40 ++++++++++++++++++++++++++---------- drivers/mtd/mtdcore.c | 3 +++ include/linux/mtd/blktrans.h | 1 + 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 47ead84407cd..f27a807dc886 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -379,19 +379,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) if (new->readonly) set_disk_ro(gd, 1); - ret = device_add_disk(&new->mtd->dev, gd, NULL); - if (ret) - goto out_cleanup_disk; - - if (new->disk_attributes) { - ret = sysfs_create_group(&disk_to_dev(gd)->kobj, - new->disk_attributes); - WARN_ON(ret); - } return 0; -out_cleanup_disk: - put_disk(new->disk); out_free_tag_set: blk_mq_free_tag_set(new->tag_set); out_kfree_tag_set: @@ -401,6 +390,35 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) return ret; } +void register_mtd_blktrans_devs(void) +{ + struct mtd_blktrans_ops *tr; + struct mtd_blktrans_dev *dev, *next; + int ret; + + list_for_each_entry(tr, &blktrans_majors, list) { + list_for_each_entry_safe(dev, next, &tr->devs, list) { + if (disk_live(dev->disk)) + continue; + + ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL); + if (ret) + goto out_cleanup_disk; + + if (dev->disk_attributes) { + ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj, + dev->disk_attributes); + WARN_ON(ret); + } + } + } + + return; + +out_cleanup_disk: + put_disk(dev->disk); +} + int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) { unsigned long flags; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6b98d581ceeb..c34e31a915f2 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -34,6 +34,7 @@ #include #include +#include #include "mtdcore.h" @@ -1132,6 +1133,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, register_reboot_notifier(&mtd->reboot_notifier); } + register_mtd_blktrans_devs(); + out: if (ret) { nvmem_unregister(mtd->otp_user_nvmem); diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index 6e471436bba5..70f246a3dceb 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h @@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); +extern void register_mtd_blktrans_devs(void); /** * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver -- 2.51.0 From 2be9bff250a6f8fe489c2b517985524c3ea64c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 7 Nov 2022 23:48:24 +0100 Subject: [PATCH 349/517] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows setting ROOT_DEV to MTD partition named "rootfs". Signed-off-by: Rafał Miłecki --- drivers/mtd/mtdcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c34e31a915f2..9bf60ad26daf 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -803,7 +803,8 @@ int add_mtd_device(struct mtd_info *mtd) mutex_unlock(&mtd_table_mutex); - if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) { + if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs") || + (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) { if (IS_BUILTIN(CONFIG_MTD)) { pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); -- 2.51.0 From eddbc1471956f3bd6a0090488fb8549dca8d962c Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 11 Oct 2021 00:53:14 +0200 Subject: [PATCH 350/517] drivers: mtd: parsers: add nvmem support to cmdlinepart Assuming cmdlinepart is only one level deep partition scheme and that static partition are also defined in DTS, we can assign an of_node for partition declared from bootargs. cmdlinepart have priority than fiexed-partition parser so in this specific case the parser doesn't assign an of_node. Fix this by searching a defined of_node using a similar fixed_partition parser and if a partition is found with the same label, check that it has the same offset and size and return the DT of_node to correctly use NVMEM cells. Signed-off-by: Ansuel Smith --- drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/mtd/parsers/cmdlinepart.c b/drivers/mtd/parsers/cmdlinepart.c index 504e5fa2b45b..fe8354cd6515 100644 --- a/drivers/mtd/parsers/cmdlinepart.c +++ b/drivers/mtd/parsers/cmdlinepart.c @@ -43,6 +43,7 @@ #include #include #include +#include /* special size referring to all the remaining space in a partition */ #define SIZE_REMAINING ULLONG_MAX @@ -315,6 +316,68 @@ static int mtdpart_setup_real(char *s) return 0; } +static int search_fixed_partition(struct mtd_info *master, + struct mtd_partition *target_part, + struct mtd_partition *fixed_part) +{ + struct device_node *mtd_node; + struct device_node *ofpart_node; + struct device_node *pp; + struct mtd_partition part; + const char *partname; + + mtd_node = mtd_get_of_node(master); + if (!mtd_node) + return -EINVAL; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); + + for_each_child_of_node(ofpart_node, pp) { + const __be32 *reg; + int len; + int a_cells, s_cells; + + reg = of_get_property(pp, "reg", &len); + if (!reg) { + pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", + master->name, pp, + mtd_node); + continue; + } + + a_cells = of_n_addr_cells(pp); + s_cells = of_n_size_cells(pp); + if (len / 4 != a_cells + s_cells) { + pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", + master->name, pp, + mtd_node); + continue; + } + + part.offset = of_read_number(reg, a_cells); + part.size = of_read_number(reg + a_cells, s_cells); + part.of_node = pp; + + partname = of_get_property(pp, "label", &len); + if (!partname) + partname = of_get_property(pp, "name", &len); + part.name = partname; + + if (!strncmp(target_part->name, part.name, len)) { + if (part.offset != target_part->offset) + return -EINVAL; + + if (part.size != target_part->size) + return -EINVAL; + + memcpy(fixed_part, &part, sizeof(struct mtd_partition)); + return 0; + } + } + + return -EINVAL; +} + /* * Main function to be called from the MTD mapping driver/device to * obtain the partitioning information. At this point the command line @@ -330,6 +393,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, int i, err; struct cmdline_mtd_partition *part; const char *mtd_id = master->name; + struct mtd_partition fixed_part; /* parse command line */ if (!cmdline_parsed) { @@ -374,6 +438,13 @@ static int parse_cmdline_partitions(struct mtd_info *master, sizeof(*part->parts) * (part->num_parts - i)); i--; } + + err = search_fixed_partition(master, &part->parts[i], &fixed_part); + if (!err) { + part->parts[i].of_node = fixed_part.of_node; + pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.", + part->parts[i].name); + } } *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, -- 2.51.0 From b9b5fcad748eca6c1a4c8edcb34e2553f75f21aa Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:41:44 +0200 Subject: [PATCH 351/517] mtd/nand: add MediaTek NAND bad block managment table --- drivers/mtd/nand/Kconfig | 4 ++++ drivers/mtd/nand/Makefile | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 5b0c2c95f10c..e775c64e355d 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH ECC codes. They are used with NAND devices requiring more than 1 bit of error correction. +config MTD_NAND_MTK_BMT + bool "Support MediaTek NAND Bad-block Management Table" + default n + config MTD_NAND_ECC_MXIC bool "Macronix external hardware ECC engine" depends on HAS_IOMEM diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index db516a45f0c5..2998d84bb5d0 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -3,6 +3,7 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o ifeq ($(CONFIG_SPI_QPIC_SNAND),y) obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o else -- 2.51.0 From fe7abda0ec355ddcf7184b0245f70dbfcb25d1aa Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 3 Nov 2025 15:50:20 +0100 Subject: [PATCH 352/517] LEGACY block: partitions: populate fwnode Assign matching firmware nodes to block partitions in order to allow them to be referenced e.g. as NVMEM providers. REMOVE THIS PATCH ONCE ALL TARGETS ARE USING LINUX 6.12 AND ALL BOARDS HAVE MIGRATED TO UPSTREAM DT BINDINGS. Signed-off-by: Daniel Golle --- block/partitions/core.c | 73 ++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/block.c | 4 +++ drivers/mmc/core/bus.c | 2 ++ 3 files changed, 79 insertions(+) diff --git a/block/partitions/core.c b/block/partitions/core.c index f5b5360dd518..29c9330b9050 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -11,6 +11,8 @@ #include #include #include +#include + #include "check.h" static int (*const check_part[])(struct parsed_partitions *) = { @@ -285,6 +287,74 @@ static ssize_t whole_disk_show(struct device *dev, } static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); +static bool part_meta_match(const char *attr, const char *member, size_t length) +{ + /* check if length of attr exceeds specified maximum length */ + if (strnlen(attr, length) == length) + return false; + + /* return true if strings match */ + return !strncmp(attr, member, length); +} + +static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev) +{ + struct fwnode_handle *fw_parts, *fw_part; + struct device *ddev = disk_to_dev(bdev->bd_disk); + const char *partname, *uuid; + u32 partno; + bool got_uuid, got_partname, got_partno; + + fw_parts = device_get_named_child_node(ddev, "partitions"); + if (!fw_parts) + return NULL; + + fwnode_for_each_child_node(fw_parts, fw_part) { + got_uuid = false; + got_partname = false; + got_partno = false; + /* + * In case 'uuid' is defined in the partitions firmware node + * require partition meta info being present and the specified + * uuid to match. + */ + got_uuid = !fwnode_property_read_string(fw_part, "uuid", &uuid); + if (got_uuid && (!bdev->bd_meta_info || + !part_meta_match(uuid, bdev->bd_meta_info->uuid, + PARTITION_META_INFO_UUIDLTH))) + continue; + + /* + * In case 'partname' is defined in the partitions firmware node + * require partition meta info being present and the specified + * volname to match. + */ + got_partname = !fwnode_property_read_string(fw_part, "partname", + &partname); + if (got_partname && (!bdev->bd_meta_info || + !part_meta_match(partname, + bdev->bd_meta_info->volname, + PARTITION_META_INFO_VOLNAMELTH))) + continue; + + /* + * In case 'partno' is defined in the partitions firmware node + * the specified partno needs to match. + */ + got_partno = !fwnode_property_read_u32(fw_part, "partno", &partno); + if (got_partno && bdev_partno(bdev) != partno) + continue; + + /* Skip if no matching criteria is present in firmware node */ + if (!got_uuid && !got_partname && !got_partno) + continue; + + return fw_part; + } + + return NULL; +} + /* * Must be called either with open_mutex held, before a disk can be opened or * after all disk users are gone. @@ -361,6 +431,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, goto out_put; } + if (!pdev->fwnode && !pdev->of_node) + device_set_node(pdev, find_partition_fwnode(bdev)); + /* delay uevent until 'holders' subdir is created */ dev_set_uevent_suppress(pdev, 1); err = device_add(pdev); diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index f56eb44ec450..3c9443c7ac49 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2679,6 +2679,10 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, if (area_type == MMC_BLK_DATA_AREA_MAIN) dev_set_drvdata(&card->dev, md); disk_fwnode = mmc_blk_get_partitions_node(parent, subname); + if (!disk_fwnode) + disk_fwnode = device_get_named_child_node(subname ? md->parent->parent : + md->parent, + subname ? subname : "block"); ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups, disk_fwnode); if (ret) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 4f3a26676ccb..359640be0592 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -368,6 +368,8 @@ int mmc_add_card(struct mmc_card *card) mmc_add_card_debugfs(card); card->dev.of_node = mmc_of_find_child_device(card->host, 0); + if (card->dev.of_node && !card->dev.fwnode) + card->dev.fwnode = &card->dev.of_node->fwnode; device_enable_async_suspend(&card->dev); -- 2.51.0 From 70fcd329f0105febc763f81d177058026db6c5f3 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 23 Apr 2024 12:35:21 +0200 Subject: [PATCH 353/517] net: enable fraglist GRO by default This can significantly improve performance for packet forwarding/bridging Signed-off-by: Felix Fietkau --- include/linux/netdev_features.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index e2e3dd919068..8b9e912f6db6 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -235,10 +235,10 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start) #define NETIF_F_UPPER_DISABLES NETIF_F_LRO /* changeable features with no special hardware requirements */ -#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO) +#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST) /* Changeable features with no special hardware requirements that defaults to off. */ -#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD) +#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD) #define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \ NETIF_F_HW_VLAN_CTAG_RX | \ -- 2.51.0 From 9bc103b739dc6e694e05bcdc86b0583e94b5e140 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 3 Jan 2025 19:29:00 +0100 Subject: [PATCH 354/517] net: page_pool: try to free deferred skbs while waiting for pool release The NAPI defer list can accumulate no longer used skbs, which can be reused during alloc. If this happens on a CPU that otherwise does not do any rx softirq processing, skbs can be held indefinitely, causing warnings on releasing page pools. Deal with this by scheduling rx softirq on all CPUs. Patch by Lorenzo Bianconi Signed-off-by: Felix Fietkau --- net/core/page_pool.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 6a7d740b396f..c3a4ab60b6de 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -1153,8 +1153,9 @@ static void page_pool_release_retry(struct work_struct *wq) { struct delayed_work *dwq = to_delayed_work(wq); struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw); + unsigned long flags; void *netdev; - int inflight; + int cpu, inflight; inflight = page_pool_release(pool); /* In rare cases, a driver bug may cause inflight to go negative. @@ -1166,6 +1167,21 @@ static void page_pool_release_retry(struct work_struct *wq) if (inflight <= 0) return; + /* Run NET_RX_SOFTIRQ in order to free pending skbs in softnet_data + * defer_list that can stay in the list until we have enough queued + * traffic. + */ + local_irq_save(flags); + for_each_online_cpu(cpu) { + struct softnet_data *sd = &per_cpu(softnet_data, cpu); + + if (cpu == raw_smp_processor_id()) + raise_softirq_irqoff(NET_RX_SOFTIRQ); + else if (!cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) + smp_call_function_single_async(cpu, &sd->defer_csd); + } + local_irq_restore(flags); + /* Periodic warning for page pools the user can't see */ netdev = READ_ONCE(pool->slow.netdev); if (time_after_eq(jiffies, pool->defer_warn) && -- 2.51.0 From 07c08919265a04b1535d18e75a8de2fc6644e6b9 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Sat, 23 Mar 2019 09:29:49 +0000 Subject: [PATCH 355/517] netfilter: connmark: introduce set-dscpmark set-dscpmark is a method of storing the DSCP of an ip packet into conntrack mark. In combination with a suitable tc filter action (act_ctinfo) DSCP values are able to be stored in the mark on egress and restored on ingress across links that otherwise alter or bleach DSCP. This is useful for qdiscs such as CAKE which are able to shape according to policies based on DSCP. Ingress classification is traditionally a challenging task since iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT lookups, hence are unable to see internal IPv4 addresses as used on the typical home masquerading gateway. x_tables CONNMARK set-dscpmark target solves the problem of storing the DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc action to restore. The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a 32bit 'statemask'. The dscp mask must be 6 contiguous bits and represents the area where the DSCP will be stored in the connmark. The state mask is a minimum 1 bit length mask that must not overlap with the dscpmask. It represents a flag which is set when the DSCP has been stored in the conntrack mark. This is useful to implement a 'one shot' iptables based classification where the 'complicated' iptables rules are only run once to classify the connection on initial (egress) packet and subsequent packets are all marked/restored with the same DSCP. A state mask of zero disables the setting of a status bit/s. example syntax with a suitably modified iptables user space application: iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000 Would store the DSCP in the top 6 bits of the 32bit mark field, and use the LSB of the top byte as the 'DSCP has been stored' marker. |----0xFC----conntrack mark----000000---| | Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| | DSCP | unused | flag |unused | |-----------------------0x01---000000---| ^ ^ | | ---| Conditional flag | set this when dscp |-ip diffserv-| stored in mark | 6 bits | |-------------| an identically configured tc action to restore looks like: tc filter show dev eth0 ingress filter parent ffff: protocol all pref 10 u32 chain 0 filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw match 00000000/00000000 at 0 action order 1: ctinfo zone 0 pipe index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000 action order 2: mirred (Egress Redirect to device ifb4eth0) stolen index 1 ref 1 bind 1 |----0xFC----conntrack mark----000000---| | Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| | DSCP | unused | flag |unused | |-----------------------0x01---000000---| | | | | ---| Conditional flag v only restore if set |-ip diffserv-| | 6 bits | |-------------| Signed-off-by: Kevin Darbyshire-Bryant --- include/uapi/linux/netfilter/xt_connmark.h | 10 ++++ net/netfilter/xt_connmark.c | 67 ++++++++++++++++++---- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_connmark.h b/include/uapi/linux/netfilter/xt_connmark.h index 41b578ccd03b..1ef51bca5cc7 100644 --- a/include/uapi/linux/netfilter/xt_connmark.h +++ b/include/uapi/linux/netfilter/xt_connmark.h @@ -14,6 +14,11 @@ enum { XT_CONNMARK_RESTORE }; +enum { + XT_CONNMARK_VALUE = (1 << 0), + XT_CONNMARK_DSCP = (1 << 1) +}; + enum { D_SHIFT_LEFT = 0, D_SHIFT_RIGHT, @@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 { __u8 shift_dir, shift_bits, mode; }; +struct xt_connmark_tginfo3 { + __u32 ctmark, ctmask, nfmask; + __u8 shift_dir, shift_bits, mode, func; +}; + struct xt_connmark_mtinfo1 { __u32 mark, mask; __u8 invert; diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 4277084de2e7..09e02d052ec7 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark"); MODULE_ALIAS("ip6t_connmark"); static unsigned int -connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) +connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info) { enum ip_conntrack_info ctinfo; u_int32_t new_targetmark; struct nf_conn *ct; u_int32_t newmark; - u_int32_t oldmark; + u_int8_t dscp; ct = nf_ct_get(skb, &ctinfo); if (ct == NULL) @@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) switch (info->mode) { case XT_CONNMARK_SET: - oldmark = READ_ONCE(ct->mark); - newmark = (oldmark & ~info->ctmask) ^ info->ctmark; - if (info->shift_dir == D_SHIFT_RIGHT) - newmark >>= info->shift_bits; - else - newmark <<= info->shift_bits; + newmark = READ_ONCE(ct->mark); + if (info->func & XT_CONNMARK_VALUE) { + newmark = (newmark & ~info->ctmask) ^ info->ctmark; + if (info->shift_dir == D_SHIFT_RIGHT) + newmark >>= info->shift_bits; + else + newmark <<= info->shift_bits; + } else if (info->func & XT_CONNMARK_DSCP) { + if (skb->protocol == htons(ETH_P_IP)) + dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2; + else if (skb->protocol == htons(ETH_P_IPV6)) + dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; + else /* protocol doesn't have diffserv */ + break; + newmark = (newmark & ~info->ctmark) | + (info->ctmask | (dscp << info->shift_bits)); + } if (READ_ONCE(ct->mark) != newmark) { WRITE_ONCE(ct->mark, newmark); nf_conntrack_event_cache(IPCT_MARK, ct); @@ -83,20 +94,36 @@ static unsigned int connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_connmark_tginfo1 *info = par->targinfo; - const struct xt_connmark_tginfo2 info2 = { + const struct xt_connmark_tginfo3 info3 = { .ctmark = info->ctmark, .ctmask = info->ctmask, .nfmask = info->nfmask, .mode = info->mode, + .func = XT_CONNMARK_VALUE }; - return connmark_tg_shift(skb, &info2); + return connmark_tg_shift(skb, &info3); } static unsigned int connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_connmark_tginfo2 *info = par->targinfo; + const struct xt_connmark_tginfo3 info3 = { + .ctmark = info->ctmark, + .ctmask = info->ctmask, + .nfmask = info->nfmask, + .mode = info->mode, + .func = XT_CONNMARK_VALUE + }; + + return connmark_tg_shift(skb, &info3); +} + +static unsigned int +connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_connmark_tginfo3 *info = par->targinfo; return connmark_tg_shift(skb, info); } @@ -168,6 +195,16 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { .destroy = connmark_tg_destroy, .me = THIS_MODULE, }, + { + .name = "CONNMARK", + .revision = 3, + .family = NFPROTO_IPV4, + .checkentry = connmark_tg_check, + .target = connmark_tg_v3, + .targetsize = sizeof(struct xt_connmark_tginfo3), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + }, #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) { .name = "CONNMARK", @@ -189,6 +226,16 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { .destroy = connmark_tg_destroy, .me = THIS_MODULE, }, + { + .name = "CONNMARK", + .revision = 3, + .family = NFPROTO_IPV6, + .checkentry = connmark_tg_check, + .target = connmark_tg_v3, + .targetsize = sizeof(struct xt_connmark_tginfo3), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, + }, #endif }; -- 2.51.0 From fd138131dfe7392f9794d929221cc4083f3661ed Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 20 Feb 2018 15:56:02 +0100 Subject: [PATCH 356/517] netfilter: add xt_FLOWOFFLOAD target Signed-off-by: Felix Fietkau --- include/net/netfilter/nf_flow_table.h | 5 + include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h | 17 + net/netfilter/Kconfig | 10 +- net/netfilter/Makefile | 1 + net/netfilter/nf_flow_table_core.c | 5 +- net/netfilter/xt_FLOWOFFLOAD.c | 703 ++++++++++++++++++ 6 files changed, 737 insertions(+), 4 deletions(-) create mode 100644 include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h create mode 100644 net/netfilter/xt_FLOWOFFLOAD.c diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index 1a6fca013165..2709725ee8cc 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -294,6 +294,11 @@ void nf_flow_table_free(struct nf_flowtable *flow_table); void flow_offload_teardown(struct flow_offload *flow); +int nf_flow_table_iterate(struct nf_flowtable *flow_table, + void (*iter)(struct nf_flowtable *flowtable, + struct flow_offload *flow, void *data), + void *data); + void nf_flow_snat_port(const struct flow_offload *flow, struct sk_buff *skb, unsigned int thoff, u8 protocol, enum flow_offload_tuple_dir dir); diff --git a/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h new file mode 100644 index 000000000000..5841bbe0e3db --- /dev/null +++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _XT_FLOWOFFLOAD_H +#define _XT_FLOWOFFLOAD_H + +#include + +enum { + XT_FLOWOFFLOAD_HW = 1 << 0, + + XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW +}; + +struct xt_flowoffload_target_info { + __u32 flags; +}; + +#endif /* _XT_FLOWOFFLOAD_H */ diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 944a47d0e2fd..e10e3b879121 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -729,7 +729,6 @@ config NF_FLOW_TABLE tristate "Netfilter flow table module" depends on NETFILTER_INGRESS depends on NF_CONNTRACK - depends on NF_TABLES help This option adds the flow table core infrastructure. @@ -1025,6 +1024,15 @@ config NETFILTER_XT_TARGET_NOTRACK depends on NETFILTER_ADVANCED select NETFILTER_XT_TARGET_CT +config NETFILTER_XT_TARGET_FLOWOFFLOAD + tristate '"FLOWOFFLOAD" target support' + depends on NF_FLOW_TABLE + depends on NETFILTER_INGRESS + help + This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload + module to speed up processing of packets by bypassing the usual + netfilter chains + config NETFILTER_XT_TARGET_RATEEST tristate '"RATEEST" target support' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index f0aa4d7ef499..e9d11858a49b 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -168,6 +168,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o +obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 54881f0e878a..f90303256229 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -373,8 +372,7 @@ flow_offload_lookup(struct nf_flowtable *flow_table, } EXPORT_SYMBOL_GPL(flow_offload_lookup); -static int -nf_flow_table_iterate(struct nf_flowtable *flow_table, +int nf_flow_table_iterate(struct nf_flowtable *flow_table, void (*iter)(struct nf_flowtable *flowtable, struct flow_offload *flow, void *data), void *data) @@ -435,6 +433,7 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table, nf_flow_offload_stats(flow_table, flow); } } +EXPORT_SYMBOL_GPL(nf_flow_table_iterate); void nf_flow_table_gc_run(struct nf_flowtable *flow_table) { diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c new file mode 100644 index 000000000000..08e0b945b4b0 --- /dev/null +++ b/net/netfilter/xt_FLOWOFFLOAD.c @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2018-2021 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xt_flowoffload_hook { + struct hlist_node list; + struct nf_hook_ops ops; + struct net *net; + bool registered; + bool used; +}; + +struct xt_flowoffload_table { + struct nf_flowtable ft; + struct hlist_head hooks; + struct delayed_work work; +}; + +struct nf_forward_info { + const struct net_device *indev; + const struct net_device *outdev; + const struct net_device *hw_outdev; + struct id { + __u16 id; + __be16 proto; + } encap[NF_FLOW_TABLE_ENCAP_MAX]; + u8 num_encaps; + u8 ingress_vlans; + u8 h_source[ETH_ALEN]; + u8 h_dest[ETH_ALEN]; + enum flow_offload_xmit_type xmit_type; +}; + +static DEFINE_SPINLOCK(hooks_lock); + +struct xt_flowoffload_table flowtable[2]; + +static unsigned int +xt_flowoffload_net_hook(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct vlan_ethhdr *veth; + __be16 proto; + + switch (skb->protocol) { + case htons(ETH_P_8021Q): + veth = (struct vlan_ethhdr *)skb_mac_header(skb); + proto = veth->h_vlan_encapsulated_proto; + break; + case htons(ETH_P_PPP_SES): + if (!nf_flow_pppoe_proto(skb, &proto)) + return NF_ACCEPT; + break; + default: + proto = skb->protocol; + break; + } + + switch (proto) { + case htons(ETH_P_IP): + return nf_flow_offload_ip_hook(priv, skb, state); + case htons(ETH_P_IPV6): + return nf_flow_offload_ipv6_hook(priv, skb, state); + } + + return NF_ACCEPT; +} + +static int +xt_flowoffload_create_hook(struct xt_flowoffload_table *table, + struct net_device *dev) +{ + struct xt_flowoffload_hook *hook; + struct nf_hook_ops *ops; + + hook = kzalloc(sizeof(*hook), GFP_ATOMIC); + if (!hook) + return -ENOMEM; + + ops = &hook->ops; + ops->pf = NFPROTO_NETDEV; + ops->hooknum = NF_NETDEV_INGRESS; + ops->priority = 10; + ops->priv = &table->ft; + ops->hook = xt_flowoffload_net_hook; + ops->dev = dev; + + hlist_add_head(&hook->list, &table->hooks); + mod_delayed_work(system_power_efficient_wq, &table->work, 0); + + return 0; +} + +static struct xt_flowoffload_hook * +flow_offload_lookup_hook(struct xt_flowoffload_table *table, + struct net_device *dev) +{ + struct xt_flowoffload_hook *hook; + + hlist_for_each_entry(hook, &table->hooks, list) { + if (hook->ops.dev == dev) + return hook; + } + + return NULL; +} + +static void +xt_flowoffload_check_device(struct xt_flowoffload_table *table, + struct net_device *dev) +{ + struct xt_flowoffload_hook *hook; + + if (!dev) + return; + + spin_lock_bh(&hooks_lock); + hook = flow_offload_lookup_hook(table, dev); + if (hook) + hook->used = true; + else + xt_flowoffload_create_hook(table, dev); + spin_unlock_bh(&hooks_lock); +} + +static void +xt_flowoffload_register_hooks(struct xt_flowoffload_table *table) +{ + struct xt_flowoffload_hook *hook; + +restart: + hlist_for_each_entry(hook, &table->hooks, list) { + if (hook->registered) + continue; + + hook->registered = true; + hook->net = dev_net(hook->ops.dev); + spin_unlock_bh(&hooks_lock); + nf_register_net_hook(hook->net, &hook->ops); + if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) + table->ft.type->setup(&table->ft, hook->ops.dev, + FLOW_BLOCK_BIND); + spin_lock_bh(&hooks_lock); + goto restart; + } + +} + +static bool +xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table) +{ + struct xt_flowoffload_hook *hook; + bool active = false; + +restart: + spin_lock_bh(&hooks_lock); + hlist_for_each_entry(hook, &table->hooks, list) { + if (hook->used || !hook->registered) { + active = true; + continue; + } + + hlist_del(&hook->list); + spin_unlock_bh(&hooks_lock); + if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) + table->ft.type->setup(&table->ft, hook->ops.dev, + FLOW_BLOCK_UNBIND); + nf_unregister_net_hook(hook->net, &hook->ops); + kfree(hook); + goto restart; + } + spin_unlock_bh(&hooks_lock); + + return active; +} + +static void +xt_flowoffload_check_hook(struct nf_flowtable *flowtable, + struct flow_offload *flow, void *data) +{ + struct xt_flowoffload_table *table; + struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple; + struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple; + struct xt_flowoffload_hook *hook; + + table = container_of(flowtable, struct xt_flowoffload_table, ft); + + spin_lock_bh(&hooks_lock); + hlist_for_each_entry(hook, &table->hooks, list) { + if (hook->ops.dev->ifindex != tuple0->iifidx && + hook->ops.dev->ifindex != tuple1->iifidx) + continue; + + hook->used = true; + } + spin_unlock_bh(&hooks_lock); +} + +static void +xt_flowoffload_hook_work(struct work_struct *work) +{ + struct xt_flowoffload_table *table; + struct xt_flowoffload_hook *hook; + int err; + + table = container_of(work, struct xt_flowoffload_table, work.work); + + spin_lock_bh(&hooks_lock); + xt_flowoffload_register_hooks(table); + hlist_for_each_entry(hook, &table->hooks, list) + hook->used = false; + spin_unlock_bh(&hooks_lock); + + err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook, + NULL); + if (err && err != -EAGAIN) + goto out; + + if (!xt_flowoffload_cleanup_hooks(table)) + return; + +out: + queue_delayed_work(system_power_efficient_wq, &table->work, HZ); +} + +static bool +xt_flowoffload_skip(struct sk_buff *skb, int family) +{ + if (skb_sec_path(skb)) + return true; + + if (family == NFPROTO_IPV4) { + const struct ip_options *opt = &(IPCB(skb)->opt); + + if (unlikely(opt->optlen)) + return true; + } + + return false; +} + +static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst) +{ + if (dst_xfrm(dst)) + return FLOW_OFFLOAD_XMIT_XFRM; + + return FLOW_OFFLOAD_XMIT_NEIGH; +} + +static void nf_default_forward_path(struct nf_flow_route *route, + struct dst_entry *dst_cache, + enum ip_conntrack_dir dir, + struct net_device **dev) +{ + dev[!dir] = dst_cache->dev; + route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex; + route->tuple[dir].dst = dst_cache; + route->tuple[dir].xmit_type = nf_xmit_type(dst_cache); +} + +static bool nf_is_valid_ether_device(const struct net_device *dev) +{ + if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || + dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) + return false; + + return true; +} + +static void nf_dev_path_info(const struct net_device_path_stack *stack, + struct nf_forward_info *info, + unsigned char *ha) +{ + const struct net_device_path *path; + int i; + + memcpy(info->h_dest, ha, ETH_ALEN); + + for (i = 0; i < stack->num_paths; i++) { + path = &stack->path[i]; + switch (path->type) { + case DEV_PATH_ETHERNET: + case DEV_PATH_DSA: + case DEV_PATH_VLAN: + case DEV_PATH_PPPOE: + info->indev = path->dev; + if (is_zero_ether_addr(info->h_source)) + memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); + + if (path->type == DEV_PATH_ETHERNET) + break; + if (path->type == DEV_PATH_DSA) { + i = stack->num_paths; + break; + } + + /* DEV_PATH_VLAN and DEV_PATH_PPPOE */ + if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { + info->indev = NULL; + break; + } + if (!info->outdev) + info->outdev = path->dev; + info->encap[info->num_encaps].id = path->encap.id; + info->encap[info->num_encaps].proto = path->encap.proto; + info->num_encaps++; + if (path->type == DEV_PATH_PPPOE) + memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN); + break; + case DEV_PATH_BRIDGE: + if (is_zero_ether_addr(info->h_source)) + memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); + + switch (path->bridge.vlan_mode) { + case DEV_PATH_BR_VLAN_UNTAG_HW: + info->ingress_vlans |= BIT(info->num_encaps - 1); + break; + case DEV_PATH_BR_VLAN_TAG: + info->encap[info->num_encaps].id = path->bridge.vlan_id; + info->encap[info->num_encaps].proto = path->bridge.vlan_proto; + info->num_encaps++; + break; + case DEV_PATH_BR_VLAN_UNTAG: + info->num_encaps--; + break; + case DEV_PATH_BR_VLAN_KEEP: + break; + } + break; + default: + info->indev = NULL; + break; + } + } + if (!info->outdev) + info->outdev = info->indev; + + info->hw_outdev = info->indev; + + if (nf_is_valid_ether_device(info->indev)) + info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; +} + +static int nf_dev_fill_forward_path(const struct nf_flow_route *route, + const struct dst_entry *dst_cache, + const struct nf_conn *ct, + enum ip_conntrack_dir dir, u8 *ha, + struct net_device_path_stack *stack) +{ + const void *daddr = &ct->tuplehash[!dir].tuple.src.u3; + struct net_device *dev = dst_cache->dev; + struct neighbour *n; + u8 nud_state; + + if (!nf_is_valid_ether_device(dev)) + goto out; + + n = dst_neigh_lookup(dst_cache, daddr); + if (!n) + return -1; + + read_lock_bh(&n->lock); + nud_state = n->nud_state; + ether_addr_copy(ha, n->ha); + read_unlock_bh(&n->lock); + neigh_release(n); + + if (!(nud_state & NUD_VALID)) + return -1; + +out: + return dev_fill_forward_path(dev, ha, stack); +} + +static void nf_dev_forward_path(struct nf_flow_route *route, + const struct nf_conn *ct, + enum ip_conntrack_dir dir, + struct net_device **devs) +{ + const struct dst_entry *dst = route->tuple[dir].dst; + struct net_device_path_stack stack; + struct nf_forward_info info = {}; + unsigned char ha[ETH_ALEN]; + int i; + + if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) + nf_dev_path_info(&stack, &info, ha); + + devs[!dir] = (struct net_device *)info.indev; + if (!info.indev) + return; + + route->tuple[!dir].in.ifindex = info.indev->ifindex; + for (i = 0; i < info.num_encaps; i++) { + route->tuple[!dir].in.encap[i].id = info.encap[i].id; + route->tuple[!dir].in.encap[i].proto = info.encap[i].proto; + } + route->tuple[!dir].in.num_encaps = info.num_encaps; + route->tuple[!dir].in.ingress_vlans = info.ingress_vlans; + + if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { + memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); + memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN); + route->tuple[dir].out.ifindex = info.outdev->ifindex; + route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex; + route->tuple[dir].xmit_type = info.xmit_type; + } +} + +static int +xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct, + const struct xt_action_param *par, + struct nf_flow_route *route, enum ip_conntrack_dir dir, + struct net_device **devs) +{ + struct dst_entry *this_dst = skb_dst(skb); + struct dst_entry *other_dst = NULL; + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + switch (xt_family(par)) { + case NFPROTO_IPV4: + fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; + fl.u.ip4.flowi4_oif = xt_in(par)->ifindex; + break; + case NFPROTO_IPV6: + fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6; + fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; + fl.u.ip6.flowi6_oif = xt_in(par)->ifindex; + break; + } + + if (!dst_hold_safe(this_dst)) + return -ENOENT; + + nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par)); + if (!other_dst) { + dst_release(this_dst); + return -ENOENT; + } + + nf_default_forward_path(route, this_dst, dir, devs); + nf_default_forward_path(route, other_dst, !dir, devs); + + if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH && + route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) { + nf_dev_forward_path(route, ct, dir, devs); + nf_dev_forward_path(route, ct, !dir, devs); + } + + return 0; +} + +static unsigned int +flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + struct xt_flowoffload_table *table; + const struct xt_flowoffload_target_info *info = par->targinfo; + struct tcphdr _tcph, *tcph = NULL; + enum ip_conntrack_info ctinfo; + enum ip_conntrack_dir dir; + struct nf_flow_route route = {}; + struct flow_offload *flow = NULL; + struct net_device *devs[2] = {}; + struct nf_conn *ct; + struct net *net; + + if (xt_flowoffload_skip(skb, xt_family(par))) + return XT_CONTINUE; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) + return XT_CONTINUE; + + switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) { + case IPPROTO_TCP: + if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) + return XT_CONTINUE; + + tcph = skb_header_pointer(skb, par->thoff, + sizeof(_tcph), &_tcph); + if (unlikely(!tcph || tcph->fin || tcph->rst)) + return XT_CONTINUE; + break; + case IPPROTO_UDP: + break; + default: + return XT_CONTINUE; + } + + if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) || + ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH)) + return XT_CONTINUE; + + if (!nf_ct_is_confirmed(ct)) + return XT_CONTINUE; + + dir = CTINFO2DIR(ctinfo); + + devs[dir] = xt_out(par); + devs[!dir] = xt_in(par); + + if (!devs[dir] || !devs[!dir]) + return XT_CONTINUE; + + if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status)) + return XT_CONTINUE; + + if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0) + goto err_flow_route; + + flow = flow_offload_alloc(ct); + if (!flow) + goto err_flow_alloc; + + flow_offload_route_init(flow, &route); + + if (tcph) { + ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + } + + table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)]; + + net = read_pnet(&table->ft.net); + if (!net) + write_pnet(&table->ft.net, xt_net(par)); + + __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags); + if (flow_offload_add(&table->ft, flow) < 0) + goto err_flow_add; + + xt_flowoffload_check_device(table, devs[0]); + xt_flowoffload_check_device(table, devs[1]); + + return XT_CONTINUE; + +err_flow_add: + flow_offload_free(flow); +err_flow_alloc: + dst_release(route.tuple[dir].dst); + dst_release(route.tuple[!dir].dst); +err_flow_route: + clear_bit(IPS_OFFLOAD_BIT, &ct->status); + + return XT_CONTINUE; +} + +static int flowoffload_chk(const struct xt_tgchk_param *par) +{ + struct xt_flowoffload_target_info *info = par->targinfo; + + if (info->flags & ~XT_FLOWOFFLOAD_MASK) + return -EINVAL; + + return 0; +} + +static struct xt_target offload_tg_reg __read_mostly = { + .family = NFPROTO_UNSPEC, + .name = "FLOWOFFLOAD", + .revision = 0, + .targetsize = sizeof(struct xt_flowoffload_target_info), + .usersize = sizeof(struct xt_flowoffload_target_info), + .checkentry = flowoffload_chk, + .target = flowoffload_tg, + .me = THIS_MODULE, +}; + +static int flow_offload_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct xt_flowoffload_hook *hook0, *hook1; + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + + spin_lock_bh(&hooks_lock); + hook0 = flow_offload_lookup_hook(&flowtable[0], dev); + if (hook0) + hlist_del(&hook0->list); + + hook1 = flow_offload_lookup_hook(&flowtable[1], dev); + if (hook1) + hlist_del(&hook1->list); + spin_unlock_bh(&hooks_lock); + + if (hook0) { + nf_unregister_net_hook(hook0->net, &hook0->ops); + kfree(hook0); + } + + if (hook1) { + nf_unregister_net_hook(hook1->net, &hook1->ops); + kfree(hook1); + } + + nf_flow_table_cleanup(dev); + + return NOTIFY_DONE; +} + +static struct notifier_block flow_offload_netdev_notifier = { + .notifier_call = flow_offload_netdev_event, +}; + +static int nf_flow_rule_route_inet(struct net *net, + struct flow_offload *flow, + enum flow_offload_tuple_dir dir, + struct nf_flow_rule *flow_rule) +{ + const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple; + int err; + + switch (flow_tuple->l3proto) { + case NFPROTO_IPV4: + err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule); + break; + case NFPROTO_IPV6: + err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule); + break; + default: + err = -1; + break; + } + + return err; +} + +static struct nf_flowtable_type flowtable_inet = { + .family = NFPROTO_INET, + .init = nf_flow_table_init, + .setup = nf_flow_table_offload_setup, + .action = nf_flow_rule_route_inet, + .free = nf_flow_table_free, + .hook = xt_flowoffload_net_hook, + .owner = THIS_MODULE, +}; + +static int init_flowtable(struct xt_flowoffload_table *tbl) +{ + INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work); + tbl->ft.type = &flowtable_inet; + tbl->ft.flags = NF_FLOWTABLE_COUNTER; + + return nf_flow_table_init(&tbl->ft); +} + +static int __init xt_flowoffload_tg_init(void) +{ + int ret; + + register_netdevice_notifier(&flow_offload_netdev_notifier); + + ret = init_flowtable(&flowtable[0]); + if (ret) + return ret; + + ret = init_flowtable(&flowtable[1]); + if (ret) + goto cleanup; + + flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD; + + ret = xt_register_target(&offload_tg_reg); + if (ret) + goto cleanup2; + + return 0; + +cleanup2: + nf_flow_table_free(&flowtable[1].ft); +cleanup: + nf_flow_table_free(&flowtable[0].ft); + return ret; +} + +static void __exit xt_flowoffload_tg_exit(void) +{ + xt_unregister_target(&offload_tg_reg); + unregister_netdevice_notifier(&flow_offload_netdev_notifier); + nf_flow_table_free(&flowtable[0].ft); + nf_flow_table_free(&flowtable[1].ft); +} + +MODULE_LICENSE("GPL"); +module_init(xt_flowoffload_tg_init); +module_exit(xt_flowoffload_tg_exit); -- 2.51.0 From a0ee647309aad3970467977ed72824d7c453aba4 Mon Sep 17 00:00:00 2001 From: Imre Kaloz Date: Fri, 7 Jul 2017 17:21:05 +0200 Subject: [PATCH 357/517] mac80211: increase wireless mesh header size lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1 Signed-off-by: Imre Kaloz --- include/linux/netdevice.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c0a26b22f590..0f68392e0199 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -159,8 +159,8 @@ static inline bool dev_xmit_complete(int rc) #if defined(CONFIG_HYPERV_NET) # define LL_MAX_HEADER 128 -#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) -# if defined(CONFIG_MAC80211_MESH) +#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1 +# if defined(CONFIG_MAC80211_MESH) || 1 # define LL_MAX_HEADER 128 # else # define LL_MAX_HEADER 96 -- 2.51.0 From 0444c74d164efb1fdec620766fd416d88fb65d4d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 17:21:53 +0200 Subject: [PATCH 358/517] hack: net: fq_codel: tune defaults for small devices Assume that x86_64 devices always have a big memory and do not need this optimization compared to devices with only 32 MB or 64 MB RAM. Signed-off-by: Felix Fietkau --- net/sched/sch_fq_codel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 551b7cbdae90..9f8741081cef 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -472,7 +472,11 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, sch->limit = 10*1024; q->flows_cnt = 1024; +#ifdef CONFIG_X86_64 q->memory_limit = 32 << 20; /* 32 MBytes */ +#else + q->memory_limit = 4 << 20; /* 4 MBytes */ +#endif q->drop_batch_size = 64; q->quantum = psched_mtu(qdisc_dev(sch)); INIT_LIST_HEAD(&q->new_flows); -- 2.51.0 From 8bbcca90b9c5ef9e32a374a259d0ae25f128c95e Mon Sep 17 00:00:00 2001 From: Rui Salvaterra Date: Wed, 30 Mar 2022 22:51:55 +0100 Subject: [PATCH 359/517] kernel: ct: size the hashtable more adequately To set the default size of the connection tracking hash table, a divider of 16384 becomes inadequate for a router handling lots of connections. Divide by 2048 instead, making the default size scale better with the available RAM. Signed-off-by: Rui Salvaterra --- net/netfilter/nf_conntrack_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index f5bde4f13958..cdcc01fcd30f 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -2648,7 +2648,7 @@ int nf_conntrack_init_start(void) if (!nf_conntrack_htable_size) { nf_conntrack_htable_size - = (((nr_pages << PAGE_SHIFT) / 16384) + = (((nr_pages << PAGE_SHIFT) / 2048) / sizeof(struct hlist_head)); if (BITS_PER_LONG >= 64 && nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) -- 2.51.0 From 2b0f67440761e35ef5eb7a2f3bc1e3d47deabf3c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 17:24:23 +0200 Subject: [PATCH 360/517] net: swconfig: adds openwrt switch layer Signed-off-by: Felix Fietkau --- drivers/net/phy/Kconfig | 74 +++++++++++++++++++++++++++++++ drivers/net/phy/Makefile | 15 +++++++ include/linux/platform_data/b53.h | 3 ++ 3 files changed, 92 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8c92405b84d4..7b1a94e8aa8b 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -77,6 +77,80 @@ config SFP depends on HWMON || HWMON=n select MDIO_I2C +comment "Switch configuration API + drivers" + +config SWCONFIG + tristate "Switch configuration API" + help + Switch configuration API using netlink. This allows + you to configure the VLAN features of certain switches. + +config SWCONFIG_LEDS + bool "Switch LED trigger support" + depends on (SWCONFIG && LEDS_TRIGGERS) + +config ADM6996_PHY + tristate "Driver for ADM6996 switches" + select SWCONFIG + help + Currently supports the ADM6996FC and ADM6996M switches. + Support for FC is very limited. + +config AR8216_PHY + tristate "Driver for Atheros AR8216/8327 switches" + select SWCONFIG + select ETHERNET_PACKET_MANGLE + +config AR8216_PHY_LEDS + bool "Atheros AR8216 switch LED support" + depends on (AR8216_PHY && LEDS_CLASS) + +source "drivers/net/phy/b53/Kconfig" + +config IP17XX_PHY + tristate "Driver for IC+ IP17xx switches" + select SWCONFIG + +config PSB6970_PHY + tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" + select SWCONFIG + +config RTL8306_PHY + tristate "Driver for Realtek RTL8306S switches" + select SWCONFIG + +config RTL8366_SMI + tristate "Driver for the RTL8366 SMI interface" + depends on GPIOLIB + help + This module implements the SMI interface protocol which is used + by some RTL8366 ethernet switch devices via the generic GPIO API. + +if RTL8366_SMI + +config RTL8366_SMI_DEBUG_FS + bool "RTL8366 SMI interface debugfs support" + depends on DEBUG_FS + default n + +config RTL8366S_PHY + tristate "Driver for the Realtek RTL8366S switch" + select SWCONFIG + +config RTL8366RB_PHY + tristate "Driver for the Realtek RTL8366RB switch" + select SWCONFIG + +config RTL8367_PHY + tristate "Driver for the Realtek RTL8367R/M switches" + select SWCONFIG + +config RTL8367B_PHY + tristate "Driver for the Realtek RTL8367R-VB switch" + select SWCONFIG + +endif # RTL8366_SMI + comment "MII PHY device drivers" config AS21XXX_PHY diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a9080b8d604e..5fefb4d699fb 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -27,6 +27,21 @@ libphy-$(CONFIG_OPEN_ALLIANCE_HELPERS) += open_alliance_helpers.o obj-$(CONFIG_PHYLINK) += phylink.o obj-$(CONFIG_PHYLIB) += libphy.o +obj-$(CONFIG_SWCONFIG) += swconfig.o +obj-$(CONFIG_ADM6996_PHY) += adm6996.o +obj-$(CONFIG_AR8216_PHY) += ar8xxx.o +ar8xxx-y += ar8216.o +ar8xxx-y += ar8327.o +obj-$(CONFIG_SWCONFIG_B53) += b53/ +obj-$(CONFIG_IP17XX_PHY) += ip17xx.o +obj-$(CONFIG_PSB6970_PHY) += psb6970.o +obj-$(CONFIG_RTL8306_PHY) += rtl8306.o +obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o +obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o +obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o +obj-$(CONFIG_RTL8367_PHY) += rtl8367.o +obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o + obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o obj-$(CONFIG_SFP) += sfp.o diff --git a/include/linux/platform_data/b53.h b/include/linux/platform_data/b53.h index 6f6fed2b171d..2d90457926e5 100644 --- a/include/linux/platform_data/b53.h +++ b/include/linux/platform_data/b53.h @@ -29,6 +29,9 @@ struct b53_platform_data { u32 chip_id; u16 enabled_ports; + /* allow to specify an ethX alias */ + const char *alias; + /* only used by MMAP'd driver */ unsigned big_endian:1; void __iomem *regs; -- 2.51.0 From 18a667d953110fd776c1a9850bc80c9290fa7527 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:45:56 +0200 Subject: [PATCH 361/517] net/dsa/mv88e6xxx: disable ATU violation --- drivers/net/dsa/mv88e6xxx/chip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 43e0482fe1fd..2b547c2a7f43 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3582,6 +3582,9 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) else reg = 1 << port; + /* Disable ATU member violation interrupt */ + reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG; + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg); if (err) -- 2.51.0 From b3147d8d726ee0e591bb977db46056fa51385934 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 7 Jul 2017 17:25:00 +0200 Subject: [PATCH 362/517] net: add packet mangeling ar8216 switches have a hardware bug, which renders normal 802.1q support unusable. Packet mangling is required to fix up the vlan for incoming packets. Signed-off-by: Felix Fietkau --- include/linux/netdevice.h | 10 ++++++++++ include/linux/skbuff.h | 14 ++++---------- net/Kconfig | 6 ++++++ net/core/dev.c | 5 +++++ net/core/skbuff.c | 17 +++++++++++++++++ net/ethernet/eth.c | 6 ++++++ 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0f68392e0199..1d2dd73b6091 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1687,6 +1687,7 @@ enum netdev_priv_flags { IFF_L3MDEV_RX_HANDLER = 1<<29, IFF_NO_ADDRCONF = BIT_ULL(30), IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), + IFF_NO_IP_ALIGN = BIT_ULL(32), }; /* Specifies the type of the struct net_device::ml_priv pointer */ @@ -2168,6 +2169,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); + struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); +#endif + unsigned int operstate; unsigned char link_mode; @@ -2237,6 +2243,10 @@ struct net_device { struct mctp_dev __rcu *mctp_ptr; #endif +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + void *phy_ptr; /* PHY device specific data */ +#endif + /* * Cache lines mostly used on receive path (including eth_type_trans()) */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index eb7b94939f46..d689ea0fa9f2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3242,6 +3242,10 @@ static inline int pskb_trim(struct sk_buff *skb, unsigned int len) return (len < skb->len) ? __pskb_trim(skb, len) : 0; } +extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length, gfp_t gfp); + + /** * pskb_trim_unique - remove end from a paged unique (not cloned) buffer * @skb: buffer to alter @@ -3407,16 +3411,6 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length) } -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, - unsigned int length, gfp_t gfp) -{ - struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); - - if (NET_IP_ALIGN && skb) - skb_reserve(skb, NET_IP_ALIGN); - return skb; -} - static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, unsigned int length) { diff --git a/net/Kconfig b/net/Kconfig index 6744f55d9683..c98df432683b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -26,6 +26,12 @@ menuconfig NET if NET +config ETHERNET_PACKET_MANGLE + bool + help + This option can be selected by phy drivers that need to mangle + packets going in or out of an ethernet device. + config WANT_COMPAT_NETLINK_MESSAGES bool help diff --git a/net/core/dev.c b/net/core/dev.c index cfd32bd02a69..30a22db52d58 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3658,6 +3658,11 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev, if (dev_nit_active(dev)) dev_queue_xmit_nit(skb, dev); +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) + return NETDEV_TX_OK; +#endif + len = skb->len; trace_net_dev_start_xmit(skb, dev); rc = netdev_start_xmit(skb, dev, txq, more); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6a92c03ee6f4..0a8628524de9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -326,6 +327,22 @@ void *__napi_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) } EXPORT_SYMBOL(__napi_alloc_frag_align); +struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length, gfp_t gfp) +{ + struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) + return skb; +#endif + + if (NET_IP_ALIGN && skb) + skb_reserve(skb, NET_IP_ALIGN); + return skb; +} +EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); + void *__netdev_alloc_frag_align(unsigned int fragsz, unsigned int align_mask) { void *data; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 4e3651101b86..b7fb89299528 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) const struct ethhdr *eth; skb->dev = dev; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + if (dev->eth_mangle_rx) + dev->eth_mangle_rx(dev, skb); +#endif + skb_reset_mac_header(skb); eth = eth_skb_pull_mac(skb); -- 2.51.0 From 2fb8b4eee5e48e4522386d31f25989d55aedab32 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Tue, 27 Aug 2019 15:16:56 +0300 Subject: [PATCH 363/517] drivers: net: phy: aquantia: enable AQR112 and AQR412 Adds support for AQR112 and AQR412 which is mostly based on existing code with the addition of code configuring the protocol on system side. This allows changing the system side protocol without having to deploy a different firmware on the PHY. Signed-off-by: Alex Marginean --- drivers/net/phy/aquantia/aquantia_main.c | 72 +++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 2008b98c689e..542c4d0d699e 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -97,6 +97,29 @@ #define AQR107_OP_IN_PROG_SLEEP 1000 #define AQR107_OP_IN_PROG_TIMEOUT 100000 +/* registers in MDIO_MMD_VEND1 region */ +#define AQUANTIA_VND1_GLOBAL_SC 0x000 +#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb) + +/* global start rate, the protocol associated with this speed is used by default + * on SI. + */ +#define AQUANTIA_VND1_GSTART_RATE 0x31a +#define AQUANTIA_VND1_GSTART_RATE_OFF 0 +#define AQUANTIA_VND1_GSTART_RATE_100M 1 +#define AQUANTIA_VND1_GSTART_RATE_1G 2 +#define AQUANTIA_VND1_GSTART_RATE_10G 3 +#define AQUANTIA_VND1_GSTART_RATE_2_5G 4 +#define AQUANTIA_VND1_GSTART_RATE_5G 5 + +/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */ +#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b +#define AQUANTIA_VND1_GSYSCFG_100M 0 +#define AQUANTIA_VND1_GSYSCFG_1G 1 +#define AQUANTIA_VND1_GSYSCFG_2_5G 2 +#define AQUANTIA_VND1_GSYSCFG_5G 3 +#define AQUANTIA_VND1_GSYSCFG_10G 4 + static int aqr107_get_sset_count(struct phy_device *phydev) { return AQR107_SGMII_STAT_SZ; @@ -203,6 +226,51 @@ static int aqr_config_aneg(struct phy_device *phydev) return genphy_c45_check_and_restart_aneg(phydev, changed); } +static struct { + u16 syscfg; + int cnt; + u16 start_rate; +} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = { + [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G, + AQUANTIA_VND1_GSTART_RATE_1G}, + [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G, + AQUANTIA_VND1_GSTART_RATE_2_5G}, + [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, + [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, +}; + +/* Sets up protocol on system side before calling aqr_config_aneg */ +static int aqr_config_aneg_set_prot(struct phy_device *phydev) +{ + int if_type = phydev->interface; + int i; + + if (!aquantia_syscfg[if_type].cnt) + return 0; + + /* set PHY in low power mode so we can configure protocols */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, + AQUANTIA_VND1_GLOBAL_SC_LP); + mdelay(10); + + /* set the default rate to enable the SI link */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, + aquantia_syscfg[if_type].start_rate); + + for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) + phy_write_mmd(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i, + aquantia_syscfg[if_type].syscfg); + + /* wake PHY back up */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); + mdelay(10); + + return aqr_config_aneg(phydev); +} + static int aqr_config_intr(struct phy_device *phydev) { bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; @@ -972,7 +1040,7 @@ static struct phy_driver aqr_driver[] = { PHY_ID_MATCH_MODEL(PHY_ID_AQR112), .name = "Aquantia AQR112", .probe = aqr107_probe, - .config_aneg = aqr_config_aneg, + .config_aneg = aqr_config_aneg_set_prot, .config_intr = aqr_config_intr, .handle_interrupt = aqr_handle_interrupt, .get_tunable = aqr107_get_tunable, @@ -995,7 +1063,7 @@ static struct phy_driver aqr_driver[] = { PHY_ID_MATCH_MODEL(PHY_ID_AQR412), .name = "Aquantia AQR412", .probe = aqr107_probe, - .config_aneg = aqr_config_aneg, + .config_aneg = aqr_config_aneg_set_prot, .config_intr = aqr_config_intr, .handle_interrupt = aqr_handle_interrupt, .get_tunable = aqr107_get_tunable, -- 2.51.0 From 36bebde61759d445e0eef0559c74377af98a3bbc Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Fri, 20 Sep 2019 18:22:52 +0300 Subject: [PATCH 364/517] drivers: net: phy: aquantia: fix system side protocol misconfiguration Do not set up protocols for speeds that are not supported by FW. Enabling these protocols leads to link issues on system side. Signed-off-by: Alex Marginean --- drivers/net/phy/aquantia/aquantia_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 542c4d0d699e..a5269b7ec26d 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -259,10 +259,16 @@ static int aqr_config_aneg_set_prot(struct phy_device *phydev) phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, aquantia_syscfg[if_type].start_rate); - for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) + for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) { + u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i); + if (!reg) + continue; + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSYSCFG_BASE + i, aquantia_syscfg[if_type].syscfg); + } /* wake PHY back up */ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); -- 2.51.0 From 9d7a3fd6822d5ea9dcd306a8adad5b3c1160047a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 23 Dec 2021 14:52:56 +0000 Subject: [PATCH 365/517] net: phy: aquantia: add PHY_ID for AQR112R As advised by Ian Chang this PHY is used in Puzzle devices. Signed-off-by: Daniel Golle --- drivers/net/phy/aquantia/aquantia_main.c | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index a5269b7ec26d..f25e63480ec2 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -32,6 +32,8 @@ #define PHY_ID_AQR114C 0x31c31c22 #define PHY_ID_AQR115C 0x31c31c33 #define PHY_ID_AQR813 0x31c31cb2 +#define PHY_ID_AQR112C 0x03a1b790 +#define PHY_ID_AQR112R 0x31c31d12 #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) @@ -1205,6 +1207,30 @@ static struct phy_driver aqr_driver[] = { .led_hw_control_get = aqr_phy_led_hw_control_get, .led_polarity_set = aqr_phy_led_polarity_set, }, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR112C), + .name = "Aquantia AQR112C", + .probe = aqr107_probe, + .config_aneg = aqr_config_aneg_set_prot, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, +}, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR112R), + .name = "Aquantia AQR112R", + .probe = aqr107_probe, + .config_aneg = aqr_config_aneg_set_prot, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, + .get_sset_count = aqr107_get_sset_count, + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, +}, }; module_phy_driver(aqr_driver); @@ -1226,6 +1252,8 @@ static const struct mdio_device_id __maybe_unused aqr_tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR115C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) }, { } }; -- 2.51.0 From 41fcce1b7749447554e6dd24270895a39be0a7ce Mon Sep 17 00:00:00 2001 From: Bo-Cun Chen Date: Wed, 27 Nov 2024 13:36:49 +0800 Subject: [PATCH 366/517] net: ethernet: mtk_eth_soc: add hw dump for forced reset Without this patch, the ETH driver is unable to dump the registers before triggering a forced reset. Signed-off-by: Bo-Cun Chen --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 55 +++++++++++++++++++++ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 56 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index bc217da6ffc7..7d8c6ee707d1 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -74,6 +74,7 @@ static const struct mtk_reg_map mtk_reg_map = { .rx_ptr = 0x1900, .rx_cnt_cfg = 0x1904, .qcrx_ptr = 0x1908, + .page = 0x19f0, .glo_cfg = 0x1a04, .rst_idx = 0x1a08, .delay_irq = 0x1a0c, @@ -140,6 +141,7 @@ static const struct mtk_reg_map mt7986_reg_map = { .rx_ptr = 0x4500, .rx_cnt_cfg = 0x4504, .qcrx_ptr = 0x4508, + .page = 0x45f0, .glo_cfg = 0x4604, .rst_idx = 0x4608, .delay_irq = 0x460c, @@ -191,6 +193,7 @@ static const struct mtk_reg_map mt7988_reg_map = { .rx_ptr = 0x4500, .rx_cnt_cfg = 0x4504, .qcrx_ptr = 0x4508, + .page = 0x45f0, .glo_cfg = 0x4604, .rst_idx = 0x4608, .delay_irq = 0x460c, @@ -4053,6 +4056,56 @@ static void mtk_set_mcr_max_rx(struct mtk_mac *mac, u32 val) mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); } +static void mtk_hw_dump_reg(struct mtk_eth *eth, char *name, u32 offset, u32 range) +{ + u32 cur = offset; + + pr_info("\n==================== %s ====================\n", name); + while (cur < offset + range) { + pr_info("0x%08x: %08x %08x %08x %08x\n", + cur, mtk_r32(eth, cur), mtk_r32(eth, cur + 0x4), + mtk_r32(eth, cur + 0x8), mtk_r32(eth, cur + 0xc)); + cur += 0x10; + } +} + +static void mtk_hw_dump(struct mtk_eth *eth) +{ + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + u32 id; + + mtk_hw_dump_reg(eth, "FE", 0x0, 0x600); + mtk_hw_dump_reg(eth, "FE", 0x1400, 0x300); + mtk_hw_dump_reg(eth, "ADMA", reg_map->pdma.rx_ptr, 0x300); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + for (id = 0; id < MTK_QDMA_NUM_QUEUES / 16; id++) { + mtk_w32(eth, id, reg_map->qdma.page); + pr_info("\nQDMA PAGE:%x ", mtk_r32(eth, reg_map->qdma.page)); + mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.qtx_cfg, 0x100); + mtk_w32(eth, 0, reg_map->qdma.page); + } + mtk_hw_dump_reg(eth, "QDMA", reg_map->qdma.rx_ptr, 0x300); + } + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + mtk_hw_dump_reg(eth, "WDMA0", reg_map->wdma_base[0], 0x400); + mtk_hw_dump_reg(eth, "WDMA1", reg_map->wdma_base[1], 0x400); + if (mtk_is_netsys_v3_or_greater(eth)) + mtk_hw_dump_reg(eth, "WDMA2", reg_map->wdma_base[2], 0x400); + } + mtk_hw_dump_reg(eth, "PPE0", reg_map->ppe_base + 0x200, 0x200); + if (!mtk_is_netsys_v1(eth)) + mtk_hw_dump_reg(eth, "PPE1", reg_map->ppe_base + 0x600, 0x200); + if (mtk_is_netsys_v3_or_greater(eth)) + mtk_hw_dump_reg(eth, "PPE2", reg_map->ppe_base + 0xE00, 0x200); + mtk_hw_dump_reg(eth, "GMAC", 0x10000, 0x300); + if (mtk_is_netsys_v3_or_greater(eth)) + mtk_hw_dump_reg(eth, "GMAC", 0x10300, 0x100); + if (mtk_is_netsys_v3_or_greater(eth)) { + mtk_hw_dump_reg(eth, "XGMAC0", 0x12000, 0x300); + mtk_hw_dump_reg(eth, "XGMAC1", 0x13000, 0x300); + } +} + static void mtk_hw_reset(struct mtk_eth *eth) { u32 val; @@ -4532,6 +4585,8 @@ static void mtk_pending_work(struct work_struct *work) rtnl_lock(); set_bit(MTK_RESETTING, ð->state); + mtk_hw_dump(eth); + mtk_prepare_for_reset(eth); mtk_wed_fe_reset(); /* Run again reset preliminary configuration in order to avoid any diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index c7ad88351a1b..d0e7ce0bcb96 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -1185,6 +1185,7 @@ struct mtk_reg_map { u32 rx_ptr; /* rx base pointer */ u32 rx_cnt_cfg; /* rx max count configuration */ u32 qcrx_ptr; /* rx cpu pointer */ + u32 page; /* page configuration */ u32 glo_cfg; /* global configuration */ u32 rst_idx; /* reset index */ u32 delay_irq; /* delay interrupt */ -- 2.51.0 From 3353024c7ed6fc97e113e5f2e4e94a94913f1a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:25 +0100 Subject: [PATCH 367/517] /home/cynerd/turris/upstream/openwrt/target/linux/generic/hack-6.12/735-net-phy-realtek-rtl8261n.patch --- drivers/net/phy/Kconfig | 2 ++ drivers/net/phy/Makefile | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 7b1a94e8aa8b..0e672540a0fa 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -431,6 +431,8 @@ config QSEMI_PHY source "drivers/net/phy/realtek/Kconfig" +source "drivers/net/phy/rtl8261n/Kconfig" + config RENESAS_PHY tristate "Renesas PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 5fefb4d699fb..d0f2b36d5c87 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek/ +obj-y += rtl8261n/ obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o obj-$(CONFIG_SMSC_PHY) += smsc.o -- 2.51.0 From a0ea1cb120f6dabaf6dcd5dc79f5b5225718c901 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 27 Mar 2023 18:41:54 +0100 Subject: [PATCH 368/517] generic: pcs-mtk-lynxi: add hack to use 2500Base-X without AN Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually disabling auto-negotiation, e.g. using ethtool. While a proper fix using SFP quirks is being discussed upstream, bring a work-around to restore user experience to what it was before the switch to the dedicated SGMII PCS driver. Signed-off-by: Daniel Golle --- drivers/net/pcs/pcs-mtk-lynxi.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 9f32540bba9c..893cac2cec05 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -129,14 +129,23 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); - unsigned int bm, adv; + unsigned int bm, bmsr, adv; /* Read the BMSR and LPA */ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); - regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); + bmsr = FIELD_GET(SGMII_BMSR, bm); + + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { + state->link = !!(bmsr & BMSR_LSTATUS); + state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); + state->speed = SPEED_2500; + state->duplex = DUPLEX_FULL; - phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), - FIELD_GET(SGMII_LPA, adv)); + return; + } + + regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); + phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv)); } static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs) @@ -157,7 +166,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); bool mode_changed = false, changed; - unsigned int rgc3, sgm_mode, bmcr; + unsigned int rgc3, sgm_mode, bmcr = 0; int advertise, link_timer; advertise = phylink_mii_c22_pcs_encode_advertisement(interface, @@ -180,9 +189,8 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { if (interface == PHY_INTERFACE_MODE_SGMII) sgm_mode |= SGMII_SPEED_DUPLEX_AN; - bmcr = BMCR_ANENABLE; - } else { - bmcr = 0; + if (interface != PHY_INTERFACE_MODE_2500BASEX) + bmcr = BMCR_ANENABLE; } if (mpcs->interface != interface) { -- 2.51.0 From 969256813f6ef11793261d85649fa8fdd5cc1ff5 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 26 Jul 2020 02:38:31 +0200 Subject: [PATCH 369/517] net: usb: r8152: add LED configuration from OF This adds the ability to configure the LED configuration register using OF. This way, the correct value for board specific LED configuration can be determined. Signed-off-by: David Bauer --- drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 3fcd2b736c5e..22ab3a08a6bc 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -7047,6 +7048,22 @@ static void rtl_tally_reset(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); } +static int r8152_led_configuration(struct r8152 *tp) +{ + u32 led_data; + int ret; + + ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data", + &led_data); + + if (ret) + return ret; + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data); + + return 0; +} + static void r8152b_init(struct r8152 *tp) { u32 ocp_data; @@ -7088,6 +7105,8 @@ static void r8152b_init(struct r8152 *tp) ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); + + r8152_led_configuration(tp); } static void r8153_init(struct r8152 *tp) @@ -7228,6 +7247,8 @@ static void r8153_init(struct r8152 *tp) tp->coalesce = COALESCE_SLOW; break; } + + r8152_led_configuration(tp); } static void r8153b_init(struct r8152 *tp) @@ -7310,6 +7331,8 @@ static void r8153b_init(struct r8152 *tp) rtl_tally_reset(tp); tp->coalesce = 15000; /* 15 us */ + + r8152_led_configuration(tp); } static void r8153c_init(struct r8152 *tp) -- 2.51.0 From 8ed5aab6aef4043c297da7f4827030482eb477af Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sun, 26 Jul 2020 15:30:33 +0200 Subject: [PATCH 370/517] dt-bindings: net: add RTL8152 binding documentation Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet adapters. Signed-off-by: David Bauer --- .../bindings/net/realtek,rtl8152.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml diff --git a/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml new file mode 100644 index 000000000000..7501b074a499 --- /dev/null +++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek RTL8152/RTL8153 series USB ethernet + +maintainers: + - David Bauer + +properties: + compatible: + oneOf: + - items: + - enum: + - realtek,rtl8152 + - realtek,rtl8153 + + reg: + description: The device number on the USB bus + + realtek,led-data: + description: Value to be written to the LED configuration register. + +required: + - compatible + - reg + +examples: + - | + usb-eth@2 { + compatible = "realtek,rtl8153"; + reg = <2>; + realtek,led-data = <0x87>; + }; \ No newline at end of file -- 2.51.0 From 3f30f686292664e0719b8a8f4d1f1dfb582fd655 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 28 Apr 2023 01:53:01 +0200 Subject: [PATCH 371/517] net: phy: mediatek-ge: add LED configuration interface This adds a small hack similar to the one used for ar8xxx switches to read a reg:value map for configuring the LED configuration registers. This allows OpenWrt to write device-specific LED action as well as blink configurations. It is unlikely to be accepted upstream, as upstream plans on integrating their own framework for handling these LEDs. Signed-off-by: David Bauer --- drivers/net/phy/mediatek/mtk-ge.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c index 73d9b72f9d9e..97d845c906dd 100644 --- a/drivers/net/phy/mediatek/mtk-ge.c +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ +#include #include #include #include @@ -73,6 +74,36 @@ static int mt7530_phy_config_init(struct phy_device *phydev) return 0; } +static int mt7530_led_config_of(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + const __be32 *paddr; + int len; + int i; + + paddr = of_get_property(np, "mediatek,led-config", &len); + if (!paddr) + return 0; + + if (len < (2 * sizeof(*paddr))) + return -EINVAL; + + len /= sizeof(*paddr); + + phydev_warn(phydev, "Configure LED registers (num=%d)\n", len); + for (i = 0; i < len - 1; i += 2) { + u32 reg; + u32 val; + + reg = be32_to_cpup(paddr + i); + val = be32_to_cpup(paddr + i + 1); + + phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val); + } + + return 0; +} + static int mt7531_phy_config_init(struct phy_device *phydev) { mtk_gephy_config_init(phydev); @@ -93,6 +124,9 @@ static int mt7531_phy_config_init(struct phy_device *phydev) FIELD_PREP(MTK_TX_DELAY_PAIR_B_MASK, 0x4) | FIELD_PREP(MTK_TX_DELAY_PAIR_D_MASK, 0x4)); + /* LED Config*/ + mt7530_led_config_of(phydev); + return 0; } -- 2.51.0 From e454aa294e15a7756316afb673b263b115ce67bc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Fri, 7 Jul 2017 17:26:01 +0200 Subject: [PATCH 372/517] bcm53xx: bgmac: use srab switch driver use the srab switch driver on these SoCs. Signed-off-by: Hauke Mehrtens --- drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 + drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++ drivers/net/ethernet/broadcom/bgmac.h | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c index 36f9bad28e6a..81db24b76591 100644 --- a/drivers/net/ethernet/broadcom/bgmac-bcma.c +++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c @@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_device *core) bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; + bgmac->feature_flags |= BGMAC_FEAT_SRAB; break; default: bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 6ffdc4229407..dd0138ee7337 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_ethtool_ops = { .set_link_ksettings = phy_ethtool_set_link_ksettings, }; +static struct b53_platform_data bgmac_b53_pdata = { +}; + +static struct platform_device bgmac_b53_dev = { + .name = "b53-srab-switch", + .id = -1, + .dev = { + .platform_data = &bgmac_b53_pdata, + }, +}; + /************************************************** * MII **************************************************/ @@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac) bgmac->in_init = false; + if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) { + bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000); + + err = platform_device_register(&bgmac_b53_dev); + if (!err) + bgmac->b53_device = &bgmac_b53_dev; + } + err = register_netdev(bgmac->net_dev); if (err) { dev_err(bgmac->dev, "Cannot register net device\n"); @@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); void bgmac_enet_remove(struct bgmac *bgmac) { + if (bgmac->b53_device) + platform_device_unregister(&bgmac_b53_dev); + bgmac->b53_device = NULL; + unregister_netdev(bgmac->net_dev); phy_disconnect(bgmac->net_dev->phydev); netif_napi_del(&bgmac->napi); diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 6fee9a41839c..c75a00af5bf6 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h @@ -387,6 +387,7 @@ #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18) #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19) #define BGMAC_FEAT_IDM_MASK BIT(20) +#define BGMAC_FEAT_SRAB BIT(21) struct bgmac_slot_info { union { @@ -494,6 +495,9 @@ struct bgmac { void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, u32 set); int (*phy_connect)(struct bgmac *bgmac); + + /* platform device for associated switch */ + struct platform_device *b53_device; }; struct bgmac *bgmac_alloc(struct device *dev); -- 2.51.0 From 890a69a2cfb04b333d3fe41cf0998ec70c5c0734 Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:49:26 +0200 Subject: [PATCH 373/517] net/usb/qmi_wwan: add MeigLink modem support --- drivers/net/usb/qmi_wwan.c | 6 ++++++ drivers/usb/serial/option.c | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index f04da733240c..50b2e996488e 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1076,6 +1076,11 @@ static const struct usb_device_id products[] = { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Meiglink SGM828 */ + USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, USB_CLASS_VENDOR_SPEC, 0x10, 0x05), + .driver_info = (unsigned long)&qmi_wwan_info, + }, + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ @@ -1083,6 +1088,7 @@ static const struct usb_device_id products[] = { {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ + {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */ /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 62e984d20e59..2ce56d02aed7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -247,6 +247,11 @@ static void option_instat_callback(struct urb *urb); #define UBLOX_PRODUCT_R410M 0x90b2 /* These Yuga products use Qualcomm's vendor ID */ #define YUGA_PRODUCT_CLM920_NC5 0x9625 +/* These MeigLink products use Qualcomm's vendor ID */ +#define MEIGLINK_PRODUCT_SLM750 0xf601 + +#define MEIGLINK_VENDOR_ID 0x2dee +#define MEIGLINK_PRODUCT_SLM828 0x4d49 #define QUECTEL_VENDOR_ID 0x2c7c /* These Quectel products use Quectel's vendor ID */ @@ -1154,6 +1159,11 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */ .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) }, + /* MeiG */ + { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x02) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x03) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGLINK_VENDOR_ID, MEIGLINK_PRODUCT_SLM828, USB_CLASS_VENDOR_SPEC, 0x10, 0x04) }, /* Quectel products using Qualcomm vendor ID */ { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)}, { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20), @@ -1195,6 +1205,11 @@ static const struct usb_device_id option_ids[] = { .driver_info = ZLP }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), .driver_info = RSVD(4) }, + /* Meiglink products using Qualcomm vendor ID */ + // Works OK. In case of some issues check macros that are used by Quectel Products + { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff), + .driver_info = NUMEP2 }, + { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, -- 2.51.0 From 16caa64f04b96be21c4d0929fae283bfc073b022 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 9 Apr 2024 17:06:38 +0100 Subject: [PATCH 374/517] rndis_host: add a bunch of USB IDs Add a bunch of USB IDs found in various places online to the RNDIS USB network driver. Signed-off-by: Daniel Golle --- drivers/net/usb/rndis_host.c | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 7b3739b29c8f..81ca6a4e9c06 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -630,6 +630,16 @@ static const struct driver_info zte_rndis_info = { .tx_fixup = rndis_tx_fixup, }; +static const struct driver_info asr_rndis_info = { + .description = "Asr RNDIS device", + .flags = FLAG_WWAN | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT | FLAG_NOARP, + .bind = rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, + .tx_fixup = rndis_tx_fixup, +}; + /*-------------------------------------------------------------------------*/ static const struct usb_device_id products [] = { @@ -665,6 +675,36 @@ static const struct usb_device_id products [] = { /* RNDIS for tethering */ USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), .driver_info = (unsigned long) &rndis_info, +}, { + /* Quectel EG060V rndis device */ + USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6004, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, +}, { + /* Quectel EC200A rndis device */ + USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6005, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, +}, { + /* Quectel EC200T rndis device */ + USB_DEVICE_AND_INTERFACE_INFO(0x2c7c, 0x6026, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, +}, { + /* Simcom A7906E rndis device */ + USB_DEVICE_AND_INTERFACE_INFO(0x1e0e, 0x9011, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, +}, { + /* Meig SLM770A */ + USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, +}, { + /* Meig SLM828 */ + USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d49, + USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &asr_rndis_info, }, { /* Novatel Verizon USB730L */ USB_INTERFACE_INFO(USB_CLASS_MISC, 4, 1), -- 2.51.0 From 35f347fc3508f2e506fd3d14677024e28f587056 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 12 Aug 2014 20:49:27 +0200 Subject: [PATCH 375/517] GPIO: add named gpio exports Signed-off-by: John Crispin --- drivers/gpio/gpiolib-of.c | 72 +++++++++++++++++++++++++++++++++++ drivers/gpio/gpiolib-sysfs.c | 17 ++++++++- include/linux/gpio/consumer.h | 17 +++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 36f8c7bb79d8..1d700c06f850 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -21,6 +21,8 @@ #include #include +#include +#include #include "gpiolib.h" #include "gpiolib-of.h" @@ -1198,3 +1200,73 @@ void of_gpiochip_remove(struct gpio_chip *chip) { of_node_put(dev_of_node(&chip->gpiodev->dev)); } + +#ifdef CONFIG_GPIO_SYSFS + +static const struct of_device_id gpio_export_ids[] = { + { .compatible = "gpio-export" }, + { /* sentinel */ } +}; + +static int of_gpio_export_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *cnp; + u32 val; + int nb = 0; + + for_each_child_of_node(np, cnp) { + const char *name = NULL; + int gpio; + bool dmc; + int max_gpio = 1; + int i; + + of_property_read_string(cnp, "gpio-export,name", &name); + + if (!name) + max_gpio = of_gpio_named_count(cnp, "gpios"); + + for (i = 0; i < max_gpio; i++) { + struct gpio_desc *desc; + unsigned flags = 0; + enum of_gpio_flags of_flags; + + desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags); + if (IS_ERR(desc)) + return PTR_ERR(desc); + gpio = desc_to_gpio(desc); + + if (of_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; + + if (!of_property_read_u32(cnp, "gpio-export,output", &val)) + flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + else + flags |= GPIOF_IN; + + if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) + continue; + + dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); + gpio_export_with_name(gpio_to_desc(gpio), dmc, name); + nb++; + } + } + + dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); + + return 0; +} + +static struct platform_driver gpio_export_driver = { + .driver = { + .name = "gpio-export", + .of_match_table = of_match_ptr(gpio_export_ids), + }, + .probe = of_gpio_export_probe, +}; + +module_platform_driver(gpio_export_driver); + +#endif diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 17ed229412af..aa98c5b08e9f 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -571,7 +571,7 @@ static struct class gpio_class = { * Returns: * 0 on success, or negative errno on failure. */ -int gpiod_export(struct gpio_desc *desc, bool direction_may_change) +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) { const char *ioname = NULL; struct gpio_device *gdev; @@ -629,6 +629,8 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) offset = gpio_chip_hwgpio(desc); if (guard.gc->names && guard.gc->names[offset]) ioname = guard.gc->names[offset]; + if (name) + ioname = name; dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, @@ -650,8 +652,21 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } +EXPORT_SYMBOL_GPL(__gpiod_export); + +int gpiod_export(struct gpio_desc *desc, bool direction_may_change) +{ + return __gpiod_export(desc, direction_may_change, NULL); +} EXPORT_SYMBOL_GPL(gpiod_export); +int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, + const char *name) +{ + return __gpiod_export(desc, direction_may_change, name); +} +EXPORT_SYMBOL_GPL(gpio_export_with_name); + static int match_export(struct device *dev, const void *desc) { struct gpiod_data *data = dev_get_drvdata(dev); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index db2dfbae8edb..22066cc19831 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -628,7 +628,10 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) +int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change, + const char *name); int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); void gpiod_unexport(struct gpio_desc *desc); @@ -637,12 +640,26 @@ void gpiod_unexport(struct gpio_desc *desc); #include +static inline int __gpiod_export(struct gpio_desc *desc, + bool direction_may_change, + const char *name) +{ + return -ENOSYS; +} + static inline int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { return -ENOSYS; } +static inline int gpio_export_with_name(struct gpio_desc *desc, + bool direction_may_change, + const char *name) +{ + return -ENOSYS; +} + static inline int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc) { -- 2.51.0 From 07ee1fba26616921d99f3aa7fcf8afb7f542c7ef Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Fri, 12 May 2023 11:08:43 +0200 Subject: [PATCH 376/517] ssb_sprom: add generic kernel support for Broadcom Fallback SPROMs --- drivers/bcma/Kconfig | 4 ++++ drivers/bcma/Makefile | 1 + drivers/bcma/bcma_private.h | 1 + drivers/bcma/main.c | 8 ++++++++ drivers/bcma/sprom.c | 23 ++++++++++++++--------- drivers/ssb/Kconfig | 5 +++++ drivers/ssb/Makefile | 1 + drivers/ssb/main.c | 8 ++++++++ drivers/ssb/sprom.c | 12 +++++++++++- drivers/ssb/ssb_private.h | 2 +- 10 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 2e9732e5c565..eb02cf92a983 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -18,6 +18,10 @@ config BCMA_BLOCKIO bool default y +config BCMA_FALLBACK_SPROM + bool + default y + config BCMA_HOST_PCI_POSSIBLE bool depends on PCI = y diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index f8c37de35da2..defc2de5c38a 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o +bcma-$(CONFIG_BCMA_FALLBACK_SPROM) += fallback-sprom.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o obj-$(CONFIG_BCMA) += bcma.o diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 6eded32d1aac..16c1ad8d0d76 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -8,6 +8,7 @@ #include #include +#include "fallback-sprom.h" #define bcma_err(bus, fmt, ...) \ dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 6842fe781eef..a7dcb8afc580 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -671,6 +671,14 @@ static int __init bcma_modinit(void) { int err; +#ifdef CONFIG_BCMA_FALLBACK_SPROM + err = bcma_fbs_register(); + if (err) { + pr_err("Fallback SPROM initialization failed\n"); + err = 0; + } +#endif /* CONFIG_BCMA_FALLBACK_SPROM */ + err = bcma_init_bus_register(); if (err) return err; diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index e668ad7963fc..6024d6b61a01 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, { int err; - if (!get_fallback_sprom) { + if (get_fallback_sprom) + err = get_fallback_sprom(bus, out); + +#ifdef CONFIG_BCMA_FALLBACK_SPROM + if (!get_fallback_sprom || err) + err = bcma_get_fallback_sprom(bus, out); +#else + if (!get_fallback_sprom) err = -ENOENT; - goto fail; - } +#endif /* CONFIG_BCMA_FALLBACK_SPROM */ - err = get_fallback_sprom(bus, out); - if (err) - goto fail; + if (err) { + bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); + return err; + } bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", bus->sprom.revision); + return 0; -fail: - bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); - return err; } /************************************************** diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 2bcf62e64f6f..a878deeb0c32 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig @@ -25,6 +25,11 @@ if SSB config SSB_SPROM bool +config SSB_FALLBACK_SPROM + bool + depends on SSB_PCIHOST + default y + # Support for Block-I/O. SELECT this from the driver that needs it. config SSB_BLOCKIO bool diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index 142d33df040f..3edced378e31 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile @@ -2,6 +2,7 @@ # core ssb-y += main.o scan.o ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o +ssb-$(CONFIG_SSB_FALLBACK_SPROM) += fallback-sprom.o ssb-$(CONFIG_SSB_SPROM) += sprom.o # host support diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index aa6165e3db4a..a62bfefd27a4 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1289,6 +1289,14 @@ static int __init ssb_modinit(void) { int err; +#ifdef CONFIG_SSB_FALLBACK_SPROM + err = ssb_fbs_register(); + if (err) { + pr_err("Fallback SPROM initialization failed\n"); + err = 0; + } +#endif /* CONFIG_SSB_FALLBACK_SPROM */ + /* See the comment at the ssb_is_early_boot definition */ ssb_is_early_boot = 0; err = bus_register(&ssb_bustype); diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 7cd553127861..1efc37466059 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus, int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) { + int err; + + if (get_fallback_sprom) + err = get_fallback_sprom(bus, out); + +#ifdef CONFIG_SSB_FALLBACK_SPROM + if (!get_fallback_sprom || err) + err = ssb_get_fallback_sprom(bus, out); +#else if (!get_fallback_sprom) return -ENOENT; +#endif /* CONFIG_SSB_FALLBACK_SPROM */ - return get_fallback_sprom(bus, out); + return err; } /* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 5f31bdfbe77f..7bdc9f80cd86 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h @@ -8,7 +8,7 @@ #include #include #include - +#include "fallback-sprom.h" /* pci.c */ #ifdef CONFIG_SSB_PCIHOST -- 2.51.0 From 2ff5fac19d3f48f1890e0f07baa53f0f0ceddec0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Jul 2017 08:16:31 +0200 Subject: [PATCH 377/517] debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS Signed-off-by: Felix Fietkau --- net/Kconfig | 3 +++ net/core/Makefile | 3 ++- net/core/sock.c | 19 +++++++++++++++++++ net/core/sock_diag.c | 18 ------------------ net/ipv4/Kconfig | 1 + net/netlink/Kconfig | 1 + net/packet/Kconfig | 1 + net/unix/Kconfig | 1 + net/xdp/Kconfig | 1 + 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/net/Kconfig b/net/Kconfig index c98df432683b..b1afb23fe2fb 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -138,6 +138,9 @@ source "net/mptcp/Kconfig" endif # if INET +config SOCK_DIAG + bool + config NETWORK_SECMARK bool "Security Marking" help diff --git a/net/core/Makefile b/net/core/Makefile index c3ebbaf9c81e..bd733d8aa76d 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -11,12 +11,13 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ - sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ + dev_ioctl.o tso.o sock_reuseport.o \ fib_notifier.o xdp.o flow_offload.o gro.o \ netdev-genl.o netdev-genl-gen.o gso.o obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o +obj-$(CONFIG_SOCK_DIAG) += sock_diag.o obj-y += net-sysfs.o obj-y += hotdata.o obj-y += netdev_rx_queue.o diff --git a/net/core/sock.c b/net/core/sock.c index 57fafa7cb47b..373671aee9c1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -118,6 +118,7 @@ #include #include #include +#include #include @@ -152,6 +153,7 @@ static DEFINE_MUTEX(proto_list_mutex); static LIST_HEAD(proto_list); +DEFINE_COOKIE(sock_cookie); static void sock_def_write_space_wfree(struct sock *sk); static void sock_def_write_space(struct sock *sk); @@ -587,6 +589,21 @@ int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, } EXPORT_SYMBOL(__sk_receive_skb); +u64 __sock_gen_cookie(struct sock *sk) +{ + u64 res = atomic64_read(&sk->sk_cookie); + + if (!res) { + u64 new = gen_cookie_next(&sock_cookie); + + atomic64_cmpxchg(&sk->sk_cookie, res, new); + + /* Another thread might have changed sk_cookie before us. */ + res = atomic64_read(&sk->sk_cookie); + } + return res; +} + INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *, u32)); INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, @@ -2342,9 +2359,11 @@ static void __sk_free(struct sock *sk) if (likely(sk->sk_net_refcnt)) sock_inuse_add(sock_net(sk), -1); +#ifdef CONFIG_SOCK_DIAG if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) sock_diag_broadcast_destroy(sk); else +#endif sk_destruct(sk); } diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a08eed9b9142..a915ec59f71d 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -22,23 +21,6 @@ static const struct sock_diag_inet_compat __rcu *inet_rcv_compat; static struct workqueue_struct *broadcast_wq; -DEFINE_COOKIE(sock_cookie); - -u64 __sock_gen_cookie(struct sock *sk) -{ - u64 res = atomic64_read(&sk->sk_cookie); - - if (!res) { - u64 new = gen_cookie_next(&sock_cookie); - - atomic64_cmpxchg(&sk->sk_cookie, res, new); - - /* Another thread might have changed sk_cookie before us. */ - res = atomic64_read(&sk->sk_cookie); - } - return res; -} - int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) { u64 res; diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 6d2c97f8e9ef..9ffd577d8270 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -423,6 +423,7 @@ config INET_TUNNEL config INET_DIAG tristate "INET: socket monitoring interface" + select SOCK_DIAG default y help Support for INET (TCP, DCCP, etc) socket monitoring interface used by diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig index 1039d4f2ce11..ef355897a316 100644 --- a/net/netlink/Kconfig +++ b/net/netlink/Kconfig @@ -5,6 +5,7 @@ config NETLINK_DIAG tristate "NETLINK: socket monitoring interface" + select SOCK_DIAG default n help Support for NETLINK socket monitoring interface used by the ss tool. diff --git a/net/packet/Kconfig b/net/packet/Kconfig index 2997382d597c..890796137daf 100644 --- a/net/packet/Kconfig +++ b/net/packet/Kconfig @@ -19,6 +19,7 @@ config PACKET config PACKET_DIAG tristate "Packet: sockets monitoring interface" depends on PACKET + select SOCK_DIAG default n help Support for PF_PACKET sockets monitoring interface used by the ss tool. diff --git a/net/unix/Kconfig b/net/unix/Kconfig index 8b5d04210d7c..39203827d660 100644 --- a/net/unix/Kconfig +++ b/net/unix/Kconfig @@ -24,6 +24,7 @@ config AF_UNIX_OOB config UNIX_DIAG tristate "UNIX: socket monitoring interface" depends on UNIX + select SOCK_DIAG default n help Support for UNIX socket monitoring interface used by the ss tool. diff --git a/net/xdp/Kconfig b/net/xdp/Kconfig index 71af2febe72a..719df49761a8 100644 --- a/net/xdp/Kconfig +++ b/net/xdp/Kconfig @@ -10,6 +10,7 @@ config XDP_SOCKETS config XDP_SOCKETS_DIAG tristate "XDP sockets: monitoring interface" depends on XDP_SOCKETS + select SOCK_DIAG default n help Support for PF_XDP sockets monitoring interface used by the ss tool. -- 2.51.0 From ef4552222c3a92648951ff86c41905786a7ce3a9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Jul 2017 08:20:09 +0200 Subject: [PATCH 378/517] debloat: procfs Signed-off-by: Felix Fietkau --- fs/locks.c | 2 ++ fs/proc/Kconfig | 5 +++++ fs/proc/consoles.c | 3 +++ fs/proc/proc_tty.c | 11 ++++++++++- include/net/snmp.h | 18 +++++++++++++++++- ipc/msg.c | 3 +++ ipc/sem.c | 2 ++ ipc/shm.c | 2 ++ ipc/util.c | 3 +++ kernel/exec_domain.c | 2 ++ kernel/irq/proc.c | 9 +++++++++ kernel/time/timer_list.c | 2 ++ mm/vmalloc.c | 3 +++ mm/vmstat.c | 8 +++++--- net/8021q/vlanproc.c | 6 ++++++ net/core/net-procfs.c | 18 ++++++++++++------ net/core/sock.c | 2 ++ net/ipv4/fib_trie.c | 18 ++++++++++++------ net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/proc.c | 3 +++ net/ipv4/route.c | 3 +++ 21 files changed, 107 insertions(+), 18 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 204847628f3e..7a98847ea331 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2971,6 +2971,8 @@ static const struct seq_operations locks_seq_operations = { static int __init proc_locks_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, sizeof(struct locks_iterator), NULL); return 0; diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index d80a1431ef7b..f5ab3bdea5c0 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -101,6 +101,11 @@ config PROC_CHILDREN Say Y if you are running any user-space software which takes benefit from this interface. For example, rkt is such a piece of software. +config PROC_STRIPPED + default n + depends on EXPERT + bool "Strip non-essential /proc functionality to reduce code size" + config PROC_PID_ARCH_STATUS def_bool n depends on PROC_FS diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c index b7cab1ad990d..e19f627a2cee 100644 --- a/fs/proc/consoles.c +++ b/fs/proc/consoles.c @@ -110,6 +110,9 @@ static const struct seq_operations consoles_op = { static int __init proc_consoles_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; + proc_create_seq("consoles", 0, NULL, &consoles_op); return 0; } diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 5c6a5ceab2f1..0e83f4daedf0 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -131,7 +131,10 @@ static const struct seq_operations tty_drivers_op = { void proc_tty_register_driver(struct tty_driver *driver) { struct proc_dir_entry *ent; - + + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + if (!driver->driver_name || driver->proc_entry || !driver->ops->proc_show) return; @@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver) { struct proc_dir_entry *ent; + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + ent = driver->proc_entry; if (!ent) return; @@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct tty_driver *driver) */ void __init proc_tty_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + if (!proc_mkdir("tty", NULL)) return; proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ diff --git a/include/net/snmp.h b/include/net/snmp.h index 468a67836e2f..f3ef151aa549 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h @@ -124,6 +124,21 @@ struct linux_tls_mib { #define DECLARE_SNMP_STAT(type, name) \ extern __typeof__(type) __percpu *name +#ifdef CONFIG_PROC_STRIPPED +#define __SNMP_STATS_DUMMY(mib) \ + do { (void) mib->mibs[0]; } while(0) + +#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) +#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib) +#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) +#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) +#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) +#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) +#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) +#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) + +#else + #define __SNMP_INC_STATS(mib, field) \ __this_cpu_inc(mib->mibs[field]) @@ -154,8 +169,9 @@ struct linux_tls_mib { __this_cpu_add(ptr[basefield##OCTETS], addend); \ } while (0) +#endif -#if BITS_PER_LONG==32 +#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED) #define __SNMP_ADD_STATS64(mib, field, addend) \ do { \ diff --git a/ipc/msg.c b/ipc/msg.c index fd08b3cb36d7..c71638872929 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -1370,6 +1370,9 @@ void __init msg_init(void) { msg_init_ns(&init_ipc_ns); + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", IPC_MSG_IDS, sysvipc_msg_proc_show); diff --git a/ipc/sem.c b/ipc/sem.c index a39cdc7bf88f..859af9ece817 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *ns) void __init sem_init(void) { sem_init_ns(&init_ipc_ns); + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; ipc_init_proc_interface("sysvipc/sem", " key semid perms nsems uid gid cuid cgid otime ctime\n", IPC_SEM_IDS, sysvipc_sem_proc_show); diff --git a/ipc/shm.c b/ipc/shm.c index 492fcc699985..8d8be78ae889 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -155,6 +155,8 @@ pure_initcall(ipc_ns_init); void __init shm_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; ipc_init_proc_interface("sysvipc/shm", #if BITS_PER_LONG <= 32 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", diff --git a/ipc/util.c b/ipc/util.c index 05cb9de66735..6a90d425e684 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(const char *path, const char *header, struct proc_dir_entry *pde; struct ipc_proc_iface *iface; + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + iface = kmalloc(sizeof(*iface), GFP_KERNEL); if (!iface) return; diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c index 33f07c5f2515..4c226a052bcd 100644 --- a/kernel/exec_domain.c +++ b/kernel/exec_domain.c @@ -29,6 +29,8 @@ static int execdomains_proc_show(struct seq_file *m, void *v) static int __init proc_execdomains_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; proc_create_single("execdomains", 0, NULL, execdomains_proc_show); return 0; } diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 9081ada81c3d..6a6ed1559ac7 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -339,6 +339,9 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) void __maybe_unused *irqp = (void *)(unsigned long) irq; char name [MAX_NAMELEN]; + if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) + return; + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) return; @@ -397,6 +400,9 @@ void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) { char name [MAX_NAMELEN]; + if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) + return; + if (!root_irq_dir || !desc->dir) return; #ifdef CONFIG_SMP @@ -435,6 +441,9 @@ void init_irq_proc(void) unsigned int irq; struct irq_desc *desc; + if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) + return; + /* create /proc/irq */ root_irq_dir = proc_mkdir("irq", NULL); if (!root_irq_dir) diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index cfbb46cc4e76..9a1dea23d175 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -354,6 +354,8 @@ static int __init init_timer_list_procfs(void) { struct proc_dir_entry *pe; + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, sizeof(struct timer_list_iter), NULL); if (!pe) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 3519c4e4f841..8a1d2bc055d9 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -5074,6 +5074,9 @@ static int vmalloc_info_show(struct seq_file *m, void *p) static int __init proc_vmalloc_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; + proc_create_single("vmallocinfo", 0400, NULL, vmalloc_info_show); return 0; } diff --git a/mm/vmstat.c b/mm/vmstat.c index 3f4134423912..7dc56a7829b5 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -2195,10 +2195,12 @@ void __init init_mm_internals(void) start_shepherd_timer(); #endif #ifdef CONFIG_PROC_FS - proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); - proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { + proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); + proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); + proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); + } proc_create_seq("vmstat", 0444, NULL, &vmstat_op); - proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); #endif } diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index fa67374bda49..3434370ab83e 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net) { struct vlan_net *vn = net_generic(net, vlan_net_id); + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return; + if (vn->proc_vlan_conf) remove_proc_entry(name_conf, vn->proc_vlan_dir); @@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net *net) { struct vlan_net *vn = net_generic(net, vlan_net_id); + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); if (!vn->proc_vlan_dir) goto err; diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index fa6d3969734a..5cafc5a9d3dc 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -295,10 +295,12 @@ static int __net_init dev_proc_net_init(struct net *net) if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, sizeof(struct seq_net_private))) goto out; - if (!proc_create_seq("softnet_stat", 0444, net->proc_net, + if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && + !proc_create_seq("softnet_stat", 0444, net->proc_net, &softnet_seq_ops)) goto out_dev; - if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, + if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && + !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, sizeof(struct seq_net_private))) goto out_softnet; @@ -308,9 +310,11 @@ static int __net_init dev_proc_net_init(struct net *net) out: return rc; out_ptype: - remove_proc_entry("ptype", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) + remove_proc_entry("ptype", net->proc_net); out_softnet: - remove_proc_entry("softnet_stat", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) + remove_proc_entry("softnet_stat", net->proc_net); out_dev: remove_proc_entry("dev", net->proc_net); goto out; @@ -320,8 +324,10 @@ static void __net_exit dev_proc_net_exit(struct net *net) { wext_proc_exit(net); - remove_proc_entry("ptype", net->proc_net); - remove_proc_entry("softnet_stat", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { + remove_proc_entry("ptype", net->proc_net); + remove_proc_entry("softnet_stat", net->proc_net); + } remove_proc_entry("dev", net->proc_net); } diff --git a/net/core/sock.c b/net/core/sock.c index 373671aee9c1..b8f37075a07e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -4277,6 +4277,8 @@ static __net_initdata struct pernet_operations proto_net_ops = { static int __init proto_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; return register_pernet_subsys(&proto_net_ops); } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index b7440806041b..3708ed3ccb44 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -3015,11 +3015,13 @@ static const struct seq_operations fib_route_seq_ops = { int __net_init fib_proc_init(struct net *net) { - if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, + if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && + !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, sizeof(struct fib_trie_iter))) goto out1; - if (!proc_create_net_single("fib_triestat", 0444, net->proc_net, + if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && + !proc_create_net_single("fib_triestat", 0444, net->proc_net, fib_triestat_seq_show, NULL)) goto out2; @@ -3030,17 +3032,21 @@ int __net_init fib_proc_init(struct net *net) return 0; out3: - remove_proc_entry("fib_triestat", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) + remove_proc_entry("fib_triestat", net->proc_net); out2: - remove_proc_entry("fib_trie", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) + remove_proc_entry("fib_trie", net->proc_net); out1: return -ENOMEM; } void __net_exit fib_proc_exit(struct net *net) { - remove_proc_entry("fib_trie", net->proc_net); - remove_proc_entry("fib_triestat", net->proc_net); + if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { + remove_proc_entry("fib_trie", net->proc_net); + remove_proc_entry("fib_triestat", net->proc_net); + } remove_proc_entry("route", net->proc_net); } diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 337390ba85b4..a03d02dca981 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -296,7 +296,7 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm) */ if (!rearm) { - bool kill = timeo <= 4*HZ; + bool __maybe_unused kill = timeo <= 4*HZ; __NET_INC_STATS(twsk_net(tw), kill ? LINUX_MIB_TIMEWAITKILLED : LINUX_MIB_TIMEWAITED); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 40053a02bae1..3e32011883f3 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -563,5 +563,8 @@ static __net_initdata struct pernet_operations ip_proc_ops = { int __init ip_misc_proc_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; + return register_pernet_subsys(&ip_proc_ops); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7d04df4fc660..a27025ff7b20 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -382,6 +382,9 @@ static struct pernet_operations ip_rt_proc_ops __net_initdata = { static int __init ip_rt_proc_init(void) { + if (IS_ENABLED(CONFIG_PROC_STRIPPED)) + return 0; + return register_pernet_subsys(&ip_rt_proc_ops); } -- 2.51.0 From 367044524b89a67e491b9fa119b1ba2fc7a7d560 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Jul 2017 08:20:43 +0200 Subject: [PATCH 379/517] debloat: dmabuf Signed-off-by: Felix Fietkau --- drivers/base/Kconfig | 2 +- drivers/dma-buf/Makefile | 20 ++++++++++++-------- drivers/dma-buf/dma-buf.c | 3 ++- drivers/dma-buf/heaps/Makefile | 4 ++-- fs/d_path.c | 1 + kernel/sched/core.c | 1 + net/Kconfig | 2 +- 7 files changed, 20 insertions(+), 13 deletions(-) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 064eb52ff7e2..f17614172bf7 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -198,7 +198,7 @@ config SOC_BUS source "drivers/base/regmap/Kconfig" config DMA_SHARED_BUFFER - bool + tristate default n select IRQ_WORK help diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 70ec901edf2c..4efa1df475f0 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,12 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ +obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o + +dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ dma-fence-unwrap.o dma-resv.o -obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o -obj-$(CONFIG_DMABUF_HEAPS) += heaps/ -obj-$(CONFIG_SYNC_FILE) += sync_file.o -obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o -obj-$(CONFIG_UDMABUF) += udmabuf.o -obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o +dma-buf-objs-$(CONFIG_DMABUF_HEAPS) += dma-heap.o +obj-$(CONFIG_DMABUF_HEAPS) += heaps/ +dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o +dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o +dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o dmabuf_selftests-y := \ selftest.o \ @@ -15,4 +17,6 @@ dmabuf_selftests-y := \ st-dma-fence-unwrap.o \ st-dma-resv.o -obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o +dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o + +dma-shared-buffer-objs := $(dma-buf-objs-y) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index afb8c1c50107..f2e5dd69b100 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -1743,4 +1743,5 @@ static void __exit dma_buf_deinit(void) kern_unmount(dma_buf_mnt); dma_buf_uninit_sysfs_statistics(); } -__exitcall(dma_buf_deinit); +module_exit(dma_buf_deinit); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma-buf/heaps/Makefile b/drivers/dma-buf/heaps/Makefile index 974467791032..87f71c3ee6fb 100644 --- a/drivers/dma-buf/heaps/Makefile +++ b/drivers/dma-buf/heaps/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o -obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o diff --git a/fs/d_path.c b/fs/d_path.c index 5f4da5c8d5db..69d49d7ab260 100644 --- a/fs/d_path.c +++ b/fs/d_path.c @@ -314,6 +314,7 @@ char *dynamic_dname(char *buffer, int buflen, const char *fmt, ...) buffer += buflen - sz; return memcpy(buffer, temp, sz); } +EXPORT_SYMBOL_GPL(dynamic_dname); char *simple_dname(struct dentry *dentry, char *buffer, int buflen) { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4b1953b6c76a..ca7ee02dc916 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4433,6 +4433,7 @@ int wake_up_state(struct task_struct *p, unsigned int state) { return try_to_wake_up(p, state, 0); } +EXPORT_SYMBOL_GPL(wake_up_state); /* * Perform scheduler related setup for a newly forked process p. diff --git a/net/Kconfig b/net/Kconfig index b1afb23fe2fb..5f179d2e74c2 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -74,7 +74,7 @@ config SKB_EXTENSIONS config NET_DEVMEM def_bool y - depends on DMA_SHARED_BUFFER + depends on DMA_SHARED_BUFFER=y depends on GENERIC_ALLOCATOR depends on PAGE_POOL -- 2.51.0 From 9856b0a5865ac77a4941f011da93921ca0a1fff4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 16 Jul 2017 16:56:10 +0200 Subject: [PATCH 380/517] lib: add uevent_next_seqnum() Signed-off-by: Felix Fietkau --- include/linux/kobject.h | 2 ++ lib/kobject_uevent.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c8219505a79f..f9c97c9b9847 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -219,4 +219,6 @@ int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count); __printf(2, 3) int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); +u64 uevent_next_seqnum(void); + #endif /* _KOBJECT_H_ */ diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index b7f2fa08d9c8..788d8959a2d3 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -178,6 +178,12 @@ static int kobject_action_args(const char *buf, size_t count, return r; } +u64 uevent_next_seqnum(void) +{ + return atomic64_inc_return(&uevent_seqnum); +} +EXPORT_SYMBOL_GPL(uevent_next_seqnum); + /** * kobject_synth_uevent - send synthetic uevent with arguments * -- 2.51.0 From 84376022c24166ef12e2aff2b845a31f29fd43bf Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 16 Jul 2017 16:56:10 +0200 Subject: [PATCH 381/517] lib: add broadcast_uevent() Signed-off-by: Felix Fietkau --- include/linux/kobject.h | 5 +++++ lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/linux/kobject.h b/include/linux/kobject.h index f9c97c9b9847..08d4818586b6 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -32,6 +32,8 @@ #define UEVENT_NUM_ENVP 64 /* number of env pointers */ #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ +struct sk_buff; + #ifdef CONFIG_UEVENT_HELPER /* path to the userspace helper executed on an event */ extern char uevent_helper[]; @@ -221,4 +223,7 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); u64 uevent_next_seqnum(void); +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, + gfp_t allocation); + #endif /* _KOBJECT_H_ */ diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 788d8959a2d3..2716e02169d6 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -698,6 +698,43 @@ int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) } EXPORT_SYMBOL_GPL(add_uevent_var); +#if defined(CONFIG_NET) +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, + gfp_t allocation) +{ + struct uevent_sock *ue_sk; + int err = 0; + + /* send netlink message */ + mutex_lock(&uevent_sock_mutex); + list_for_each_entry(ue_sk, &uevent_sock_list, list) { + struct sock *uevent_sock = ue_sk->sk; + struct sk_buff *skb2; + + skb2 = skb_clone(skb, allocation); + if (!skb2) + break; + + err = netlink_broadcast(uevent_sock, skb2, pid, group, + allocation); + if (err) + break; + } + mutex_unlock(&uevent_sock_mutex); + + kfree_skb(skb); + return err; +} +#else +int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, + gfp_t allocation) +{ + kfree_skb(skb); + return 0; +} +#endif +EXPORT_SYMBOL_GPL(broadcast_uevent); + #if defined(CONFIG_NET) static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, struct netlink_ext_ack *extack) -- 2.51.0 From 809764a8e59e218960291427c0dfc3fec03896de Mon Sep 17 00:00:00 2001 From: OpenWrt community Date: Wed, 13 Jul 2022 13:52:28 +0200 Subject: [PATCH 382/517] of/ftd: add device tree cmdline --- drivers/of/fdt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 8c80f4dc8b3f..500807cccee4 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1049,6 +1049,9 @@ int __init early_init_dt_scan_chosen(char *cmdline) p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); + p = of_get_flat_dt_prop(node, "bootargs-append", &l); + if (p != NULL && l > 0) + strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); handle_cmdline: /* -- 2.51.0 From f9ab6c46d9c89e908775d62b0104f5a370a66023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Jul 2022 06:17:48 +0200 Subject: [PATCH 383/517] Revert "Revert "Revert "driver core: Set fw_devlink=on by default""" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ea718c699055c8566eb64432388a04974c43b2ea. With of_platform_populate() called for MTD partitions that commit breaks probing devices which reference MTD in device tree. Link: https://lore.kernel.org/all/696cb2da-20b9-b3dd-46d9-de4bf91a1506@gmail.com/T/#u Signed-off-by: Rafał Miłecki --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index ba9b4cbef9e0..4bbd4c2c9448 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1653,7 +1653,7 @@ static void device_links_purge(struct device *dev) #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \ DL_FLAG_PM_RUNTIME) -static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_RPM; +static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE; static int __init fw_devlink_setup(char *arg) { if (!arg) -- 2.51.0 From 0d4da66db0ee983798e8a0fc412539cdf4c8003a Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 17 Dec 2024 09:54:26 +0100 Subject: [PATCH 384/517] pinctrl: mediatek: add support for MTK_PULL_PD_TYPE The MediaTek MT7988 SoC got some pins which only got configurable pull-down but unlike previous designs there is no pull-up option. Add new type MTK_PULL_PD_TYPE to support configuring such pins. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/20241217085435.9586-2-linux@fw-web.de Signed-off-by: Linus Walleij --- .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 73 ++++++++++++++++--- .../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 + 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c index 54301fbba524..7b704cc55c9f 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_rev1); */ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, - u32 pullup, u32 arg) + u32 pullup, u32 arg, bool pd_only) { int err, pu, pd; @@ -587,18 +587,34 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, pu = 0; pd = 1; } else { - err = -EINVAL; - goto out; + return -EINVAL; } - err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); - if (err) - goto out; + if (!pd_only) { + err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu); + if (err) + return err; + } - err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); +} + +static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + u32 pullup, u32 arg) +{ + int err, pd; + + if (arg != MTK_DISABLE && arg != MTK_ENABLE) + return -EINVAL; + + if (arg == MTK_DISABLE || pullup) + pd = 0; + else if (!pullup) + pd = 1; + + return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); -out: - return err; } static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, @@ -737,7 +753,7 @@ static int mtk_pinconf_bias_set_pu_pd_rsel(struct mtk_pinctrl *hw, return err; } - return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable); + return mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, enable, false); } int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, @@ -758,8 +774,14 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw, return 0; } + if (try_all_type & MTK_PULL_PD_TYPE) { + err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg, true); + if (!err) + return err; + } + if (try_all_type & MTK_PULL_PU_PD_TYPE) { - err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg); + err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg, false); if (!err) return 0; } @@ -878,6 +900,29 @@ static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw, return err; } +static int mtk_pinconf_bias_get_pd(struct mtk_pinctrl *hw, + const struct mtk_pin_desc *desc, + u32 *pullup, u32 *enable) +{ + int err, pd; + + err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd); + if (err) + goto out; + + if (pd == 0) { + *pullup = 0; + *enable = MTK_DISABLE; + } else if (pd == 1) { + *pullup = 0; + *enable = MTK_ENABLE; + } else + err = -EINVAL; + +out: + return err; +} + static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, u32 *pullup, u32 *enable) @@ -947,6 +992,12 @@ int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw, return 0; } + if (try_all_type & MTK_PULL_PD_TYPE) { + err = mtk_pinconf_bias_get_pd(hw, desc, pullup, enable); + if (!err) + return err; + } + if (try_all_type & MTK_PULL_PU_PD_TYPE) { err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable); if (!err) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h index 23688ca6d04e..9c271dc2b521 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h @@ -24,6 +24,7 @@ * turned on/off itself. But it can't be selected pull up/down */ #define MTK_PULL_RSEL_TYPE BIT(3) +#define MTK_PULL_PD_TYPE BIT(4) /* MTK_PULL_PU_PD_RSEL_TYPE is a type which is controlled by * MTK_PULL_PU_PD_TYPE and MTK_PULL_RSEL_TYPE. */ -- 2.51.0 From 9f6832a6bcf3fa5ef863246b5ae17537433342a8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 17 Dec 2024 09:54:27 +0100 Subject: [PATCH 385/517] pinctrl: mediatek: add MT7988 pinctrl driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add pinctrl driver for the MediaTek MT7988 SoC. Signed-off-by: Sam Shih Signed-off-by: Daniel Golle [correctly initialise for the function_desc structure] Signed-off-by: Arınç ÜNAL Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/20241217085435.9586-3-linux@fw-web.de Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/Kconfig | 7 + drivers/pinctrl/mediatek/Makefile | 1 + drivers/pinctrl/mediatek/pinctrl-mt7988.c | 1556 +++++++++++++++++++++ 3 files changed, 1564 insertions(+) create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7988.c diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index 7af287252834..952110c783d4 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -187,6 +187,13 @@ config PINCTRL_MT7986 default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_MOORE +config PINCTRL_MT7988 + bool "Mediatek MT7988 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_MOORE + config PINCTRL_MT8167 bool "MediaTek MT8167 pin control" depends on OF diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 680f7e8526e0..2b47ce030b54 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o +obj-$(CONFIG_PINCTRL_MT7988) += pinctrl-mt7988.o obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/drivers/pinctrl/mediatek/pinctrl-mt7988.c new file mode 100644 index 000000000000..68b4097792b8 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7988.c @@ -0,0 +1,1556 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The MT7988 driver based on Linux generic pinctrl binding. + * + * Copyright (C) 2020 MediaTek Inc. + * Author: Sam Shih + */ + +#include "pinctrl-moore.h" + +enum mt7988_pinctrl_reg_page { + GPIO_BASE, + IOCFG_TR_BASE, + IOCFG_BR_BASE, + IOCFG_RB_BASE, + IOCFG_LB_BASE, + IOCFG_TL_BASE, +}; + +#define MT7988_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4) + +#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +static const struct mtk_pin_field_calc mt7988_pin_mode_range[] = { + PIN_FIELD(0, 83, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt7988_pin_dir_range[] = { + PIN_FIELD(0, 83, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_di_range[] = { + PIN_FIELD(0, 83, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_do_range[] = { + PIN_FIELD(0, 83, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_ies_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0x30, 0x10, 13, 1), + PIN_FIELD_BASE(1, 1, 5, 0x30, 0x10, 14, 1), + PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 11, 1), + PIN_FIELD_BASE(3, 3, 5, 0x30, 0x10, 12, 1), + PIN_FIELD_BASE(4, 4, 5, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(5, 5, 5, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(6, 6, 5, 0x30, 0x10, 10, 1), + + PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(10, 10, 4, 0x30, 0x10, 3, 1), + + PIN_FIELD_BASE(11, 11, 1, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x40, 0x10, 21, 1), + PIN_FIELD_BASE(13, 13, 1, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(14, 14, 1, 0x40, 0x10, 2, 1), + + PIN_FIELD_BASE(15, 15, 5, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(16, 16, 5, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(17, 17, 5, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(18, 18, 5, 0x30, 0x10, 4, 1), + + PIN_FIELD_BASE(19, 19, 4, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(20, 20, 4, 0x30, 0x10, 4, 1), + + PIN_FIELD_BASE(21, 21, 3, 0x50, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x50, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x50, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x50, 0x10, 19, 1), + PIN_FIELD_BASE(25, 25, 3, 0x50, 0x10, 21, 1), + PIN_FIELD_BASE(26, 26, 3, 0x50, 0x10, 22, 1), + PIN_FIELD_BASE(27, 27, 3, 0x50, 0x10, 18, 1), + PIN_FIELD_BASE(28, 28, 3, 0x50, 0x10, 25, 1), + PIN_FIELD_BASE(29, 29, 3, 0x50, 0x10, 26, 1), + PIN_FIELD_BASE(30, 30, 3, 0x50, 0x10, 27, 1), + PIN_FIELD_BASE(31, 31, 3, 0x50, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x50, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 31, 1), + PIN_FIELD_BASE(35, 35, 3, 0x50, 0x10, 29, 1), + PIN_FIELD_BASE(36, 36, 3, 0x50, 0x10, 30, 1), + PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x50, 0x10, 10, 1), + PIN_FIELD_BASE(40, 40, 3, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 3, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(42, 42, 3, 0x50, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x50, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x50, 0x10, 15, 1), + PIN_FIELD_BASE(51, 51, 3, 0x50, 0x10, 12, 1), + PIN_FIELD_BASE(52, 52, 3, 0x50, 0x10, 13, 1), + PIN_FIELD_BASE(53, 53, 3, 0x50, 0x10, 14, 1), + PIN_FIELD_BASE(54, 54, 3, 0x50, 0x10, 16, 1), + + PIN_FIELD_BASE(55, 55, 1, 0x40, 0x10, 14, 1), + PIN_FIELD_BASE(56, 56, 1, 0x40, 0x10, 15, 1), + PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 13, 1), + PIN_FIELD_BASE(58, 58, 1, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(59, 59, 1, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(60, 60, 1, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(62, 62, 1, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(63, 63, 1, 0x40, 0x10, 20, 1), + PIN_FIELD_BASE(64, 64, 1, 0x40, 0x10, 8, 1), + PIN_FIELD_BASE(65, 65, 1, 0x40, 0x10, 9, 1), + PIN_FIELD_BASE(66, 66, 1, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(67, 67, 1, 0x40, 0x10, 11, 1), + PIN_FIELD_BASE(68, 68, 1, 0x40, 0x10, 12, 1), + + PIN_FIELD_BASE(69, 69, 5, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(70, 70, 5, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(71, 71, 5, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0x30, 0x10, 6, 1), + + PIN_FIELD_BASE(73, 73, 4, 0x30, 0x10, 10, 1), + PIN_FIELD_BASE(74, 74, 4, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(75, 75, 4, 0x30, 0x10, 11, 1), + PIN_FIELD_BASE(76, 76, 4, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(77, 77, 4, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(78, 78, 4, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x30, 0x10, 12, 1), + + PIN_FIELD_BASE(80, 80, 1, 0x40, 0x10, 18, 1), + PIN_FIELD_BASE(81, 81, 1, 0x40, 0x10, 19, 1), + PIN_FIELD_BASE(82, 82, 1, 0x40, 0x10, 16, 1), + PIN_FIELD_BASE(83, 83, 1, 0x40, 0x10, 17, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_smt_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0xc0, 0x10, 13, 1), + PIN_FIELD_BASE(1, 1, 5, 0xc0, 0x10, 14, 1), + PIN_FIELD_BASE(2, 2, 5, 0xc0, 0x10, 11, 1), + PIN_FIELD_BASE(3, 3, 5, 0xc0, 0x10, 12, 1), + PIN_FIELD_BASE(4, 4, 5, 0xc0, 0x10, 0, 1), + PIN_FIELD_BASE(5, 5, 5, 0xc0, 0x10, 9, 1), + PIN_FIELD_BASE(6, 6, 5, 0xc0, 0x10, 10, 1), + + PIN_FIELD_BASE(7, 7, 4, 0xb0, 0x10, 8, 1), + PIN_FIELD_BASE(8, 8, 4, 0xb0, 0x10, 6, 1), + PIN_FIELD_BASE(9, 9, 4, 0xb0, 0x10, 5, 1), + PIN_FIELD_BASE(10, 10, 4, 0xb0, 0x10, 3, 1), + + PIN_FIELD_BASE(11, 11, 1, 0xe0, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0xe0, 0x10, 21, 1), + PIN_FIELD_BASE(13, 13, 1, 0xe0, 0x10, 1, 1), + PIN_FIELD_BASE(14, 14, 1, 0xe0, 0x10, 2, 1), + + PIN_FIELD_BASE(15, 15, 5, 0xc0, 0x10, 7, 1), + PIN_FIELD_BASE(16, 16, 5, 0xc0, 0x10, 8, 1), + PIN_FIELD_BASE(17, 17, 5, 0xc0, 0x10, 3, 1), + PIN_FIELD_BASE(18, 18, 5, 0xc0, 0x10, 4, 1), + + PIN_FIELD_BASE(19, 19, 4, 0xb0, 0x10, 7, 1), + PIN_FIELD_BASE(20, 20, 4, 0xb0, 0x10, 4, 1), + + PIN_FIELD_BASE(21, 21, 3, 0x140, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x140, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x140, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x140, 0x10, 19, 1), + PIN_FIELD_BASE(25, 25, 3, 0x140, 0x10, 21, 1), + PIN_FIELD_BASE(26, 26, 3, 0x140, 0x10, 22, 1), + PIN_FIELD_BASE(27, 27, 3, 0x140, 0x10, 18, 1), + PIN_FIELD_BASE(28, 28, 3, 0x140, 0x10, 25, 1), + PIN_FIELD_BASE(29, 29, 3, 0x140, 0x10, 26, 1), + PIN_FIELD_BASE(30, 30, 3, 0x140, 0x10, 27, 1), + PIN_FIELD_BASE(31, 31, 3, 0x140, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x140, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x150, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x140, 0x10, 31, 1), + PIN_FIELD_BASE(35, 35, 3, 0x140, 0x10, 29, 1), + PIN_FIELD_BASE(36, 36, 3, 0x140, 0x10, 30, 1), + PIN_FIELD_BASE(37, 37, 3, 0x150, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x140, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x140, 0x10, 10, 1), + PIN_FIELD_BASE(40, 40, 3, 0x140, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 3, 0x140, 0x10, 1, 1), + PIN_FIELD_BASE(42, 42, 3, 0x140, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x140, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x140, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x140, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x140, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x140, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x140, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x140, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x140, 0x10, 15, 1), + PIN_FIELD_BASE(51, 51, 3, 0x140, 0x10, 12, 1), + PIN_FIELD_BASE(52, 52, 3, 0x140, 0x10, 13, 1), + PIN_FIELD_BASE(53, 53, 3, 0x140, 0x10, 14, 1), + PIN_FIELD_BASE(54, 54, 3, 0x140, 0x10, 16, 1), + + PIN_FIELD_BASE(55, 55, 1, 0xe0, 0x10, 14, 1), + PIN_FIELD_BASE(56, 56, 1, 0xe0, 0x10, 15, 1), + PIN_FIELD_BASE(57, 57, 1, 0xe0, 0x10, 13, 1), + PIN_FIELD_BASE(58, 58, 1, 0xe0, 0x10, 4, 1), + PIN_FIELD_BASE(59, 59, 1, 0xe0, 0x10, 5, 1), + PIN_FIELD_BASE(60, 60, 1, 0xe0, 0x10, 6, 1), + PIN_FIELD_BASE(61, 61, 1, 0xe0, 0x10, 3, 1), + PIN_FIELD_BASE(62, 62, 1, 0xe0, 0x10, 7, 1), + PIN_FIELD_BASE(63, 63, 1, 0xe0, 0x10, 20, 1), + PIN_FIELD_BASE(64, 64, 1, 0xe0, 0x10, 8, 1), + PIN_FIELD_BASE(65, 65, 1, 0xe0, 0x10, 9, 1), + PIN_FIELD_BASE(66, 66, 1, 0xe0, 0x10, 10, 1), + PIN_FIELD_BASE(67, 67, 1, 0xe0, 0x10, 11, 1), + PIN_FIELD_BASE(68, 68, 1, 0xe0, 0x10, 12, 1), + + PIN_FIELD_BASE(69, 69, 5, 0xc0, 0x10, 1, 1), + PIN_FIELD_BASE(70, 70, 5, 0xc0, 0x10, 2, 1), + PIN_FIELD_BASE(71, 71, 5, 0xc0, 0x10, 5, 1), + PIN_FIELD_BASE(72, 72, 5, 0xc0, 0x10, 6, 1), + + PIN_FIELD_BASE(73, 73, 4, 0xb0, 0x10, 10, 1), + PIN_FIELD_BASE(74, 74, 4, 0xb0, 0x10, 1, 1), + PIN_FIELD_BASE(75, 75, 4, 0xb0, 0x10, 11, 1), + PIN_FIELD_BASE(76, 76, 4, 0xb0, 0x10, 9, 1), + PIN_FIELD_BASE(77, 77, 4, 0xb0, 0x10, 2, 1), + PIN_FIELD_BASE(78, 78, 4, 0xb0, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0xb0, 0x10, 12, 1), + + PIN_FIELD_BASE(80, 80, 1, 0xe0, 0x10, 18, 1), + PIN_FIELD_BASE(81, 81, 1, 0xe0, 0x10, 19, 1), + PIN_FIELD_BASE(82, 82, 1, 0xe0, 0x10, 16, 1), + PIN_FIELD_BASE(83, 83, 1, 0xe0, 0x10, 17, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pu_range[] = { + PIN_FIELD_BASE(7, 7, 4, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 4, 0x60, 0x10, 4, 1), + PIN_FIELD_BASE(9, 9, 4, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(10, 10, 4, 0x60, 0x10, 2, 1), + + PIN_FIELD_BASE(13, 13, 1, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(14, 14, 1, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(63, 63, 1, 0x70, 0x10, 2, 1), + + PIN_FIELD_BASE(75, 75, 4, 0x60, 0x10, 7, 1), + PIN_FIELD_BASE(76, 76, 4, 0x60, 0x10, 6, 1), + PIN_FIELD_BASE(77, 77, 4, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(78, 78, 4, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x60, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pd_range[] = { + PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(10, 10, 4, 0x40, 0x10, 2, 1), + + PIN_FIELD_BASE(13, 13, 1, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(14, 14, 1, 0x50, 0x10, 1, 1), + + PIN_FIELD_BASE(15, 15, 5, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(16, 16, 5, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(17, 17, 5, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(18, 18, 5, 0x40, 0x10, 1, 1), + + PIN_FIELD_BASE(63, 63, 1, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(71, 71, 5, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(72, 72, 5, 0x40, 0x10, 3, 1), + + PIN_FIELD_BASE(75, 75, 4, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(76, 76, 4, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(77, 77, 4, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(78, 78, 4, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x40, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_drv_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(1, 1, 5, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(3, 3, 5, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(4, 4, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(5, 5, 5, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(6, 6, 5, 0x00, 0x10, 12, 3), + + PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 28, 3), + PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(10, 10, 4, 0x00, 0x10, 9, 3), + + PIN_FIELD_BASE(11, 11, 1, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(12, 12, 1, 0x20, 0x10, 3, 3), + PIN_FIELD_BASE(13, 13, 1, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(14, 14, 1, 0x00, 0x10, 6, 3), + + PIN_FIELD_BASE(19, 19, 4, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(20, 20, 4, 0x00, 0x10, 12, 3), + + PIN_FIELD_BASE(21, 21, 3, 0x10, 0x10, 21, 3), + PIN_FIELD_BASE(22, 22, 3, 0x20, 0x10, 9, 3), + PIN_FIELD_BASE(23, 23, 3, 0x20, 0x10, 0, 3), + PIN_FIELD_BASE(24, 24, 3, 0x10, 0x10, 27, 3), + PIN_FIELD_BASE(25, 25, 3, 0x20, 0x10, 3, 3), + PIN_FIELD_BASE(26, 26, 3, 0x20, 0x10, 6, 3), + PIN_FIELD_BASE(27, 27, 3, 0x10, 0x10, 24, 3), + PIN_FIELD_BASE(28, 28, 3, 0x20, 0x10, 15, 3), + PIN_FIELD_BASE(29, 29, 3, 0x20, 0x10, 18, 3), + PIN_FIELD_BASE(30, 30, 3, 0x20, 0x10, 21, 3), + PIN_FIELD_BASE(31, 31, 3, 0x20, 0x10, 12, 3), + PIN_FIELD_BASE(32, 32, 3, 0x20, 0x10, 24, 3), + PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 6, 3), + PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 3, 3), + PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 27, 3), + PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 0, 3), + PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 9, 3), + PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 3, 3), + PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(40, 40, 3, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(41, 41, 3, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(42, 42, 3, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(43, 43, 3, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(44, 44, 3, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(45, 45, 3, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(46, 46, 3, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(47, 47, 3, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(48, 48, 3, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(49, 49, 3, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(50, 50, 3, 0x10, 0x10, 15, 3), + PIN_FIELD_BASE(51, 51, 3, 0x10, 0x10, 6, 3), + PIN_FIELD_BASE(52, 52, 3, 0x10, 0x10, 9, 3), + PIN_FIELD_BASE(53, 53, 3, 0x10, 0x10, 12, 3), + PIN_FIELD_BASE(54, 54, 3, 0x10, 0x10, 18, 3), + + PIN_FIELD_BASE(55, 55, 1, 0x10, 0x10, 12, 3), + PIN_FIELD_BASE(56, 56, 1, 0x10, 0x10, 15, 3), + PIN_FIELD_BASE(57, 57, 1, 0x10, 0x10, 9, 3), + PIN_FIELD_BASE(58, 58, 1, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(59, 59, 1, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(60, 60, 1, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(61, 61, 1, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(62, 62, 1, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(63, 63, 1, 0x20, 0x10, 0, 3), + PIN_FIELD_BASE(64, 64, 1, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(65, 65, 1, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(66, 66, 1, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(67, 67, 1, 0x10, 0x10, 3, 3), + PIN_FIELD_BASE(68, 68, 1, 0x10, 0x10, 6, 3), + + PIN_FIELD_BASE(69, 69, 5, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(70, 70, 5, 0x00, 0x10, 6, 3), + + PIN_FIELD_BASE(73, 73, 4, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(74, 74, 4, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(75, 75, 4, 0x10, 0x10, 3, 3), + PIN_FIELD_BASE(76, 76, 4, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(77, 77, 4, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(78, 78, 4, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(79, 79, 4, 0x10, 0x10, 6, 3), + + PIN_FIELD_BASE(80, 80, 1, 0x10, 0x10, 24, 3), + PIN_FIELD_BASE(81, 81, 1, 0x10, 0x10, 27, 3), + PIN_FIELD_BASE(82, 82, 1, 0x10, 0x10, 18, 3), + PIN_FIELD_BASE(83, 83, 1, 0x10, 0x10, 21, 3), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pupd_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(1, 1, 5, 0x50, 0x10, 8, 1), + PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(3, 3, 5, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 5, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(5, 5, 5, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(6, 6, 5, 0x50, 0x10, 4, 1), + + PIN_FIELD_BASE(11, 11, 1, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x60, 0x10, 18, 1), + + PIN_FIELD_BASE(19, 19, 4, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x50, 0x10, 1, 1), + + PIN_FIELD_BASE(21, 21, 3, 0x70, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x70, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x70, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x70, 0x10, 19, 1), + PIN_FIELD_BASE(25, 25, 3, 0x70, 0x10, 21, 1), + PIN_FIELD_BASE(26, 26, 3, 0x70, 0x10, 22, 1), + PIN_FIELD_BASE(27, 27, 3, 0x70, 0x10, 18, 1), + PIN_FIELD_BASE(28, 28, 3, 0x70, 0x10, 25, 1), + PIN_FIELD_BASE(29, 29, 3, 0x70, 0x10, 26, 1), + PIN_FIELD_BASE(30, 30, 3, 0x70, 0x10, 27, 1), + PIN_FIELD_BASE(31, 31, 3, 0x70, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x70, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x70, 0x10, 31, 1), + PIN_FIELD_BASE(35, 35, 3, 0x70, 0x10, 29, 1), + PIN_FIELD_BASE(36, 36, 3, 0x70, 0x10, 30, 1), + PIN_FIELD_BASE(37, 37, 3, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x70, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x70, 0x10, 10, 1), + PIN_FIELD_BASE(40, 40, 3, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 3, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(42, 42, 3, 0x70, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x70, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x70, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x70, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x70, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x70, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x70, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x70, 0x10, 15, 1), + PIN_FIELD_BASE(51, 51, 3, 0x70, 0x10, 12, 1), + PIN_FIELD_BASE(52, 52, 3, 0x70, 0x10, 13, 1), + PIN_FIELD_BASE(53, 53, 3, 0x70, 0x10, 14, 1), + PIN_FIELD_BASE(54, 54, 3, 0x70, 0x10, 16, 1), + + PIN_FIELD_BASE(55, 55, 1, 0x60, 0x10, 12, 1), + PIN_FIELD_BASE(56, 56, 1, 0x60, 0x10, 13, 1), + PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 11, 1), + PIN_FIELD_BASE(58, 58, 1, 0x60, 0x10, 2, 1), + PIN_FIELD_BASE(59, 59, 1, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(60, 60, 1, 0x60, 0x10, 4, 1), + PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(64, 64, 1, 0x60, 0x10, 6, 1), + PIN_FIELD_BASE(65, 65, 1, 0x60, 0x10, 7, 1), + PIN_FIELD_BASE(66, 66, 1, 0x60, 0x10, 8, 1), + PIN_FIELD_BASE(67, 67, 1, 0x60, 0x10, 9, 1), + PIN_FIELD_BASE(68, 68, 1, 0x60, 0x10, 10, 1), + + PIN_FIELD_BASE(69, 69, 5, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(70, 70, 5, 0x50, 0x10, 2, 1), + + PIN_FIELD_BASE(73, 73, 4, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x50, 0x10, 0, 1), + + PIN_FIELD_BASE(80, 80, 1, 0x60, 0x10, 16, 1), + PIN_FIELD_BASE(81, 81, 1, 0x60, 0x10, 17, 1), + PIN_FIELD_BASE(82, 82, 1, 0x60, 0x10, 14, 1), + PIN_FIELD_BASE(83, 83, 1, 0x60, 0x10, 15, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_r0_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0x60, 0x10, 7, 1), + PIN_FIELD_BASE(1, 1, 5, 0x60, 0x10, 8, 1), + PIN_FIELD_BASE(2, 2, 5, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(3, 3, 5, 0x60, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 5, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(5, 5, 5, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(6, 6, 5, 0x60, 0x10, 4, 1), + + PIN_FIELD_BASE(11, 11, 1, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x80, 0x10, 18, 1), + + PIN_FIELD_BASE(19, 19, 4, 0x70, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x70, 0x10, 1, 1), + + PIN_FIELD_BASE(21, 21, 3, 0x90, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x90, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x90, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x90, 0x10, 19, 1), + PIN_FIELD_BASE(25, 25, 3, 0x90, 0x10, 21, 1), + PIN_FIELD_BASE(26, 26, 3, 0x90, 0x10, 22, 1), + PIN_FIELD_BASE(27, 27, 3, 0x90, 0x10, 18, 1), + PIN_FIELD_BASE(28, 28, 3, 0x90, 0x10, 25, 1), + PIN_FIELD_BASE(29, 29, 3, 0x90, 0x10, 26, 1), + PIN_FIELD_BASE(30, 30, 3, 0x90, 0x10, 27, 1), + PIN_FIELD_BASE(31, 31, 3, 0x90, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x90, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0xa0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 31, 1), + PIN_FIELD_BASE(35, 35, 3, 0x90, 0x10, 29, 1), + PIN_FIELD_BASE(36, 36, 3, 0x90, 0x10, 30, 1), + PIN_FIELD_BASE(37, 37, 3, 0xa0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x90, 0x10, 10, 1), + PIN_FIELD_BASE(40, 40, 3, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 3, 0x90, 0x10, 1, 1), + PIN_FIELD_BASE(42, 42, 3, 0x90, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x90, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x90, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x90, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x90, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x90, 0x10, 15, 1), + PIN_FIELD_BASE(51, 51, 3, 0x90, 0x10, 12, 1), + PIN_FIELD_BASE(52, 52, 3, 0x90, 0x10, 13, 1), + PIN_FIELD_BASE(53, 53, 3, 0x90, 0x10, 14, 1), + PIN_FIELD_BASE(54, 54, 3, 0x90, 0x10, 16, 1), + + PIN_FIELD_BASE(55, 55, 1, 0x80, 0x10, 12, 1), + PIN_FIELD_BASE(56, 56, 1, 0x80, 0x10, 13, 1), + PIN_FIELD_BASE(57, 57, 1, 0x80, 0x10, 11, 1), + PIN_FIELD_BASE(58, 58, 1, 0x80, 0x10, 2, 1), + PIN_FIELD_BASE(59, 59, 1, 0x80, 0x10, 3, 1), + PIN_FIELD_BASE(60, 60, 1, 0x80, 0x10, 4, 1), + PIN_FIELD_BASE(61, 61, 1, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x80, 0x10, 5, 1), + PIN_FIELD_BASE(64, 64, 1, 0x80, 0x10, 6, 1), + PIN_FIELD_BASE(65, 65, 1, 0x80, 0x10, 7, 1), + PIN_FIELD_BASE(66, 66, 1, 0x80, 0x10, 8, 1), + PIN_FIELD_BASE(67, 67, 1, 0x80, 0x10, 9, 1), + PIN_FIELD_BASE(68, 68, 1, 0x80, 0x10, 10, 1), + + PIN_FIELD_BASE(69, 69, 5, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(70, 70, 5, 0x60, 0x10, 2, 1), + + PIN_FIELD_BASE(73, 73, 4, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x70, 0x10, 0, 1), + + PIN_FIELD_BASE(80, 80, 1, 0x80, 0x10, 16, 1), + PIN_FIELD_BASE(81, 81, 1, 0x80, 0x10, 17, 1), + PIN_FIELD_BASE(82, 82, 1, 0x80, 0x10, 14, 1), + PIN_FIELD_BASE(83, 83, 1, 0x80, 0x10, 15, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_r1_range[] = { + PIN_FIELD_BASE(0, 0, 5, 0x70, 0x10, 7, 1), + PIN_FIELD_BASE(1, 1, 5, 0x70, 0x10, 8, 1), + PIN_FIELD_BASE(2, 2, 5, 0x70, 0x10, 5, 1), + PIN_FIELD_BASE(3, 3, 5, 0x70, 0x10, 6, 1), + PIN_FIELD_BASE(4, 4, 5, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(5, 5, 5, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(6, 6, 5, 0x70, 0x10, 4, 1), + + PIN_FIELD_BASE(11, 11, 1, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x90, 0x10, 18, 1), + + PIN_FIELD_BASE(19, 19, 4, 0x80, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x80, 0x10, 1, 1), + + PIN_FIELD_BASE(21, 21, 3, 0xb0, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0xb0, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0xb0, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0xb0, 0x10, 19, 1), + PIN_FIELD_BASE(25, 25, 3, 0xb0, 0x10, 21, 1), + PIN_FIELD_BASE(26, 26, 3, 0xb0, 0x10, 22, 1), + PIN_FIELD_BASE(27, 27, 3, 0xb0, 0x10, 18, 1), + PIN_FIELD_BASE(28, 28, 3, 0xb0, 0x10, 25, 1), + PIN_FIELD_BASE(29, 29, 3, 0xb0, 0x10, 26, 1), + PIN_FIELD_BASE(30, 30, 3, 0xb0, 0x10, 27, 1), + PIN_FIELD_BASE(31, 31, 3, 0xb0, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0xb0, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0xc0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0xb0, 0x10, 31, 1), + PIN_FIELD_BASE(35, 35, 3, 0xb0, 0x10, 29, 1), + PIN_FIELD_BASE(36, 36, 3, 0xb0, 0x10, 30, 1), + PIN_FIELD_BASE(37, 37, 3, 0xc0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0xb0, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0xb0, 0x10, 10, 1), + PIN_FIELD_BASE(40, 40, 3, 0xb0, 0x10, 0, 1), + PIN_FIELD_BASE(41, 41, 3, 0xb0, 0x10, 1, 1), + PIN_FIELD_BASE(42, 42, 3, 0xb0, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0xb0, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0xb0, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0xb0, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0xb0, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0xb0, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0xb0, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0xb0, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0xb0, 0x10, 15, 1), + PIN_FIELD_BASE(51, 51, 3, 0xb0, 0x10, 12, 1), + PIN_FIELD_BASE(52, 52, 3, 0xb0, 0x10, 13, 1), + PIN_FIELD_BASE(53, 53, 3, 0xb0, 0x10, 14, 1), + PIN_FIELD_BASE(54, 54, 3, 0xb0, 0x10, 16, 1), + + PIN_FIELD_BASE(55, 55, 1, 0x90, 0x10, 12, 1), + PIN_FIELD_BASE(56, 56, 1, 0x90, 0x10, 13, 1), + PIN_FIELD_BASE(57, 57, 1, 0x90, 0x10, 11, 1), + PIN_FIELD_BASE(58, 58, 1, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(59, 59, 1, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(60, 60, 1, 0x90, 0x10, 4, 1), + PIN_FIELD_BASE(61, 61, 1, 0x90, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x90, 0x10, 5, 1), + PIN_FIELD_BASE(64, 64, 1, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(65, 65, 1, 0x90, 0x10, 7, 1), + PIN_FIELD_BASE(66, 66, 1, 0x90, 0x10, 8, 1), + PIN_FIELD_BASE(67, 67, 1, 0x90, 0x10, 9, 1), + PIN_FIELD_BASE(68, 68, 1, 0x90, 0x10, 10, 1), + + PIN_FIELD_BASE(69, 69, 5, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(70, 70, 5, 0x70, 0x10, 2, 1), + + PIN_FIELD_BASE(73, 73, 4, 0x80, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x80, 0x10, 0, 1), + + PIN_FIELD_BASE(80, 80, 1, 0x90, 0x10, 16, 1), + PIN_FIELD_BASE(81, 81, 1, 0x90, 0x10, 17, 1), + PIN_FIELD_BASE(82, 82, 1, 0x90, 0x10, 14, 1), + PIN_FIELD_BASE(83, 83, 1, 0x90, 0x10, 15, 1), +}; + +static const unsigned int mt7988_pull_type[] = { + MTK_PULL_PUPD_R1R0_TYPE,/*0*/ MTK_PULL_PUPD_R1R0_TYPE,/*1*/ + MTK_PULL_PUPD_R1R0_TYPE,/*2*/ MTK_PULL_PUPD_R1R0_TYPE,/*3*/ + MTK_PULL_PUPD_R1R0_TYPE,/*4*/ MTK_PULL_PUPD_R1R0_TYPE,/*5*/ + MTK_PULL_PUPD_R1R0_TYPE,/*6*/ MTK_PULL_PU_PD_TYPE, /*7*/ + MTK_PULL_PU_PD_TYPE, /*8*/ MTK_PULL_PU_PD_TYPE, /*9*/ + MTK_PULL_PU_PD_TYPE, /*10*/ MTK_PULL_PUPD_R1R0_TYPE,/*11*/ + MTK_PULL_PUPD_R1R0_TYPE,/*12*/ MTK_PULL_PU_PD_TYPE, /*13*/ + MTK_PULL_PU_PD_TYPE, /*14*/ MTK_PULL_PD_TYPE, /*15*/ + MTK_PULL_PD_TYPE, /*16*/ MTK_PULL_PD_TYPE, /*17*/ + MTK_PULL_PD_TYPE, /*18*/ MTK_PULL_PUPD_R1R0_TYPE,/*19*/ + MTK_PULL_PUPD_R1R0_TYPE,/*20*/ MTK_PULL_PUPD_R1R0_TYPE,/*21*/ + MTK_PULL_PUPD_R1R0_TYPE,/*22*/ MTK_PULL_PUPD_R1R0_TYPE,/*23*/ + MTK_PULL_PUPD_R1R0_TYPE,/*24*/ MTK_PULL_PUPD_R1R0_TYPE,/*25*/ + MTK_PULL_PUPD_R1R0_TYPE,/*26*/ MTK_PULL_PUPD_R1R0_TYPE,/*27*/ + MTK_PULL_PUPD_R1R0_TYPE,/*28*/ MTK_PULL_PUPD_R1R0_TYPE,/*29*/ + MTK_PULL_PUPD_R1R0_TYPE,/*30*/ MTK_PULL_PUPD_R1R0_TYPE,/*31*/ + MTK_PULL_PUPD_R1R0_TYPE,/*32*/ MTK_PULL_PUPD_R1R0_TYPE,/*33*/ + MTK_PULL_PUPD_R1R0_TYPE,/*34*/ MTK_PULL_PUPD_R1R0_TYPE,/*35*/ + MTK_PULL_PUPD_R1R0_TYPE,/*36*/ MTK_PULL_PUPD_R1R0_TYPE,/*37*/ + MTK_PULL_PUPD_R1R0_TYPE,/*38*/ MTK_PULL_PUPD_R1R0_TYPE,/*39*/ + MTK_PULL_PUPD_R1R0_TYPE,/*40*/ MTK_PULL_PUPD_R1R0_TYPE,/*41*/ + MTK_PULL_PUPD_R1R0_TYPE,/*42*/ MTK_PULL_PUPD_R1R0_TYPE,/*43*/ + MTK_PULL_PUPD_R1R0_TYPE,/*44*/ MTK_PULL_PUPD_R1R0_TYPE,/*45*/ + MTK_PULL_PUPD_R1R0_TYPE,/*46*/ MTK_PULL_PUPD_R1R0_TYPE,/*47*/ + MTK_PULL_PUPD_R1R0_TYPE,/*48*/ MTK_PULL_PUPD_R1R0_TYPE,/*49*/ + MTK_PULL_PUPD_R1R0_TYPE,/*50*/ MTK_PULL_PUPD_R1R0_TYPE,/*51*/ + MTK_PULL_PUPD_R1R0_TYPE,/*52*/ MTK_PULL_PUPD_R1R0_TYPE,/*53*/ + MTK_PULL_PUPD_R1R0_TYPE,/*54*/ MTK_PULL_PUPD_R1R0_TYPE,/*55*/ + MTK_PULL_PUPD_R1R0_TYPE,/*56*/ MTK_PULL_PUPD_R1R0_TYPE,/*57*/ + MTK_PULL_PUPD_R1R0_TYPE,/*58*/ MTK_PULL_PUPD_R1R0_TYPE,/*59*/ + MTK_PULL_PUPD_R1R0_TYPE,/*60*/ MTK_PULL_PUPD_R1R0_TYPE,/*61*/ + MTK_PULL_PUPD_R1R0_TYPE,/*62*/ MTK_PULL_PU_PD_TYPE, /*63*/ + MTK_PULL_PUPD_R1R0_TYPE,/*64*/ MTK_PULL_PUPD_R1R0_TYPE,/*65*/ + MTK_PULL_PUPD_R1R0_TYPE,/*66*/ MTK_PULL_PUPD_R1R0_TYPE,/*67*/ + MTK_PULL_PUPD_R1R0_TYPE,/*68*/ MTK_PULL_PUPD_R1R0_TYPE,/*69*/ + MTK_PULL_PUPD_R1R0_TYPE,/*70*/ MTK_PULL_PD_TYPE, /*71*/ + MTK_PULL_PD_TYPE, /*72*/ MTK_PULL_PUPD_R1R0_TYPE,/*73*/ + MTK_PULL_PUPD_R1R0_TYPE,/*74*/ MTK_PULL_PU_PD_TYPE, /*75*/ + MTK_PULL_PU_PD_TYPE, /*76*/ MTK_PULL_PU_PD_TYPE, /*77*/ + MTK_PULL_PU_PD_TYPE, /*78*/ MTK_PULL_PU_PD_TYPE, /*79*/ + MTK_PULL_PUPD_R1R0_TYPE,/*80*/ MTK_PULL_PUPD_R1R0_TYPE,/*81*/ + MTK_PULL_PUPD_R1R0_TYPE,/*82*/ MTK_PULL_PUPD_R1R0_TYPE,/*83*/ +}; + +static const struct mtk_pin_reg_calc mt7988_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7988_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7988_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7988_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7988_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7988_pin_pu_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7988_pin_pd_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7988_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7988_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7988_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7988_pin_r1_range), +}; + +static const struct mtk_pin_desc mt7988_pins[] = { + MT7988_PIN(0, "UART2_RXD"), + MT7988_PIN(1, "UART2_TXD"), + MT7988_PIN(2, "UART2_CTS"), + MT7988_PIN(3, "UART2_RTS"), + MT7988_PIN(4, "GPIO_A"), + MT7988_PIN(5, "SMI_0_MDC"), + MT7988_PIN(6, "SMI_0_MDIO"), + MT7988_PIN(7, "PCIE30_2L_0_WAKE_N"), + MT7988_PIN(8, "PCIE30_2L_0_CLKREQ_N"), + MT7988_PIN(9, "PCIE30_1L_1_WAKE_N"), + MT7988_PIN(10, "PCIE30_1L_1_CLKREQ_N"), + MT7988_PIN(11, "GPIO_P"), + MT7988_PIN(12, "WATCHDOG"), + MT7988_PIN(13, "GPIO_RESET"), + MT7988_PIN(14, "GPIO_WPS"), + MT7988_PIN(15, "PMIC_I2C_SCL"), + MT7988_PIN(16, "PMIC_I2C_SDA"), + MT7988_PIN(17, "I2C_1_SCL"), + MT7988_PIN(18, "I2C_1_SDA"), + MT7988_PIN(19, "PCIE30_2L_0_PRESET_N"), + MT7988_PIN(20, "PCIE30_1L_1_PRESET_N"), + MT7988_PIN(21, "PWMD1"), + MT7988_PIN(22, "SPI0_WP"), + MT7988_PIN(23, "SPI0_HOLD"), + MT7988_PIN(24, "SPI0_CSB"), + MT7988_PIN(25, "SPI0_MISO"), + MT7988_PIN(26, "SPI0_MOSI"), + MT7988_PIN(27, "SPI0_CLK"), + MT7988_PIN(28, "SPI1_CSB"), + MT7988_PIN(29, "SPI1_MISO"), + MT7988_PIN(30, "SPI1_MOSI"), + MT7988_PIN(31, "SPI1_CLK"), + MT7988_PIN(32, "SPI2_CLK"), + MT7988_PIN(33, "SPI2_MOSI"), + MT7988_PIN(34, "SPI2_MISO"), + MT7988_PIN(35, "SPI2_CSB"), + MT7988_PIN(36, "SPI2_HOLD"), + MT7988_PIN(37, "SPI2_WP"), + MT7988_PIN(38, "EMMC_RSTB"), + MT7988_PIN(39, "EMMC_DSL"), + MT7988_PIN(40, "EMMC_CK"), + MT7988_PIN(41, "EMMC_CMD"), + MT7988_PIN(42, "EMMC_DATA_7"), + MT7988_PIN(43, "EMMC_DATA_6"), + MT7988_PIN(44, "EMMC_DATA_5"), + MT7988_PIN(45, "EMMC_DATA_4"), + MT7988_PIN(46, "EMMC_DATA_3"), + MT7988_PIN(47, "EMMC_DATA_2"), + MT7988_PIN(48, "EMMC_DATA_1"), + MT7988_PIN(49, "EMMC_DATA_0"), + MT7988_PIN(50, "PCM_FS_I2S_LRCK"), + MT7988_PIN(51, "PCM_CLK_I2S_BCLK"), + MT7988_PIN(52, "PCM_DRX_I2S_DIN"), + MT7988_PIN(53, "PCM_DTX_I2S_DOUT"), + MT7988_PIN(54, "PCM_MCK_I2S_MCLK"), + MT7988_PIN(55, "UART0_RXD"), + MT7988_PIN(56, "UART0_TXD"), + MT7988_PIN(57, "PWMD0"), + MT7988_PIN(58, "JTAG_JTDI"), + MT7988_PIN(59, "JTAG_JTDO"), + MT7988_PIN(60, "JTAG_JTMS"), + MT7988_PIN(61, "JTAG_JTCLK"), + MT7988_PIN(62, "JTAG_JTRST_N"), + MT7988_PIN(63, "USB_DRV_VBUS_P1"), + MT7988_PIN(64, "LED_A"), + MT7988_PIN(65, "LED_B"), + MT7988_PIN(66, "LED_C"), + MT7988_PIN(67, "LED_D"), + MT7988_PIN(68, "LED_E"), + MT7988_PIN(69, "GPIO_B"), + MT7988_PIN(70, "GPIO_C"), + MT7988_PIN(71, "I2C_2_SCL"), + MT7988_PIN(72, "I2C_2_SDA"), + MT7988_PIN(73, "PCIE30_2L_1_PRESET_N"), + MT7988_PIN(74, "PCIE30_1L_0_PRESET_N"), + MT7988_PIN(75, "PCIE30_2L_1_WAKE_N"), + MT7988_PIN(76, "PCIE30_2L_1_CLKREQ_N"), + MT7988_PIN(77, "PCIE30_1L_0_WAKE_N"), + MT7988_PIN(78, "PCIE30_1L_0_CLKREQ_N"), + MT7988_PIN(79, "USB_DRV_VBUS_P0"), + MT7988_PIN(80, "UART1_RXD"), + MT7988_PIN(81, "UART1_TXD"), + MT7988_PIN(82, "UART1_CTS"), + MT7988_PIN(83, "UART1_RTS"), +}; + +/* jtag */ +static const int mt7988_tops_jtag0_0_pins[] = { 0, 1, 2, 3, 4 }; +static int mt7988_tops_jtag0_0_funcs[] = { 2, 2, 2, 2, 2 }; + +static const int mt7988_wo0_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo0_jtag_funcs[] = { 3, 3, 3, 3, 3 }; + +static const int mt7988_wo1_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo1_jtag_funcs[] = { 4, 4, 4, 4, 4 }; + +static const int mt7988_wo2_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo2_jtag_funcs[] = { 5, 5, 5, 5, 5 }; + +static const int mt7988_jtag_pins[] = { 58, 59, 60, 61, 62 }; +static int mt7988_jtag_funcs[] = { 1, 1, 1, 1, 1 }; + +static const int mt7988_tops_jtag0_1_pins[] = { 58, 59, 60, 61, 62 }; +static int mt7988_tops_jtag0_1_funcs[] = { 4, 4, 4, 4, 4 }; + +/* int_usxgmii */ +static const int mt7988_int_usxgmii_pins[] = { 2, 3 }; +static int mt7988_int_usxgmii_funcs[] = { 3, 3 }; + +/* pwm */ +static const int mt7988_pwm0_pins[] = { 57 }; +static int mt7988_pwm0_funcs[] = { 1 }; + +static const int mt7988_pwm1_pins[] = { 21 }; +static int mt7988_pwm1_funcs[] = { 1 }; + +static const int mt7988_pwm2_pins[] = { 80 }; +static int mt7988_pwm2_funcs[] = { 2 }; + +static const int mt7988_pwm2_0_pins[] = { 58 }; +static int mt7988_pwm2_0_funcs[] = { 5 }; + +static const int mt7988_pwm3_pins[] = { 81 }; +static int mt7988_pwm3_funcs[] = { 2 }; + +static const int mt7988_pwm3_0_pins[] = { 59 }; +static int mt7988_pwm3_0_funcs[] = { 5 }; + +static const int mt7988_pwm4_pins[] = { 82 }; +static int mt7988_pwm4_funcs[] = { 2 }; + +static const int mt7988_pwm4_0_pins[] = { 60 }; +static int mt7988_pwm4_0_funcs[] = { 5 }; + +static const int mt7988_pwm5_pins[] = { 83 }; +static int mt7988_pwm5_funcs[] = { 2 }; + +static const int mt7988_pwm5_0_pins[] = { 61 }; +static int mt7988_pwm5_0_funcs[] = { 5 }; + +static const int mt7988_pwm6_pins[] = { 69 }; +static int mt7988_pwm6_funcs[] = { 3 }; + +static const int mt7988_pwm6_0_pins[] = { 62 }; +static int mt7988_pwm6_0_funcs[] = { 5 }; + +static const int mt7988_pwm7_pins[] = { 70 }; +static int mt7988_pwm7_funcs[] = { 3 }; + +static const int mt7988_pwm7_0_pins[] = { 4 }; +static int mt7988_pwm7_0_funcs[] = { 3 }; + +/* dfd */ +static const int mt7988_dfd_pins[] = { 0, 1, 2, 3, 4 }; +static int mt7988_dfd_funcs[] = { 4, 4, 4, 4, 4 }; + +/* i2c */ +static const int mt7988_xfi_phy0_i2c0_pins[] = { 0, 1 }; +static int mt7988_xfi_phy0_i2c0_funcs[] = { 5, 5 }; + +static const int mt7988_xfi_phy1_i2c0_pins[] = { 0, 1 }; +static int mt7988_xfi_phy1_i2c0_funcs[] = { 6, 6 }; + +static const int mt7988_xfi_phy_pll_i2c0_pins[] = { 3, 4 }; +static int mt7988_xfi_phy_pll_i2c0_funcs[] = { 5, 5 }; + +static const int mt7988_xfi_phy_pll_i2c1_pins[] = { 3, 4 }; +static int mt7988_xfi_phy_pll_i2c1_funcs[] = { 6, 6 }; + +static const int mt7988_i2c0_0_pins[] = { 5, 6 }; +static int mt7988_i2c0_0_funcs[] = { 2, 2 }; + +static const int mt7988_i2c1_sfp_pins[] = { 5, 6 }; +static int mt7988_i2c1_sfp_funcs[] = { 4, 4 }; + +static const int mt7988_xfi_pextp_phy0_i2c_pins[] = { 5, 6 }; +static int mt7988_xfi_pextp_phy0_i2c_funcs[] = { 5, 5 }; + +static const int mt7988_xfi_pextp_phy1_i2c_pins[] = { 5, 6 }; +static int mt7988_xfi_pextp_phy1_i2c_funcs[] = { 6, 6 }; + +static const int mt7988_i2c0_1_pins[] = { 15, 16 }; +static int mt7988_i2c0_1_funcs[] = { 1, 1 }; + +static const int mt7988_u30_phy_i2c0_pins[] = { 15, 16 }; +static int mt7988_u30_phy_i2c0_funcs[] = { 2, 2 }; + +static const int mt7988_u32_phy_i2c0_pins[] = { 15, 16 }; +static int mt7988_u32_phy_i2c0_funcs[] = { 3, 3 }; + +static const int mt7988_xfi_phy0_i2c1_pins[] = { 15, 16 }; +static int mt7988_xfi_phy0_i2c1_funcs[] = { 5, 5 }; + +static const int mt7988_xfi_phy1_i2c1_pins[] = { 15, 16 }; +static int mt7988_xfi_phy1_i2c1_funcs[] = { 6, 6 }; + +static const int mt7988_xfi_phy_pll_i2c2_pins[] = { 15, 16 }; +static int mt7988_xfi_phy_pll_i2c2_funcs[] = { 7, 7 }; + +static const int mt7988_i2c1_0_pins[] = { 17, 18 }; +static int mt7988_i2c1_0_funcs[] = { 1, 1 }; + +static const int mt7988_u30_phy_i2c1_pins[] = { 17, 18 }; +static int mt7988_u30_phy_i2c1_funcs[] = { 2, 2 }; + +static const int mt7988_u32_phy_i2c1_pins[] = { 17, 18 }; +static int mt7988_u32_phy_i2c1_funcs[] = { 3, 3 }; + +static const int mt7988_xfi_phy_pll_i2c3_pins[] = { 17, 18 }; +static int mt7988_xfi_phy_pll_i2c3_funcs[] = { 4, 4 }; + +static const int mt7988_sgmii0_i2c_pins[] = { 17, 18 }; +static int mt7988_sgmii0_i2c_funcs[] = { 5, 5 }; + +static const int mt7988_sgmii1_i2c_pins[] = { 17, 18 }; +static int mt7988_sgmii1_i2c_funcs[] = { 6, 6 }; + +static const int mt7988_i2c1_2_pins[] = { 69, 70 }; +static int mt7988_i2c1_2_funcs[] = { 2, 2 }; + +static const int mt7988_i2c2_0_pins[] = { 69, 70 }; +static int mt7988_i2c2_0_funcs[] = { 4, 4 }; + +static const int mt7988_i2c2_1_pins[] = { 71, 72 }; +static int mt7988_i2c2_1_funcs[] = { 1, 1 }; + +/* eth */ +static const int mt7988_mdc_mdio0_pins[] = { 5, 6 }; +static int mt7988_mdc_mdio0_funcs[] = { 1, 1 }; + +static const int mt7988_2p5g_ext_mdio_pins[] = { 28, 29 }; +static int mt7988_2p5g_ext_mdio_funcs[] = { 6, 6 }; + +static const int mt7988_gbe_ext_mdio_pins[] = { 30, 31 }; +static int mt7988_gbe_ext_mdio_funcs[] = { 6, 6 }; + +static const int mt7988_mdc_mdio1_pins[] = { 69, 70 }; +static int mt7988_mdc_mdio1_funcs[] = { 1, 1 }; + +/* pcie */ +static const int mt7988_pcie_wake_n0_0_pins[] = { 7 }; +static int mt7988_pcie_wake_n0_0_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n0_0_pins[] = { 8 }; +static int mt7988_pcie_clk_req_n0_0_funcs[] = { 1 }; + +static const int mt7988_pcie_wake_n3_0_pins[] = { 9 }; +static int mt7988_pcie_wake_n3_0_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n3_pins[] = { 10 }; +static int mt7988_pcie_clk_req_n3_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n0_1_pins[] = { 10 }; +static int mt7988_pcie_clk_req_n0_1_funcs[] = { 2 }; + +static const int mt7988_pcie_p0_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p0_phy_i2c_funcs[] = { 3, 3 }; + +static const int mt7988_pcie_p1_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p1_phy_i2c_funcs[] = { 4, 4 }; + +static const int mt7988_pcie_p3_phy_i2c_pins[] = { 9, 10 }; +static int mt7988_pcie_p3_phy_i2c_funcs[] = { 4, 4 }; + +static const int mt7988_pcie_p2_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p2_phy_i2c_funcs[] = { 5, 5 }; + +static const int mt7988_ckm_phy_i2c_pins[] = { 9, 10 }; +static int mt7988_ckm_phy_i2c_funcs[] = { 5, 5 }; + +static const int mt7988_pcie_wake_n0_1_pins[] = { 13 }; +static int mt7988_pcie_wake_n0_1_funcs[] = { 2 }; + +static const int mt7988_pcie_wake_n3_1_pins[] = { 14 }; +static int mt7988_pcie_wake_n3_1_funcs[] = { 2 }; + +static const int mt7988_pcie_2l_0_pereset_pins[] = { 19 }; +static int mt7988_pcie_2l_0_pereset_funcs[] = { 1 }; + +static const int mt7988_pcie_1l_1_pereset_pins[] = { 20 }; +static int mt7988_pcie_1l_1_pereset_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n2_1_pins[] = { 63 }; +static int mt7988_pcie_clk_req_n2_1_funcs[] = { 2 }; + +static const int mt7988_pcie_2l_1_pereset_pins[] = { 73 }; +static int mt7988_pcie_2l_1_pereset_funcs[] = { 1 }; + +static const int mt7988_pcie_1l_0_pereset_pins[] = { 74 }; +static int mt7988_pcie_1l_0_pereset_funcs[] = { 1 }; + +static const int mt7988_pcie_wake_n1_0_pins[] = { 75 }; +static int mt7988_pcie_wake_n1_0_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n1_pins[] = { 76 }; +static int mt7988_pcie_clk_req_n1_funcs[] = { 1 }; + +static const int mt7988_pcie_wake_n2_0_pins[] = { 77 }; +static int mt7988_pcie_wake_n2_0_funcs[] = { 1 }; + +static const int mt7988_pcie_clk_req_n2_0_pins[] = { 78 }; +static int mt7988_pcie_clk_req_n2_0_funcs[] = { 1 }; + +static const int mt7988_pcie_wake_n2_1_pins[] = { 79 }; +static int mt7988_pcie_wake_n2_1_funcs[] = { 2 }; + +/* pmic */ +static const int mt7988_pmic_pins[] = { 11 }; +static int mt7988_pmic_funcs[] = { 1 }; + +/* watchdog */ +static const int mt7988_watchdog_pins[] = { 12 }; +static int mt7988_watchdog_funcs[] = { 1 }; + +/* spi */ +static const int mt7988_spi0_wp_hold_pins[] = { 22, 23 }; +static int mt7988_spi0_wp_hold_funcs[] = { 1, 1 }; + +static const int mt7988_spi0_pins[] = { 24, 25, 26, 27 }; +static int mt7988_spi0_funcs[] = { 1, 1, 1, 1 }; + +static const int mt7988_spi1_pins[] = { 28, 29, 30, 31 }; +static int mt7988_spi1_funcs[] = { 1, 1, 1, 1 }; + +static const int mt7988_spi2_pins[] = { 32, 33, 34, 35 }; +static int mt7988_spi2_funcs[] = { 1, 1, 1, 1 }; + +static const int mt7988_spi2_wp_hold_pins[] = { 36, 37 }; +static int mt7988_spi2_wp_hold_funcs[] = { 1, 1 }; + +/* flash */ +static const int mt7988_snfi_pins[] = { 22, 23, 24, 25, 26, 27 }; +static int mt7988_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 }; + +static const int mt7988_emmc_45_pins[] = { + 21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 +}; +static int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; + +static const int mt7988_sdcard_pins[] = { 32, 33, 34, 35, 36, 37 }; +static int mt7988_sdcard_funcs[] = { 5, 5, 5, 5, 5, 5 }; + +static const int mt7988_emmc_51_pins[] = { 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49 }; +static int mt7988_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + +/* uart */ +static const int mt7988_uart2_pins[] = { 0, 1, 2, 3 }; +static int mt7988_uart2_funcs[] = { 1, 1, 1, 1 }; + +static const int mt7988_tops_uart0_0_pins[] = { 22, 23 }; +static int mt7988_tops_uart0_0_funcs[] = { 3, 3 }; + +static const int mt7988_uart2_0_pins[] = { 28, 29, 30, 31 }; +static int mt7988_uart2_0_funcs[] = { 2, 2, 2, 2 }; + +static const int mt7988_uart1_0_pins[] = { 32, 33, 34, 35 }; +static int mt7988_uart1_0_funcs[] = { 2, 2, 2, 2 }; + +static const int mt7988_uart2_1_pins[] = { 32, 33, 34, 35 }; +static int mt7988_uart2_1_funcs[] = { 3, 3, 3, 3 }; + +static const int mt7988_net_wo0_uart_txd_0_pins[] = { 28 }; +static int mt7988_net_wo0_uart_txd_0_funcs[] = { 3 }; + +static const int mt7988_net_wo1_uart_txd_0_pins[] = { 29 }; +static int mt7988_net_wo1_uart_txd_0_funcs[] = { 3 }; + +static const int mt7988_net_wo2_uart_txd_0_pins[] = { 30 }; +static int mt7988_net_wo2_uart_txd_0_funcs[] = { 3 }; + +static const int mt7988_tops_uart1_0_pins[] = { 28, 29 }; +static int mt7988_tops_uart1_0_funcs[] = { 4, 4 }; + +static const int mt7988_tops_uart0_1_pins[] = { 30, 31 }; +static int mt7988_tops_uart0_1_funcs[] = { 4, 4 }; + +static const int mt7988_tops_uart1_1_pins[] = { 36, 37 }; +static int mt7988_tops_uart1_1_funcs[] = { 3, 3 }; + +static const int mt7988_uart0_pins[] = { 55, 56 }; +static int mt7988_uart0_funcs[] = { 1, 1 }; + +static const int mt7988_tops_uart0_2_pins[] = { 55, 56 }; +static int mt7988_tops_uart0_2_funcs[] = { 2, 2 }; + +static const int mt7988_uart2_2_pins[] = { 50, 51, 52, 53 }; +static int mt7988_uart2_2_funcs[] = { 2, 2, 2, 2 }; + +static const int mt7988_uart1_1_pins[] = { 58, 59, 60, 61 }; +static int mt7988_uart1_1_funcs[] = { 2, 2, 2, 2 }; + +static const int mt7988_uart2_3_pins[] = { 58, 59, 60, 61 }; +static int mt7988_uart2_3_funcs[] = { 3, 3, 3, 3 }; + +static const int mt7988_uart1_2_pins[] = { 80, 81, 82, 83 }; +static int mt7988_uart1_2_funcs[] = { 1, 1, 1, 1 }; + +static const int mt7988_uart1_2_lite_pins[] = { 80, 81 }; +static int mt7988_uart1_2_lite_funcs[] = { 1, 1 }; + +static const int mt7988_tops_uart1_2_pins[] = { 80, 81 }; +static int mt7988_tops_uart1_2_funcs[] = { 4, 4, }; + +static const int mt7988_net_wo0_uart_txd_1_pins[] = { 80 }; +static int mt7988_net_wo0_uart_txd_1_funcs[] = { 3 }; + +static const int mt7988_net_wo1_uart_txd_1_pins[] = { 81 }; +static int mt7988_net_wo1_uart_txd_1_funcs[] = { 3 }; + +static const int mt7988_net_wo2_uart_txd_1_pins[] = { 82 }; +static int mt7988_net_wo2_uart_txd_1_funcs[] = { 3 }; + +/* udi */ +static const int mt7988_udi_pins[] = { 32, 33, 34, 35, 36 }; +static int mt7988_udi_funcs[] = { 4, 4, 4, 4, 4 }; + +/* i2s */ +static const int mt7988_i2s_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_i2s_funcs[] = { 1, 1, 1, 1, 1 }; + +/* pcm */ +static const int mt7988_pcm_pins[] = { 50, 51, 52, 53 }; +static int mt7988_pcm_funcs[] = { 1, 1, 1, 1 }; + +/* led */ +static const int mt7988_gbe0_led1_pins[] = { 58 }; +static int mt7988_gbe0_led1_funcs[] = { 6 }; +static const int mt7988_gbe1_led1_pins[] = { 59 }; +static int mt7988_gbe1_led1_funcs[] = { 6 }; +static const int mt7988_gbe2_led1_pins[] = { 60 }; +static int mt7988_gbe2_led1_funcs[] = { 6 }; +static const int mt7988_gbe3_led1_pins[] = { 61 }; +static int mt7988_gbe3_led1_funcs[] = { 6 }; + +static const int mt7988_2p5gbe_led1_pins[] = { 62 }; +static int mt7988_2p5gbe_led1_funcs[] = { 6 }; + +static const int mt7988_gbe0_led0_pins[] = { 64 }; +static int mt7988_gbe0_led0_funcs[] = { 1 }; +static const int mt7988_gbe1_led0_pins[] = { 65 }; +static int mt7988_gbe1_led0_funcs[] = { 1 }; +static const int mt7988_gbe2_led0_pins[] = { 66 }; +static int mt7988_gbe2_led0_funcs[] = { 1 }; +static const int mt7988_gbe3_led0_pins[] = { 67 }; +static int mt7988_gbe3_led0_funcs[] = { 1 }; + +static const int mt7988_2p5gbe_led0_pins[] = { 68 }; +static int mt7988_2p5gbe_led0_funcs[] = { 1 }; + +/* usb */ +static const int mt7988_drv_vbus_p1_pins[] = { 63 }; +static int mt7988_drv_vbus_p1_funcs[] = { 1 }; + +static const int mt7988_drv_vbus_pins[] = { 79 }; +static int mt7988_drv_vbus_funcs[] = { 1 }; + +static const struct group_desc mt7988_groups[] = { + /* @GPIO(0,1,2,3): uart2 */ + PINCTRL_PIN_GROUP("uart2", mt7988_uart2), + /* @GPIO(0,1,2,3,4): tops_jtag0_0 */ + PINCTRL_PIN_GROUP("tops_jtag0_0", mt7988_tops_jtag0_0), + /* @GPIO(2,3): int_usxgmii */ + PINCTRL_PIN_GROUP("int_usxgmii", mt7988_int_usxgmii), + /* @GPIO(0,1,2,3,4): dfd */ + PINCTRL_PIN_GROUP("dfd", mt7988_dfd), + /* @GPIO(0,1): xfi_phy0_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy0_i2c0", mt7988_xfi_phy0_i2c0), + /* @GPIO(0,1): xfi_phy1_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy1_i2c0", mt7988_xfi_phy1_i2c0), + /* @GPIO(3,4): xfi_phy_pll_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c0", mt7988_xfi_phy_pll_i2c0), + /* @GPIO(3,4): xfi_phy_pll_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c1", mt7988_xfi_phy_pll_i2c1), + /* @GPIO(4): pwm7 */ + PINCTRL_PIN_GROUP("pwm7_0", mt7988_pwm7_0), + /* @GPIO(5,6) i2c0_0 */ + PINCTRL_PIN_GROUP("i2c0_0", mt7988_i2c0_0), + /* @GPIO(5,6) i2c1_sfp */ + PINCTRL_PIN_GROUP("i2c1_sfp", mt7988_i2c1_sfp), + /* @GPIO(5,6) xfi_pextp_phy0_i2c */ + PINCTRL_PIN_GROUP("xfi_pextp_phy0_i2c", mt7988_xfi_pextp_phy0_i2c), + /* @GPIO(5,6) xfi_pextp_phy1_i2c */ + PINCTRL_PIN_GROUP("xfi_pextp_phy1_i2c", mt7988_xfi_pextp_phy1_i2c), + /* @GPIO(5,6) mdc_mdio0 */ + PINCTRL_PIN_GROUP("mdc_mdio0", mt7988_mdc_mdio0), + /* @GPIO(7): pcie_wake_n0_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n0_0", mt7988_pcie_wake_n0_0), + /* @GPIO(8): pcie_clk_req_n0_0 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n0_0", mt7988_pcie_clk_req_n0_0), + /* @GPIO(9): pcie_wake_n3_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n3_0", mt7988_pcie_wake_n3_0), + /* @GPIO(10): pcie_clk_req_n3 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n3", mt7988_pcie_clk_req_n3), + /* @GPIO(10): pcie_clk_req_n0_1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n0_1", mt7988_pcie_clk_req_n0_1), + /* @GPIO(7,8) pcie_p0_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p0_phy_i2c", mt7988_pcie_p0_phy_i2c), + /* @GPIO(7,8) pcie_p1_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p1_phy_i2c", mt7988_pcie_p1_phy_i2c), + /* @GPIO(7,8) pcie_p2_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p2_phy_i2c", mt7988_pcie_p2_phy_i2c), + /* @GPIO(9,10) pcie_p3_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p3_phy_i2c", mt7988_pcie_p3_phy_i2c), + /* @GPIO(9,10) ckm_phy_i2c */ + PINCTRL_PIN_GROUP("ckm_phy_i2c", mt7988_ckm_phy_i2c), + /* @GPIO(11): pmic */ + PINCTRL_PIN_GROUP("pcie_pmic", mt7988_pmic), + /* @GPIO(12): watchdog */ + PINCTRL_PIN_GROUP("watchdog", mt7988_watchdog), + /* @GPIO(13): pcie_wake_n0_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n0_1", mt7988_pcie_wake_n0_1), + /* @GPIO(14): pcie_wake_n3_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n3_1", mt7988_pcie_wake_n3_1), + /* @GPIO(15,16) i2c0_1 */ + PINCTRL_PIN_GROUP("i2c0_1", mt7988_i2c0_1), + /* @GPIO(15,16) u30_phy_i2c0 */ + PINCTRL_PIN_GROUP("u30_phy_i2c0", mt7988_u30_phy_i2c0), + /* @GPIO(15,16) u32_phy_i2c0 */ + PINCTRL_PIN_GROUP("u32_phy_i2c0", mt7988_u32_phy_i2c0), + /* @GPIO(15,16) xfi_phy0_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy0_i2c1", mt7988_xfi_phy0_i2c1), + /* @GPIO(15,16) xfi_phy1_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy1_i2c1", mt7988_xfi_phy1_i2c1), + /* @GPIO(15,16) xfi_phy_pll_i2c2 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c2", mt7988_xfi_phy_pll_i2c2), + /* @GPIO(17,18) i2c1_0 */ + PINCTRL_PIN_GROUP("i2c1_0", mt7988_i2c1_0), + /* @GPIO(17,18) u30_phy_i2c1 */ + PINCTRL_PIN_GROUP("u30_phy_i2c1", mt7988_u30_phy_i2c1), + /* @GPIO(17,18) u32_phy_i2c1 */ + PINCTRL_PIN_GROUP("u32_phy_i2c1", mt7988_u32_phy_i2c1), + /* @GPIO(17,18) xfi_phy_pll_i2c3 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c3", mt7988_xfi_phy_pll_i2c3), + /* @GPIO(17,18) sgmii0_i2c */ + PINCTRL_PIN_GROUP("sgmii0_i2c", mt7988_sgmii0_i2c), + /* @GPIO(17,18) sgmii1_i2c */ + PINCTRL_PIN_GROUP("sgmii1_i2c", mt7988_sgmii1_i2c), + /* @GPIO(19): pcie_2l_0_pereset */ + PINCTRL_PIN_GROUP("pcie_2l_0_pereset", mt7988_pcie_2l_0_pereset), + /* @GPIO(20): pcie_1l_1_pereset */ + PINCTRL_PIN_GROUP("pcie_1l_1_pereset", mt7988_pcie_1l_1_pereset), + /* @GPIO(21): pwm1 */ + PINCTRL_PIN_GROUP("pwm1", mt7988_pwm1), + /* @GPIO(22,23) spi0_wp_hold */ + PINCTRL_PIN_GROUP("spi0_wp_hold", mt7988_spi0_wp_hold), + /* @GPIO(24,25,26,27) spi0 */ + PINCTRL_PIN_GROUP("spi0", mt7988_spi0), + /* @GPIO(28,29,30,31) spi1 */ + PINCTRL_PIN_GROUP("spi1", mt7988_spi1), + /* @GPIO(32,33,34,35) spi2 */ + PINCTRL_PIN_GROUP("spi2", mt7988_spi2), + /* @GPIO(36,37) spi2_wp_hold */ + PINCTRL_PIN_GROUP("spi2_wp_hold", mt7988_spi2_wp_hold), + /* @GPIO(22,23,24,25,26,27) snfi */ + PINCTRL_PIN_GROUP("snfi", mt7988_snfi), + /* @GPIO(22,23) tops_uart0_0 */ + PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart0_0), + /* @GPIO(28,29,30,31) uart2_0 */ + PINCTRL_PIN_GROUP("uart2_0", mt7988_uart2_0), + /* @GPIO(32,33,34,35) uart1_0 */ + PINCTRL_PIN_GROUP("uart1_0", mt7988_uart1_0), + /* @GPIO(32,33,34,35) uart2_1 */ + PINCTRL_PIN_GROUP("uart2_1", mt7988_uart2_1), + /* @GPIO(28) net_wo0_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), + /* @GPIO(29) net_wo1_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), + /* @GPIO(30) net_wo2_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), + /* @GPIO(28,29) tops_uart1_0 */ + PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart1_0), + /* @GPIO(30,31) tops_uart0_1 */ + PINCTRL_PIN_GROUP("tops_uart0_1", mt7988_tops_uart0_1), + /* @GPIO(36,37) tops_uart1_1 */ + PINCTRL_PIN_GROUP("tops_uart1_1", mt7988_tops_uart1_1), + /* @GPIO(32,33,34,35,36) udi */ + PINCTRL_PIN_GROUP("udi", mt7988_udi), + /* @GPIO(21,28,29,30,31,32,33,34,35,36,37) emmc_45 */ + PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45), + /* @GPIO(32,33,34,35,36,37) sdcard */ + PINCTRL_PIN_GROUP("sdcard", mt7988_sdcard), + /* @GPIO(38,39,40,41,42,43,44,45,46,47,48,49) emmc_51 */ + PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51), + /* @GPIO(28,29) 2p5g_ext_mdio */ + PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio), + /* @GPIO(30,31) gbe_ext_mdio */ + PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio), + /* @GPIO(50,51,52,53,54) i2s */ + PINCTRL_PIN_GROUP("i2s", mt7988_i2s), + /* @GPIO(50,51,52,53) pcm */ + PINCTRL_PIN_GROUP("pcm", mt7988_pcm), + /* @GPIO(55,56) uart0 */ + PINCTRL_PIN_GROUP("uart0", mt7988_uart0), + /* @GPIO(55,56) tops_uart0_2 */ + PINCTRL_PIN_GROUP("tops_uart0_2", mt7988_tops_uart0_2), + /* @GPIO(50,51,52,53) uart2_2 */ + PINCTRL_PIN_GROUP("uart2_2", mt7988_uart2_2), + /* @GPIO(50,51,52,53,54) wo0_jtag */ + PINCTRL_PIN_GROUP("wo0_jtag", mt7988_wo0_jtag), + /* @GPIO(50,51,52,53,54) wo1-wo1_jtag */ + PINCTRL_PIN_GROUP("wo1_jtag", mt7988_wo1_jtag), + /* @GPIO(50,51,52,53,54) wo2_jtag */ + PINCTRL_PIN_GROUP("wo2_jtag", mt7988_wo2_jtag), + /* @GPIO(57) pwm0 */ + PINCTRL_PIN_GROUP("pwm0", mt7988_pwm0), + /* @GPIO(58) pwm2_0 */ + PINCTRL_PIN_GROUP("pwm2_0", mt7988_pwm2_0), + /* @GPIO(59) pwm3_0 */ + PINCTRL_PIN_GROUP("pwm3_0", mt7988_pwm3_0), + /* @GPIO(60) pwm4_0 */ + PINCTRL_PIN_GROUP("pwm4_0", mt7988_pwm4_0), + /* @GPIO(61) pwm5_0 */ + PINCTRL_PIN_GROUP("pwm5_0", mt7988_pwm5_0), + /* @GPIO(58,59,60,61,62) jtag */ + PINCTRL_PIN_GROUP("jtag", mt7988_jtag), + /* @GPIO(58,59,60,61,62) tops_jtag0_1 */ + PINCTRL_PIN_GROUP("tops_jtag0_1", mt7988_tops_jtag0_1), + /* @GPIO(58,59,60,61) uart2_3 */ + PINCTRL_PIN_GROUP("uart2_3", mt7988_uart2_3), + /* @GPIO(58,59,60,61) uart1_1 */ + PINCTRL_PIN_GROUP("uart1_1", mt7988_uart1_1), + /* @GPIO(58,59,60,61) gbe_led1 */ + PINCTRL_PIN_GROUP("gbe0_led1", mt7988_gbe0_led1), + PINCTRL_PIN_GROUP("gbe1_led1", mt7988_gbe1_led1), + PINCTRL_PIN_GROUP("gbe2_led1", mt7988_gbe2_led1), + PINCTRL_PIN_GROUP("gbe3_led1", mt7988_gbe3_led1), + /* @GPIO(62) pwm6_0 */ + PINCTRL_PIN_GROUP("pwm6_0", mt7988_pwm6_0), + /* @GPIO(62) 2p5gbe_led1 */ + PINCTRL_PIN_GROUP("2p5gbe_led1", mt7988_2p5gbe_led1), + /* @GPIO(64,65,66,67) gbe_led0 */ + PINCTRL_PIN_GROUP("gbe0_led0", mt7988_gbe0_led0), + PINCTRL_PIN_GROUP("gbe1_led0", mt7988_gbe1_led0), + PINCTRL_PIN_GROUP("gbe2_led0", mt7988_gbe2_led0), + PINCTRL_PIN_GROUP("gbe3_led0", mt7988_gbe3_led0), + /* @GPIO(68) 2p5gbe_led0 */ + PINCTRL_PIN_GROUP("2p5gbe_led0", mt7988_2p5gbe_led0), + /* @GPIO(63) drv_vbus_p1 */ + PINCTRL_PIN_GROUP("drv_vbus_p1", mt7988_drv_vbus_p1), + /* @GPIO(63) pcie_clk_req_n2_1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n2_1", mt7988_pcie_clk_req_n2_1), + /* @GPIO(69, 70) mdc_mdio1 */ + PINCTRL_PIN_GROUP("mdc_mdio1", mt7988_mdc_mdio1), + /* @GPIO(69, 70) i2c1_2 */ + PINCTRL_PIN_GROUP("i2c1_2", mt7988_i2c1_2), + /* @GPIO(69) pwm6 */ + PINCTRL_PIN_GROUP("pwm6", mt7988_pwm6), + /* @GPIO(70) pwm7 */ + PINCTRL_PIN_GROUP("pwm7", mt7988_pwm7), + /* @GPIO(69,70) i2c2_0 */ + PINCTRL_PIN_GROUP("i2c2_0", mt7988_i2c2_0), + /* @GPIO(71,72) i2c2_1 */ + PINCTRL_PIN_GROUP("i2c2_1", mt7988_i2c2_1), + /* @GPIO(73) pcie_2l_1_pereset */ + PINCTRL_PIN_GROUP("pcie_2l_1_pereset", mt7988_pcie_2l_1_pereset), + /* @GPIO(74) pcie_1l_0_pereset */ + PINCTRL_PIN_GROUP("pcie_1l_0_pereset", mt7988_pcie_1l_0_pereset), + /* @GPIO(75) pcie_wake_n1_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n1_0", mt7988_pcie_wake_n1_0), + /* @GPIO(76) pcie_clk_req_n1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n1", mt7988_pcie_clk_req_n1), + /* @GPIO(77) pcie_wake_n2_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n2_0", mt7988_pcie_wake_n2_0), + /* @GPIO(78) pcie_clk_req_n2_0 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n2_0", mt7988_pcie_clk_req_n2_0), + /* @GPIO(79) drv_vbus */ + PINCTRL_PIN_GROUP("drv_vbus", mt7988_drv_vbus), + /* @GPIO(79) pcie_wake_n2_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n2_1", mt7988_pcie_wake_n2_1), + /* @GPIO(80,81,82,83) uart1_2 */ + PINCTRL_PIN_GROUP("uart1_2", mt7988_uart1_2), + /* @GPIO(80,81) uart1_2_lite */ + PINCTRL_PIN_GROUP("uart1_2_lite", mt7988_uart1_2_lite), + /* @GPIO(80) pwm2 */ + PINCTRL_PIN_GROUP("pwm2", mt7988_pwm2), + /* @GPIO(81) pwm3 */ + PINCTRL_PIN_GROUP("pwm3", mt7988_pwm3), + /* @GPIO(82) pwm4 */ + PINCTRL_PIN_GROUP("pwm4", mt7988_pwm4), + /* @GPIO(83) pwm5 */ + PINCTRL_PIN_GROUP("pwm5", mt7988_pwm5), + /* @GPIO(80) net_wo0_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), + /* @GPIO(81) net_wo1_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), + /* @GPIO(82) net_wo2_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), + /* @GPIO(80,81) tops_uart1_2 */ + PINCTRL_PIN_GROUP("tops_uart1_2", mt7988_tops_uart1_2), + /* @GPIO(80) net_wo0_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7988_net_wo0_uart_txd_1), + /* @GPIO(81) net_wo1_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_1", mt7988_net_wo1_uart_txd_1), + /* @GPIO(82) net_wo2_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_1", mt7988_net_wo2_uart_txd_1), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char * const mt7988_jtag_groups[] = { + "tops_jtag0_0", "wo0_jtag", "wo1_jtag", + "wo2_jtag", "jtag", "tops_jtag0_1", +}; +static const char * const mt7988_int_usxgmii_groups[] = { + "int_usxgmii", +}; +static const char * const mt7988_pwm_groups[] = { + "pwm0", "pwm1", "pwm2", "pwm2_0", "pwm3", "pwm3_0", "pwm4", "pwm4_0", + "pwm5", "pwm5_0", "pwm6", "pwm6_0", "pwm7", "pwm7_0", + +}; +static const char * const mt7988_dfd_groups[] = { + "dfd", +}; +static const char * const mt7988_i2c_groups[] = { + "xfi_phy0_i2c0", + "xfi_phy1_i2c0", + "xfi_phy_pll_i2c0", + "xfi_phy_pll_i2c1", + "i2c0_0", + "i2c1_sfp", + "xfi_pextp_phy0_i2c", + "xfi_pextp_phy1_i2c", + "i2c0_1", + "u30_phy_i2c0", + "u32_phy_i2c0", + "xfi_phy0_i2c1", + "xfi_phy1_i2c1", + "xfi_phy_pll_i2c2", + "i2c1_0", + "u30_phy_i2c1", + "u32_phy_i2c1", + "xfi_phy_pll_i2c3", + "sgmii0_i2c", + "sgmii1_i2c", + "i2c1_2", + "i2c2_0", + "i2c2_1", +}; +static const char * const mt7988_ethernet_groups[] = { + "mdc_mdio0", + "2p5g_ext_mdio", + "gbe_ext_mdio", + "mdc_mdio1", +}; +static const char * const mt7988_pcie_groups[] = { + "pcie_wake_n0_0", "pcie_clk_req_n0_0", "pcie_wake_n3_0", + "pcie_clk_req_n3", "pcie_p0_phy_i2c", "pcie_p1_phy_i2c", + "pcie_p3_phy_i2c", "pcie_p2_phy_i2c", "ckm_phy_i2c", + "pcie_wake_n0_1", "pcie_wake_n3_1", "pcie_2l_0_pereset", + "pcie_1l_1_pereset", "pcie_clk_req_n2_1", "pcie_2l_1_pereset", + "pcie_1l_0_pereset", "pcie_wake_n1_0", "pcie_clk_req_n1", + "pcie_wake_n2_0", "pcie_clk_req_n2_0", "pcie_wake_n2_1", + "pcie_clk_req_n0_1" +}; +static const char * const mt7988_pmic_groups[] = { + "pmic", +}; +static const char * const mt7988_wdt_groups[] = { + "watchdog", +}; +static const char * const mt7988_spi_groups[] = { + "spi0", "spi0_wp_hold", "spi1", "spi2", "spi2_wp_hold", +}; +static const char * const mt7988_flash_groups[] = { "emmc_45", "sdcard", "snfi", + "emmc_51" }; +static const char * const mt7988_uart_groups[] = { + "uart2", + "tops_uart0_0", + "uart2_0", + "uart1_0", + "uart2_1", + "net_wo0_uart_txd_0", + "net_wo1_uart_txd_0", + "net_wo2_uart_txd_0", + "tops_uart1_0", + "ops_uart0_1", + "ops_uart1_1", + "uart0", + "tops_uart0_2", + "uart1_1", + "uart2_3", + "uart1_2", + "uart1_2_lite", + "tops_uart1_2", + "net_wo0_uart_txd_1", + "net_wo1_uart_txd_1", + "net_wo2_uart_txd_1", +}; +static const char * const mt7988_udi_groups[] = { + "udi", +}; +static const char * const mt7988_audio_groups[] = { + "i2s", "pcm", +}; +static const char * const mt7988_led_groups[] = { + "gbe0_led1", "gbe1_led1", "gbe2_led1", "gbe3_led1", "2p5gbe_led1", + "gbe0_led0", "gbe1_led0", "gbe2_led0", "gbe3_led0", "2p5gbe_led0", + "wf5g_led0", "wf5g_led1", +}; +static const char * const mt7988_usb_groups[] = { + "drv_vbus", + "drv_vbus_p1", +}; + +static const struct function_desc mt7988_functions[] = { + { { "audio", mt7988_audio_groups, ARRAY_SIZE(mt7988_audio_groups) }, + NULL }, + { { "jtag", mt7988_jtag_groups, ARRAY_SIZE(mt7988_jtag_groups) }, + NULL }, + { { "int_usxgmii", mt7988_int_usxgmii_groups, + ARRAY_SIZE(mt7988_int_usxgmii_groups) }, + NULL }, + { { "pwm", mt7988_pwm_groups, ARRAY_SIZE(mt7988_pwm_groups) }, NULL }, + { { "dfd", mt7988_dfd_groups, ARRAY_SIZE(mt7988_dfd_groups) }, NULL }, + { { "i2c", mt7988_i2c_groups, ARRAY_SIZE(mt7988_i2c_groups) }, NULL }, + { { "eth", mt7988_ethernet_groups, ARRAY_SIZE(mt7988_ethernet_groups) }, + NULL }, + { { "pcie", mt7988_pcie_groups, ARRAY_SIZE(mt7988_pcie_groups) }, + NULL }, + { { "pmic", mt7988_pmic_groups, ARRAY_SIZE(mt7988_pmic_groups) }, + NULL }, + { { "watchdog", mt7988_wdt_groups, ARRAY_SIZE(mt7988_wdt_groups) }, + NULL }, + { { "spi", mt7988_spi_groups, ARRAY_SIZE(mt7988_spi_groups) }, NULL }, + { { "flash", mt7988_flash_groups, ARRAY_SIZE(mt7988_flash_groups) }, + NULL }, + { { "uart", mt7988_uart_groups, ARRAY_SIZE(mt7988_uart_groups) }, + NULL }, + { { "udi", mt7988_udi_groups, ARRAY_SIZE(mt7988_udi_groups) }, NULL }, + { { "usb", mt7988_usb_groups, ARRAY_SIZE(mt7988_usb_groups) }, NULL }, + { { "led", mt7988_led_groups, ARRAY_SIZE(mt7988_led_groups) }, NULL }, +}; + +static const struct mtk_eint_hw mt7988_eint_hw = { + .port_mask = 7, + .ports = 7, + .ap_num = ARRAY_SIZE(mt7988_pins), + .db_cnt = 16, +}; + +static const char * const mt7988_pinctrl_register_base_names[] = { + "gpio", "iocfg_tr", "iocfg_br", + "iocfg_rb", "iocfg_lb", "iocfg_tl", +}; + +static const struct mtk_pin_soc mt7988_data = { + .reg_cal = mt7988_reg_cals, + .pins = mt7988_pins, + .npins = ARRAY_SIZE(mt7988_pins), + .grps = mt7988_groups, + .ngrps = ARRAY_SIZE(mt7988_groups), + .funcs = mt7988_functions, + .nfuncs = ARRAY_SIZE(mt7988_functions), + .eint_hw = &mt7988_eint_hw, + .gpio_m = 0, + .ies_present = false, + .base_names = mt7988_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7988_pinctrl_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set, + .bias_disable_get = mtk_pinconf_bias_disable_get, + .bias_set = mtk_pinconf_bias_set, + .bias_get = mtk_pinconf_bias_get, + .pull_type = mt7988_pull_type, + .bias_set_combo = mtk_pinconf_bias_set_combo, + .bias_get_combo = mtk_pinconf_bias_get_combo, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +static const struct of_device_id mt7988_pinctrl_of_match[] = { + { .compatible = "mediatek,mt7988-pinctrl" }, + {} +}; + +static int mt7988_pinctrl_probe(struct platform_device *pdev) +{ + return mtk_moore_pinctrl_probe(pdev, &mt7988_data); +} + +static struct platform_driver mt7988_pinctrl_driver = { + .driver = { + .name = "mt7988-pinctrl", + .of_match_table = mt7988_pinctrl_of_match, + }, + .probe = mt7988_pinctrl_probe, +}; + +static int __init mt7988_pinctrl_init(void) +{ + return platform_driver_register(&mt7988_pinctrl_driver); +} +arch_initcall(mt7988_pinctrl_init); -- 2.51.0 From 521e63edd7dc24d0a8474f682ce9256d9456c754 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 8 Jan 2025 22:52:44 +0100 Subject: [PATCH 386/517] pinctrl: mediatek: Drop mtk_pinconf_bias_set_pd() This function is unused and causing compile errors, delete it. Reported-by: Stephen Rothwell Link: https://lore.kernel.org/linux-next/20250106164630.4447cd0d@canb.auug.org.au/ Signed-off-by: Linus Walleij --- .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c index 7b704cc55c9f..00e95682b9f8 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c @@ -599,24 +599,6 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw, return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); } -static int mtk_pinconf_bias_set_pd(struct mtk_pinctrl *hw, - const struct mtk_pin_desc *desc, - u32 pullup, u32 arg) -{ - int err, pd; - - if (arg != MTK_DISABLE && arg != MTK_ENABLE) - return -EINVAL; - - if (arg == MTK_DISABLE || pullup) - pd = 0; - else if (!pullup) - pd = 1; - - return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd); - -} - static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc, u32 pullup, u32 arg) -- 2.51.0 From 4e3da9d88396aac9caa6a20f414ed01d54adc02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 5 Jun 2024 10:54:33 +0200 Subject: [PATCH 387/517] arm64: dts: mediatek: mt7988: add UART controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT7988 has three on-SoC UART controllers that support M16C450 and M16550A modes. Signed-off-by: Rafał Miłecki Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240605085433.26513-2-zajec5@gmail.com Signed-off-by: Matthias Brugger Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 284e240b7997..bf7468c00d11 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -86,7 +86,7 @@ infracfg: clock-controller@10001000 { #clock-cells = <1>; }; - clock-controller@1001b000 { + topckgen: clock-controller@1001b000 { compatible = "mediatek,mt7988-topckgen", "syscon"; reg = <0 0x1001b000 0 0x1000>; #clock-cells = <1>; @@ -124,6 +124,39 @@ pwm@10048000 { status = "disabled"; }; + serial@11000000 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000000 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART0_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + serial@11000100 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000100 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART1_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + serial@11000200 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000200 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART2_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + i2c@11003000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11003000 0 0x1000>, -- 2.51.0 From 24ab7e822a0a6504bdec0061f051edbb3975c767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 13 Jun 2024 21:59:33 +0200 Subject: [PATCH 388/517] arm64: dts: mediatek: mt7988: add efuse block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MT7988 (AKA MediaTek Filogic 880) uses efuse for storing calibration data. Signed-off-by: Rafał Miłecki Link: https://lore.kernel.org/r/20240613195933.31089-2-zajec5@gmail.com Signed-off-by: Matthias Brugger Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index bf7468c00d11..73561c7a3ad2 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -234,6 +234,13 @@ clock-controller@11f40000 { #clock-cells = <1>; }; + efuse@11f50000 { + compatible = "mediatek,mt7988-efuse", "mediatek,efuse"; + reg = <0 0x11f50000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + }; + clock-controller@15000000 { compatible = "mediatek,mt7988-ethsys", "syscon"; reg = <0 0x15000000 0 0x1000>; -- 2.51.0 From d8836ca9c42c01503f86c4f0e239eec89005713a Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 09:54:29 +0100 Subject: [PATCH 389/517] arm64: dts: mediatek: mt7988: Add pinctrl support Add mt7988a pinctrl node. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217085435.9586-5-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 73561c7a3ad2..69998351489d 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -3,6 +3,7 @@ #include #include #include +#include / { compatible = "mediatek,mt7988a"; @@ -105,6 +106,59 @@ clock-controller@1001e000 { #clock-cells = <1>; }; + pio: pinctrl@1001f000 { + compatible = "mediatek,mt7988-pinctrl"; + reg = <0 0x1001f000 0 0x1000>, + <0 0x11c10000 0 0x1000>, + <0 0x11d00000 0 0x1000>, + <0 0x11d20000 0 0x1000>, + <0 0x11e00000 0 0x1000>, + <0 0x11f00000 0 0x1000>, + <0 0x1000b000 0 0x1000>; + reg-names = "gpio", "iocfg_tr", + "iocfg_br", "iocfg_rb", + "iocfg_lb", "iocfg_tl", "eint"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pio 0 0 84>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; + groups = "pcie_2l_0_pereset", "pcie_clk_req_n0_0", + "pcie_wake_n0_0"; + }; + }; + + pcie1_pins: pcie1-pins { + mux { + function = "pcie"; + groups = "pcie_2l_1_pereset", "pcie_clk_req_n1", + "pcie_wake_n1_0"; + }; + }; + + pcie2_pins: pcie2-pins { + mux { + function = "pcie"; + groups = "pcie_1l_0_pereset", "pcie_clk_req_n2_0", + "pcie_wake_n2_0"; + }; + }; + + pcie3_pins: pcie3-pins { + mux { + function = "pcie"; + groups = "pcie_1l_1_pereset", "pcie_clk_req_n3", + "pcie_wake_n3_0"; + }; + }; + }; + pwm@10048000 { compatible = "mediatek,mt7988-pwm"; reg = <0 0x10048000 0 0x1000>; -- 2.51.0 From f2c71d82b159b8019e0cc8e1845aa1b8905564e4 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:15 +0100 Subject: [PATCH 390/517] arm64: dts: mediatek: mt7988: Add reserved memory Add memory range handled by ATF to not be touched by linux kernel. ATF is SoC specific and not board-specific so add it to mt7988.dtsi. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-2-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 69998351489d..8fc7160e23a8 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -62,6 +62,18 @@ psci { method = "smc"; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 320 KiB reserved for ARM Trusted Firmware (BL31 and BL32) */ + secmon@43000000 { + reg = <0 0x43000000 0 0x50000>; + no-map; + }; + }; + soc { compatible = "simple-bus"; ranges; -- 2.51.0 From 47c00a33f75dfb3da9f42b1e934d0491df437b92 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:16 +0100 Subject: [PATCH 391/517] arm64: dts: mediatek: mt7988: Add mmc support Add devicetree node for MMC controller. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-3-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 8fc7160e23a8..62c2befb2f94 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -112,7 +112,7 @@ watchdog: watchdog@1001c000 { #reset-cells = <1>; }; - clock-controller@1001e000 { + apmixedsys: clock-controller@1001e000 { compatible = "mediatek,mt7988-apmixedsys"; reg = <0 0x1001e000 0 0x1000>; #clock-cells = <1>; @@ -293,6 +293,25 @@ usb@11200000 { clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; }; + mmc0: mmc@11230000 { + compatible = "mediatek,mt7988-mmc"; + reg = <0 0x11230000 0 0x1000>, + <0 0x11D60000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_MSDC400>, + <&infracfg CLK_INFRA_MSDC2_HCK>, + <&infracfg CLK_INFRA_66M_MSDC_0_HCK>, + <&infracfg CLK_INFRA_133M_MSDC_0_HCK>; + assigned-clocks = <&topckgen CLK_TOP_EMMC_250M_SEL>, + <&topckgen CLK_TOP_EMMC_400M_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_NET1PLL_D5_D2>, + <&apmixedsys CLK_APMIXED_MSDCPLL>; + clock-names = "source", "hclk", "axi_cg", "ahb_cg"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + clock-controller@11f40000 { compatible = "mediatek,mt7988-xfi-pll"; reg = <0 0x11f40000 0 0x1000>; -- 2.51.0 From 18d2e044598267f937931938ebc27fb564d97c1c Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:17 +0100 Subject: [PATCH 392/517] arm64: dts: mediatek: mt7988: Add lvts node Add Low Voltage Thermal Sensor (LVTS) node for mt7988 SoC. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-4-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 62c2befb2f94..e46f4dc0b453 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -4,6 +4,7 @@ #include #include #include +#include / { compatible = "mediatek,mt7988a"; @@ -97,6 +98,7 @@ infracfg: clock-controller@10001000 { compatible = "mediatek,mt7988-infracfg", "syscon"; reg = <0 0x10001000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; topckgen: clock-controller@1001b000 { @@ -265,6 +267,17 @@ i2c@11005000 { status = "disabled"; }; + lvts: lvts@1100a000 { + compatible = "mediatek,mt7988-lvts-ap"; + #thermal-sensor-cells = <1>; + reg = <0 0x1100a000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_26M_THERM_SYSTEM>; + interrupts = ; + resets = <&infracfg MT7988_INFRA_RST1_THERM_CTRL_SWRST>; + nvmem-cells = <&lvts_calibration>; + nvmem-cell-names = "lvts-calib-data-1"; + }; + usb@11190000 { compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; reg = <0 0x11190000 0 0x2e00>, @@ -324,6 +337,10 @@ efuse@11f50000 { reg = <0 0x11f50000 0 0x1000>; #address-cells = <1>; #size-cells = <1>; + + lvts_calibration: calib@918 { + reg = <0x918 0x28>; + }; }; clock-controller@15000000 { -- 2.51.0 From a2d9e3b266aaf5e9949459218934a94fc7cd85a3 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:18 +0100 Subject: [PATCH 393/517] arm64: dts: mediatek: mt7988: Add thermal-zone Add basic thermal-zone node. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-5-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index e46f4dc0b453..16b28fcf1e3c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -358,6 +358,21 @@ clock-controller@15031000 { }; }; + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + thermal-sensors = <&lvts 0>; + trips { + cpu_trip_crit: crit { + temperature = <125000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupt-parent = <&gic>; -- 2.51.0 From bfde0dd54fbdfb71446eb27aa3ab94feafc012cf Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:20 +0100 Subject: [PATCH 394/517] arm64: dts: mediatek: mt7988: Add mcu-sys node for cpu In preparation for adding support for CPU DVFS and clock tables for it, add the MCUSYS clock controller node. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-7-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 16b28fcf1e3c..5e53ea47f159 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -192,6 +192,12 @@ pwm@10048000 { status = "disabled"; }; + mcusys: mcusys@100e0000 { + compatible = "mediatek,mt7988-mcusys", "syscon"; + reg = <0 0x100e0000 0 0x1000>; + #clock-cells = <1>; + }; + serial@11000000 { compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; reg = <0 0x11000000 0 0x100>; -- 2.51.0 From a148d657d3d03a61d9612b016bfc699693c3dfc9 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:21 +0100 Subject: [PATCH 395/517] arm64: dts: mediatek: mt7988: Add CPU OPP table for clock scaling Add operating points defining frequency/voltages of cpu cores. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-8-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 5e53ea47f159..a7954bf5c81e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -21,6 +21,10 @@ cpu@0 { reg = <0x0>; device_type = "cpu"; enable-method = "psci"; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; }; cpu@1 { @@ -28,6 +32,10 @@ cpu@1 { reg = <0x1>; device_type = "cpu"; enable-method = "psci"; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; }; cpu@2 { @@ -35,6 +43,10 @@ cpu@2 { reg = <0x2>; device_type = "cpu"; enable-method = "psci"; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; }; cpu@3 { @@ -42,6 +54,32 @@ cpu@3 { reg = <0x3>; device_type = "cpu"; enable-method = "psci"; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; + }; + + cluster0_opp: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <850000>; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <850000>; + }; + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <850000>; + }; + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <900000>; + }; }; }; -- 2.51.0 From a32293660d2f75d86ff0510e5080e1b6872cf19d Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:22 +0100 Subject: [PATCH 396/517] arm64: dts: mediatek: mt7988: Disable usb controllers by default The controllers should be enabled at board level if used. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-9-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index a7954bf5c81e..f8b01f3fff32 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -334,6 +334,7 @@ usb@11190000 { <&infracfg CLK_INFRA_133M_USB_HCK>, <&infracfg CLK_INFRA_USB_XHCI>; clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + status = "disabled"; }; usb@11200000 { @@ -348,6 +349,7 @@ usb@11200000 { <&infracfg CLK_INFRA_133M_USB_HCK_CK_P1>, <&infracfg CLK_INFRA_USB_XHCI_CK_P1>; clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + status = "disabled"; }; mmc0: mmc@11230000 { -- 2.51.0 From 1fdb543475c2e842edf667c3012ed827d7986831 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:23 +0100 Subject: [PATCH 397/517] arm64: dts: mediatek: mt7988: Add t-phy for ssusb1 USB controller needs phys for working properly. On mt7988 ssusb0 uses a xs-phy, ssusb uses t-phy. For now add the t-phy for ssusb1. We can reuse the mt7986 compatible here. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-10-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index f8b01f3fff32..209d170bce7f 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -349,6 +349,8 @@ usb@11200000 { <&infracfg CLK_INFRA_133M_USB_HCK_CK_P1>, <&infracfg CLK_INFRA_USB_XHCI_CK_P1>; clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + phys = <&tphyu2port0 PHY_TYPE_USB2>, + <&tphyu3port0 PHY_TYPE_USB3>; status = "disabled"; }; @@ -371,6 +373,29 @@ mmc0: mmc@11230000 { status = "disabled"; }; + t-phy@11c50000 { + compatible = "mediatek,mt7986-tphy", + "mediatek,generic-tphy-v2"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + tphyu2port0: usb-phy@11c50000 { + reg = <0 0x11c50000 0 0x700>; + clocks = <&infracfg CLK_INFRA_USB_UTMI_CK_P1>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + tphyu3port0: usb-phy@11c50700 { + reg = <0 0x11c50700 0 0x900>; + clocks = <&infracfg CLK_INFRA_USB_PIPE_CK_P1>; + clock-names = "ref"; + #phy-cells = <1>; + }; + }; + clock-controller@11f40000 { compatible = "mediatek,mt7988-xfi-pll"; reg = <0 0x11f40000 0 0x1000>; -- 2.51.0 From ba6afcc4d52795e58ce148e960c3fefe94468e69 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:24 +0100 Subject: [PATCH 398/517] arm64: dts: mediatek: mt7988: Add pcie nodes Add pcie controllers for mt7988. Reuse mt7986 compatible. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-11-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 152 ++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 209d170bce7f..74c75d5149d7 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -373,6 +373,158 @@ mmc0: mmc@11230000 { status = "disabled"; }; + pcie@11280000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11280000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <3>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x20000000 0x00 + 0x20000000 0x00 0x00200000>, + <0x82000000 0x00 0x20200000 0x00 + 0x20200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P2>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P2>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P2>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P2>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_pins>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc2 0>, + <0 0 0 2 &pcie_intc2 1>, + <0 0 0 3 &pcie_intc2 2>, + <0 0 0 4 &pcie_intc2 3>; + pcie_intc2: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie@11290000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11290000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <2>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x28000000 0x00 + 0x28000000 0x00 0x00200000>, + <0x82000000 0x00 0x28200000 0x00 + 0x28200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P3>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P3>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P3>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P3>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_pins>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc3 0>, + <0 0 0 2 &pcie_intc3 1>, + <0 0 0 3 &pcie_intc3 2>, + <0 0 0 4 &pcie_intc3 3>; + pcie_intc3: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie@11300000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11300000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <0>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x30000000 0x00 + 0x30000000 0x00 0x00200000>, + <0x82000000 0x00 0x30200000 0x00 + 0x30200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P0>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P0>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P0>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P0>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_pins>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + pcie_intc0: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie@11310000 { + compatible = "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11310000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <1>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x38000000 0x00 + 0x38000000 0x00 0x00200000>, + <0x82000000 0x00 0x38200000 0x00 + 0x38200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P1>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P1>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P1>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P1>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_pins>; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + pcie_intc1: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + t-phy@11c50000 { compatible = "mediatek,mt7986-tphy", "mediatek,generic-tphy-v2"; -- 2.51.0 From a99265c23bb893b0b9c5f5ba13fdacb5a21652ce Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 09:54:30 +0100 Subject: [PATCH 399/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add pinctrl subnodes for bpi-r4 Add board specific pinctrl configurations on Bananapi R4. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217085435.9586-6-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index efc4ad0b08b8..aa2dabc041fd 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -9,3 +9,192 @@ / { model = "Banana Pi BPI-R4"; chassis-type = "embedded"; }; + +&pio { + mdio0_pins: mdio0-pins { + mux { + function = "eth"; + groups = "mdc_mdio0"; + }; + + conf { + pins = "SMI_0_MDC", "SMI_0_MDIO"; + drive-strength = <8>; + }; + }; + + i2c0_pins: i2c0-g0-pins { + mux { + function = "i2c"; + groups = "i2c0_1"; + }; + }; + + i2c1_pins: i2c1-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c1_sfp_pins: i2c1-sfp-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_sfp"; + }; + }; + + i2c2_0_pins: i2c2-g0-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2c2_1_pins: i2c2-g1-pins { + mux { + function = "i2c"; + groups = "i2c2_1"; + }; + }; + + gbe0_led0_pins: gbe0-led0-pins { + mux { + function = "led"; + groups = "gbe0_led0"; + }; + }; + + gbe1_led0_pins: gbe1-led0-pins { + mux { + function = "led"; + groups = "gbe1_led0"; + }; + }; + + gbe2_led0_pins: gbe2-led0-pins { + mux { + function = "led"; + groups = "gbe2_led0"; + }; + }; + + gbe3_led0_pins: gbe3-led0-pins { + mux { + function = "led"; + groups = "gbe3_led0"; + }; + }; + + gbe0_led1_pins: gbe0-led1-pins { + mux { + function = "led"; + groups = "gbe0_led1"; + }; + }; + + gbe1_led1_pins: gbe1-led1-pins { + mux { + function = "led"; + groups = "gbe1_led1"; + }; + }; + + gbe2_led1_pins: gbe2-led1-pins { + mux { + function = "led"; + groups = "gbe2_led1"; + }; + }; + + gbe3_led1_pins: gbe3-led1-pins { + mux { + function = "led"; + groups = "gbe3_led1"; + }; + }; + + i2p5gbe_led0_pins: 2p5gbe-led0-pins { + mux { + function = "led"; + groups = "2p5gbe_led0"; + }; + }; + + i2p5gbe_led1_pins: 2p5gbe-led1-pins { + mux { + function = "led"; + groups = "2p5gbe_led1"; + }; + }; + + mmc0_pins_emmc_45: mmc0-emmc-45-pins { + mux { + function = "flash"; + groups = "emmc_45"; + }; + }; + + mmc0_pins_emmc_51: mmc0-emmc-51-pins { + mux { + function = "flash"; + groups = "emmc_51"; + }; + }; + + mmc0_pins_sdcard: mmc0-sdcard-pins { + mux { + function = "flash"; + groups = "sdcard"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; + + snfi_pins: snfi-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spi0_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0"; + }; + }; + + spi0_flash_pins: spi0-flash-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + }; + + spi1_pins: spi1-pins { + mux { + function = "spi"; + groups = "spi1"; + }; + }; + + spi2_pins: spi2-pins { + mux { + function = "spi"; + groups = "spi2"; + }; + }; + + spi2_flash_pins: spi2-flash-pins { + mux { + function = "spi"; + groups = "spi2", "spi2_wp_hold"; + }; + }; +}; -- 2.51.0 From c311c2eff0873eac18886281d368b42581c01d1c Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:25 +0100 Subject: [PATCH 400/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable watchdog Enable the watchdog on Bananapi R4 board. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-12-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index aa2dabc041fd..d914eae2b524 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -198,3 +198,7 @@ mux { }; }; }; + +&watchdog { + status = "okay"; +}; -- 2.51.0 From 65c66cd8018fd84c92c9ccf5f0c678d50229c7c5 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:26 +0100 Subject: [PATCH 401/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add fixed regulators for 1v8 and 3v3 Add regulator nodes used for mmc to Bananapi R4 board. This board has 1 MMC controller used for SDMMC and eMMC where only one can be used at one time, selected by hardware switches. SD uses 3v3 for both supplies and emmc uses both regulators. So defining both regulators in board dts and referencing them in the dt overlay. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-13-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index d914eae2b524..df53512c6890 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -8,6 +8,24 @@ / { compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; model = "Banana Pi BPI-R4"; chassis-type = "embedded"; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; }; &pio { -- 2.51.0 From fbf80ec8ea987d4b1502f5c3cd828178cd25ae60 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:28 +0100 Subject: [PATCH 402/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add thermal configuration Add additional thermal trips to Bananapi R4 board. SoC only contains the critical trip. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-15-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index df53512c6890..8a320d9da443 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -28,6 +28,34 @@ reg_3p3v: regulator-3p3v { }; }; +&cpu_thermal { + trips { + cpu_trip_hot: hot { + temperature = <120000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_trip_active_high: active-high { + temperature = <115000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_med: active-med { + temperature = <85000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_low: active-low { + temperature = <40000>; + hysteresis = <2000>; + type = "active"; + }; + }; +}; + &pio { mdio0_pins: mdio0-pins { mux { -- 2.51.0 From d9387686201948033cc157e6f558a74355d26df5 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:29 +0100 Subject: [PATCH 403/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable serial0 debug uart Enable the debug uart on Bananapi R4 board. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-16-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 8a320d9da443..9037f35857a9 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -245,6 +245,10 @@ mux { }; }; +&serial0 { + status = "okay"; +}; + &watchdog { status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 74c75d5149d7..59a1ffc2edfc 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -236,7 +236,7 @@ mcusys: mcusys@100e0000 { #clock-cells = <1>; }; - serial@11000000 { + serial0: serial@11000000 { compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; reg = <0 0x11000000 0 0x100>; interrupts = ; -- 2.51.0 From cf8247feecf2566f95bffc1b759132155c0f00de Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:30 +0100 Subject: [PATCH 404/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add default UART stdout Add chosen node on Bananapi R4 board with stdout and default bootargs. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-17-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 9037f35857a9..46117df7d44c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -9,6 +9,10 @@ / { model = "Banana Pi BPI-R4"; chassis-type = "embedded"; + chosen { + stdout-path = "serial0:115200n8"; + }; + reg_1p8v: regulator-1p8v { compatible = "regulator-fixed"; regulator-name = "fixed-1.8V"; -- 2.51.0 From 0ae0dc4c7db9945521c400ffdf8f02879b50689c Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:31 +0100 Subject: [PATCH 405/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable I2C controllers Enable the I2C0, I2C2 controllers found on the BananaPi R4 board. Both controllers are not accessible from user and having fixed spare devices. I2C0 have a pmic connected, I2C2 is used with I2C-multiplexer for e.g. SFP cages. The missing I2C1 is connected to GPIO header which can have either GPIO mode or I2C mode. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-18-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 12 ++++++++++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 46117df7d44c..3d165f7b29dc 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -60,6 +60,18 @@ cpu_trip_active_low: active-low { }; }; +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_1_pins>; + status = "okay"; +}; + &pio { mdio0_pins: mdio0-pins { mux { diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 59a1ffc2edfc..c0a49f68834a 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -269,7 +269,7 @@ serial@11000200 { status = "disabled"; }; - i2c@11003000 { + i2c0: i2c@11003000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11003000 0 0x1000>, <0 0x10217080 0 0x80>; @@ -283,7 +283,7 @@ i2c@11003000 { status = "disabled"; }; - i2c@11004000 { + i2c1: i2c@11004000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11004000 0 0x1000>, <0 0x10217100 0 0x80>; @@ -297,7 +297,7 @@ i2c@11004000 { status = "disabled"; }; - i2c@11005000 { + i2c2: i2c@11005000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11005000 0 0x1000>, <0 0x10217180 0 0x80>; -- 2.51.0 From cb1ff418a05559a1e32911d8721217269d978c3f Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:32 +0100 Subject: [PATCH 406/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add PCA9545 I2C Mux Bananapi R4 uses an i2c multiplexer for SFP slots, rtc and eeprom. Add its node to the right i2c controller. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-19-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 3d165f7b29dc..0dc1fd9265c6 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -2,6 +2,8 @@ /dts-v1/; +#include + #include "mt7988a.dtsi" / { @@ -70,6 +72,45 @@ &i2c2 { pinctrl-names = "default"; pinctrl-0 = <&i2c2_1_pins>; status = "okay"; + + pca9545: i2c-mux@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; + }; + + eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + size = <256>; + }; + + }; + + i2c_sfp1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + i2c_sfp2: i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + }; }; &pio { -- 2.51.0 From fc1e5be0bc78c5339f0d864251b4da8e72a4bf09 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:33 +0100 Subject: [PATCH 407/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable t-phy for ssusb1 Bananapi R4 uses t-phy for usb. Enable its node at board level. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-20-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 0dc1fd9265c6..129031b0d784 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -306,6 +306,10 @@ &serial0 { status = "okay"; }; +&tphy { + status = "okay"; +}; + &watchdog { status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index c0a49f68834a..0766ca0dd3f6 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -525,7 +525,7 @@ pcie_intc1: interrupt-controller { }; }; - t-phy@11c50000 { + tphy: t-phy@11c50000 { compatible = "mediatek,mt7986-tphy", "mediatek,generic-tphy-v2"; #address-cells = <2>; -- 2.51.0 From 622671b5fc76a6544e1394c8ea019ad7e90a22f4 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:34 +0100 Subject: [PATCH 408/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable ssusb1 on bpi-r4 Enable usb on Bananapi R4 board. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-21-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 129031b0d784..08d664d6449b 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -306,6 +306,10 @@ &serial0 { status = "okay"; }; +&ssusb1 { + status = "okay"; +}; + &tphy { status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 0766ca0dd3f6..f3e942db0b99 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -337,7 +337,7 @@ usb@11190000 { status = "disabled"; }; - usb@11200000 { + ssusb1: usb@11200000 { compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; reg = <0 0x11200000 0 0x2e00>, <0 0x11203e00 0 0x0100>; -- 2.51.0 From d985de90a4c6d7b466c7d42d85095604a83a63fe Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:35 +0100 Subject: [PATCH 409/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable pwm Enable pwm on Bananapi R4 board. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-22-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 4 ++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 08d664d6449b..4b1eaf818b66 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -302,6 +302,10 @@ mux { }; }; +&pwm { + status = "okay"; +}; + &serial0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index f3e942db0b99..6f6a1a1c1d78 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -211,7 +211,7 @@ mux { }; }; - pwm@10048000 { + pwm: pwm@10048000 { compatible = "mediatek,mt7988-pwm"; reg = <0 0x10048000 0 0x1000>; clocks = <&infracfg CLK_INFRA_66M_PWM_BCK>, -- 2.51.0 From 0d428f6a03e252a4977c226592370b6057ba47ec Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 17 Dec 2024 10:12:36 +0100 Subject: [PATCH 410/517] arm64: dts: mediatek: mt7988a-bpi-r4: Enable pcie Enable the pci controllers on BPI-R4. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241217091238.16032-23-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 20 +++++++++++++++++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 8 ++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 4b1eaf818b66..d6f1fca3323c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -113,6 +113,26 @@ i2c_sfp2: i2c@2 { }; }; +/* mPCIe SIM2 */ +&pcie0 { + status = "okay"; +}; + +/* mPCIe SIM3 */ +&pcie1 { + status = "okay"; +}; + +/* M.2 key-B SIM1 */ +&pcie2 { + status = "okay"; +}; + +/* M.2 key-M SSD */ +&pcie3 { + status = "okay"; +}; + &pio { mdio0_pins: mdio0-pins { mux { diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 6f6a1a1c1d78..7a5e16a97476 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -373,7 +373,7 @@ mmc0: mmc@11230000 { status = "disabled"; }; - pcie@11280000 { + pcie2: pcie@11280000 { compatible = "mediatek,mt7986-pcie", "mediatek,mt8192-pcie"; device_type = "pci"; @@ -411,7 +411,7 @@ pcie_intc2: interrupt-controller { }; }; - pcie@11290000 { + pcie3: pcie@11290000 { compatible = "mediatek,mt7986-pcie", "mediatek,mt8192-pcie"; device_type = "pci"; @@ -449,7 +449,7 @@ pcie_intc3: interrupt-controller { }; }; - pcie@11300000 { + pcie0: pcie@11300000 { compatible = "mediatek,mt7986-pcie", "mediatek,mt8192-pcie"; device_type = "pci"; @@ -487,7 +487,7 @@ pcie_intc0: interrupt-controller { }; }; - pcie@11310000 { + pcie1: pcie@11310000 { compatible = "mediatek,mt7986-pcie", "mediatek,mt8192-pcie"; device_type = "pci"; -- 2.51.0 From b3e25597ce6ae8971e784945a00c8bdbd7866883 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Fri, 20 Dec 2024 17:38:35 +0100 Subject: [PATCH 411/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add MediaTek MT6682A/RT5190A PMIC Bananapi R4 Board contains a MT6682A pmic which is compatible to rt5190a. Add its node to the i2 controller. The BananaPi R4 board has a MediaTek MT6682A PMIC, a rebrand of the Richtek RT5190A chip, connected to the I2C0 bus. Add the relevant node and, while at it, also configure the regulators from this PMIC that are used on this board. Only Buck2/Buck3 voltage can be controlled by software. BUCK4 input is 5V from BUCK1 output, and the resistor (mapped to RP30/RP31 on BPI-R4) configures BUCK4 output to 1.8V. LDO input is 3.3V from 3.3VD, and the resistor (mapped to RP38/RP40 on BPI-R4) configures LDO output to 1.8V. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241220163838.114786-2-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index d6f1fca3323c..27edc6b84f80 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -3,6 +3,7 @@ /dts-v1/; #include +#include #include "mt7988a.dtsi" @@ -66,6 +67,55 @@ &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; status = "okay"; + + rt5190a_64: rt5190a@64 { + compatible = "richtek,rt5190a"; + reg = <0x64>; + vin2-supply = <&rt5190_buck1>; + vin3-supply = <&rt5190_buck1>; + vin4-supply = <&rt5190_buck1>; + + regulators { + rt5190_buck1: buck1 { + regulator-name = "rt5190a-buck1"; + regulator-min-microvolt = <5090000>; + regulator-max-microvolt = <5090000>; + regulator-allowed-modes = + , ; + regulator-boot-on; + regulator-always-on; + }; + buck2 { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + rt5190_buck3: buck3 { + regulator-name = "vproc"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + buck4 { + regulator-name = "rt5190a-buck4"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-allowed-modes = + , ; + regulator-boot-on; + regulator-always-on; + }; + ldo { + regulator-name = "rt5190a-ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &i2c2 { -- 2.51.0 From 200185c61220ecb7982d5605701649e925c7e11b Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Fri, 20 Dec 2024 17:38:36 +0100 Subject: [PATCH 412/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add proc-supply for cpus Add proc-supply property to cpus on Bananapi R4 board. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20241220163838.114786-3-linux@fw-web.de Signed-off-by: AngeloGioacchino Del Regno --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 16 ++++++++++++++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 27edc6b84f80..6623112c24c7 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -35,6 +35,22 @@ reg_3p3v: regulator-3p3v { }; }; +&cpu0 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu1 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu2 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu3 { + proc-supply = <&rt5190_buck3>; +}; + &cpu_thermal { trips { cpu_trip_hot: hot { diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 7a5e16a97476..88b56a24efca 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -16,7 +16,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { compatible = "arm,cortex-a73"; reg = <0x0>; device_type = "cpu"; @@ -27,7 +27,7 @@ cpu@0 { operating-points-v2 = <&cluster0_opp>; }; - cpu@1 { + cpu1: cpu@1 { compatible = "arm,cortex-a73"; reg = <0x1>; device_type = "cpu"; @@ -38,7 +38,7 @@ cpu@1 { operating-points-v2 = <&cluster0_opp>; }; - cpu@2 { + cpu2: cpu@2 { compatible = "arm,cortex-a73"; reg = <0x2>; device_type = "cpu"; @@ -49,7 +49,7 @@ cpu@2 { operating-points-v2 = <&cluster0_opp>; }; - cpu@3 { + cpu3: cpu@3 { compatible = "arm,cortex-a73"; reg = <0x3>; device_type = "cpu"; -- 2.51.0 From 59d0aeb36921af8a5aea530485a6ede3adf9abc3 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 22 Apr 2025 15:24:29 +0200 Subject: [PATCH 413/517] phy: mediatek: xsphy: support type switch by pericfg Patch from Sam Shih found in MediaTek SDK released under GPL. Get syscon and use it to set the PHY type. Extend support to PCIe and SGMII mode in addition to USB2 and USB3. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno --- drivers/phy/mediatek/phy-mtk-xsphy.c | 85 +++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c index 7c248f5cfca5..c0ddb9273cc3 100644 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include "phy-mtk-io.h" @@ -81,12 +83,22 @@ #define XSP_SR_COEF_DIVISOR 1000 #define XSP_FM_DET_CYCLE_CNT 1024 +/* PHY switch between pcie/usb3/sgmii */ +#define USB_PHY_SWITCH_CTRL 0x0 +#define RG_PHY_SW_TYPE GENMASK(3, 0) +#define RG_PHY_SW_PCIE 0x0 +#define RG_PHY_SW_USB3 0x1 +#define RG_PHY_SW_SGMII 0x2 + struct xsphy_instance { struct phy *phy; void __iomem *port_base; struct clk *ref_clk; /* reference clock of anolog phy */ u32 index; u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; /* only for HQA test */ int efuse_intr; int efuse_tx_imp; @@ -259,6 +271,10 @@ static void phy_parse_property(struct mtk_xsphy *xsphy, inst->efuse_intr, inst->efuse_tx_imp, inst->efuse_rx_imp); break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do */ + break; default: dev_err(xsphy->dev, "incompatible phy type\n"); return; @@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy, RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp); } +/* type switch for usb3/pcie/sgmii */ +static int phy_type_syscon_get(struct xsphy_instance *instance, + struct device_node *dn) +{ + struct of_phandle_args args; + int ret; + + /* type switch function is optional */ + if (!of_property_present(dn, "mediatek,syscon-type")) + return 0; + + ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type", + 2, 0, &args); + if (ret) + return ret; + + instance->type_sw_reg = args.args[0]; + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ + instance->type_sw = syscon_node_to_regmap(args.np); + of_node_put(args.np); + dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n", + instance->type_sw_reg, instance->type_sw_index); + + return PTR_ERR_OR_ZERO(instance->type_sw); +} + +static int phy_type_set(struct xsphy_instance *instance) +{ + int type; + u32 offset; + + if (!instance->type_sw) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB3: + type = RG_PHY_SW_USB3; + break; + case PHY_TYPE_PCIE: + type = RG_PHY_SW_PCIE; + break; + case PHY_TYPE_SGMII: + type = RG_PHY_SW_SGMII; + break; + case PHY_TYPE_USB2: + default: + return 0; + } + + offset = instance->type_sw_index * BITS_PER_BYTE; + regmap_update_bits(instance->type_sw, instance->type_sw_reg, + RG_PHY_SW_TYPE << offset, type << offset); + + return 0; +} + static int mtk_phy_init(struct phy *phy) { struct xsphy_instance *inst = phy_get_drvdata(phy); @@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy) case PHY_TYPE_USB3: u3_phy_props_set(xsphy, inst); break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do, only used to set type */ + break; default: dev_err(xsphy->dev, "incompatible phy type\n"); clk_disable_unprepare(inst->ref_clk); @@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct device *dev, inst->type = args->args[0]; if (!(inst->type == PHY_TYPE_USB2 || - inst->type == PHY_TYPE_USB3)) { + inst->type == PHY_TYPE_USB3 || + inst->type == PHY_TYPE_PCIE || + inst->type == PHY_TYPE_SGMII)) { dev_err(dev, "unsupported phy type: %d\n", inst->type); return ERR_PTR(-EINVAL); } phy_parse_property(xsphy, inst); + phy_type_set(inst); return inst->phy; } @@ -510,6 +589,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev) dev_err(dev, "failed to get ref_clk(id-%d)\n", port); return PTR_ERR(inst->ref_clk); } + + retval = phy_type_syscon_get(inst, child_np); + if (retval) + return retval; } provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); -- 2.51.0 From 15a3afc987aa9c3756760898f296372abd94f71b Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sat, 12 Oct 2024 16:38:23 +0200 Subject: [PATCH 414/517] mmc: mtk-sd: add support for mt7988 Add support for mmc on MT7988 SoC. We can use mt7986 platform data in driver, but mt7988 needs different clocks so for binding we need own compatible. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno Message-ID: <20241012143826.7690-3-linux@fw-web.de> Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index be9954f5bc0a..4a486eb77f3b 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -631,6 +631,7 @@ static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat}, + { .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, -- 2.51.0 From 1cd673167f75da5662cfd2762a35245b0799b743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:38 +0100 Subject: [PATCH 415/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/100-dts-update-mt7622-rfb1.patch --- arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 44 +++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index 8c3e2e2578bc..5280ca95e5c1 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -1,7 +1,6 @@ /* - * Copyright (c) 2017 MediaTek Inc. - * Author: Ming Huang - * Sean Wang + * Copyright (c) 2018 MediaTek Inc. + * Author: Ryder Lee * * SPDX-License-Identifier: (GPL-2.0 OR MIT) */ @@ -24,7 +23,7 @@ aliases { chosen { stdout-path = "serial0:115200n8"; - bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; }; cpus { @@ -45,18 +44,18 @@ gpio-keys { key-factory { label = "factory"; linux,code = ; - gpios = <&pio 0 0>; + gpios = <&pio 0 GPIO_ACTIVE_LOW>; }; key-wps { label = "wps"; linux,code = ; - gpios = <&pio 102 0>; + gpios = <&pio 102 GPIO_ACTIVE_LOW>; }; }; memory@40000000 { - reg = <0 0x40000000 0 0x20000000>; + reg = <0 0x40000000 0 0x40000000>; device_type = "memory"; }; @@ -134,9 +133,9 @@ mdio-bus { #address-cells = <1>; #size-cells = <0>; - switch@0 { + switch@1f { compatible = "mediatek,mt7531"; - reg = <0>; + reg = <31>; reset-gpios = <&pio 54 0>; ports { @@ -145,22 +144,22 @@ ports { port@0 { reg = <0>; - label = "lan0"; + label = "lan1"; }; port@1 { reg = <1>; - label = "lan1"; + label = "lan2"; }; port@2 { reg = <2>; - label = "lan2"; + label = "lan3"; }; port@3 { reg = <3>; - label = "lan3"; + label = "lan4"; }; port@4 { @@ -264,7 +263,22 @@ &pcie0 { status = "okay"; }; +&pcie1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_pins>; + status = "okay"; +}; + &pio { + /* Attention: GPIO 90 is used to switch between PCIe@1,0 and + * SATA functions. i.e. output-high: PCIe, output-low: SATA + */ + asm_sel { + gpio-hog; + gpios = <90 GPIO_ACTIVE_HIGH>; + output-high; + }; + /* eMMC is shared pin with parallel NAND */ emmc_pins_default: emmc-pins-default { mux { @@ -541,11 +555,11 @@ &pwrap { }; &sata { - status = "okay"; + status = "disabled"; }; &sata_phy { - status = "okay"; + status = "disabled"; }; &spi0 { -- 2.51.0 From 98902ead914a8b836afc3adb01d46eeeca1d9fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:39 +0100 Subject: [PATCH 416/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/101-dts-update-mt7629-rfb.patch --- arch/arm/boot/dts/mediatek/mt7629-rfb.dts | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts index f24ebc20732a..c1a306268730 100644 --- a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +++ b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts @@ -18,6 +18,7 @@ aliases { chosen { stdout-path = "serial0:115200n8"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8"; }; gpio-keys { @@ -70,6 +71,10 @@ gmac0: mac@0 { compatible = "mediatek,eth-mac"; reg = <0>; phy-mode = "2500base-x"; + + nvmem-cells = <&macaddr_factory_2a>; + nvmem-cell-names = "mac-address"; + fixed-link { speed = <2500>; full-duplex; @@ -82,6 +87,9 @@ gmac1: mac@1 { reg = <1>; phy-mode = "gmii"; phy-handle = <&phy0>; + + nvmem-cells = <&macaddr_factory_24>; + nvmem-cell-names = "mac-address"; }; mdio: mdio-bus { @@ -133,8 +141,9 @@ factory: partition@70000 { }; partition@b0000 { - label = "kernel"; + label = "firmware"; reg = <0xb0000 0xb50000>; + compatible = "denx,fit"; }; }; }; @@ -273,3 +282,19 @@ &watchdog { pinctrl-0 = <&watchdog_pins>; status = "okay"; }; + +&factory { + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_24: macaddr@24 { + reg = <0x24 0x6>; + }; + + macaddr_factory_2a: macaddr@2a { + reg = <0x2a 0x6>; + }; + }; +}; -- 2.51.0 From 89b17d34e902fd03937449e3bac9fba792144827 Mon Sep 17 00:00:00 2001 From: Chuanhong Guo Date: Fri, 29 Apr 2022 10:40:56 +0800 Subject: [PATCH 417/517] arm: mediatek: select arch timer for mt7623 Signed-off-by: Chuanhong Guo --- arch/arm/mach-mediatek/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 35a3430c7942..8a8d9142260a 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -26,6 +26,7 @@ config MACH_MT6592 config MACH_MT7623 bool "MediaTek MT7623 SoCs support" default ARCH_MEDIATEK + select HAVE_ARM_ARCH_TIMER config MACH_MT7629 bool "MediaTek MT7629 SoCs support" -- 2.51.0 From fe577f41bdfe2ec80ddc1a83bb3b71a6690dd2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:40 +0100 Subject: [PATCH 418/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/104-mt7622-add-snor-irq.patch --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index 917fa39a74f8..bc40287b8f55 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -575,6 +575,7 @@ nor_flash: spi@11014000 { compatible = "mediatek,mt7622-nor", "mediatek,mt8173-nor"; reg = <0 0x11014000 0 0xe0>; + interrupts = ; clocks = <&pericfg CLK_PERI_FLASH_PD>, <&topckgen CLK_TOP_FLASH_SEL>; clock-names = "spi", "sf"; -- 2.51.0 From 6d49971735a5928b5a1b13714f6931bb70a4bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:40 +0100 Subject: [PATCH 419/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/105-dts-mt7622-enable-pstore.patch --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index bc40287b8f55..9aeca60effc0 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -135,6 +135,13 @@ reserved-memory { #size-cells = <2>; ranges; + /* 64 KiB reserved for ramoops/pstore */ + ramoops@42ff0000 { + compatible = "ramoops"; + reg = <0 0x42ff0000 0 0x10000>; + record-size = <0x1000>; + }; + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ secmon_reserved: secmon@43000000 { reg = <0 0x43000000 0 0x30000>; -- 2.51.0 From 840aa57c1c8487ed681cf4dcae1d3d710c0b2b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:41 +0100 Subject: [PATCH 420/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/106-dts-mt7622-disable_btif.patch --- arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 4 ---- arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index d12eac9b3eeb..e516e8357082 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -109,10 +109,6 @@ &bch { status = "disabled"; }; -&btif { - status = "okay"; -}; - &cir { pinctrl-names = "default"; pinctrl-0 = <&irrx_pins>; diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index 5280ca95e5c1..06b708e8fd0e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -90,10 +90,6 @@ &bch { status = "disabled"; }; -&btif { - status = "okay"; -}; - &cir { pinctrl-names = "default"; pinctrl-0 = <&irrx_pins>; -- 2.51.0 From 8240371de56292ac0183c36f963744c6f54df9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:41 +0100 Subject: [PATCH 421/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/110-dts-fix-bpi2-console.patch --- arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index a37f3fa223c7..4275d1214f49 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -19,6 +19,7 @@ aliases { chosen { stdout-path = "serial2:115200n8"; + bootargs = "console=ttyS2,115200n8 console=tty1"; }; connector { -- 2.51.0 From 1afd404bb68fc69428d4e9a312a8a0a4dd49e6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:41 +0100 Subject: [PATCH 422/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/111-dts-fix-bpi64-console.patch --- arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index e516e8357082..6490fa754ddd 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -24,7 +24,7 @@ aliases { chosen { stdout-path = "serial0:115200n8"; - bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; + bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; }; cpus { -- 2.51.0 From ddce26c256090622c46bad02c8b588a096d6c290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:42 +0100 Subject: [PATCH 423/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/112-dts-fix-bpi64-lan-names.patch --- arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 6490fa754ddd..0bea189e91db 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -20,6 +20,7 @@ / { aliases { serial0 = &uart0; + ethernet0 = &gmac0; }; chosen { @@ -164,22 +165,22 @@ port@0 { port@1 { reg = <1>; - label = "lan0"; + label = "lan1"; }; port@2 { reg = <2>; - label = "lan1"; + label = "lan2"; }; port@3 { reg = <3>; - label = "lan2"; + label = "lan3"; }; port@4 { reg = <4>; - label = "lan3"; + label = "lan4"; }; port@5 { -- 2.51.0 From 2fa7e103e880630228e8349e155155ff63baceca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:42 +0100 Subject: [PATCH 424/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/113-dts-fix-bpi64-leds-and-buttons.patch --- .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 0bea189e91db..35b7f3b79d6b 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -21,6 +21,12 @@ / { aliases { serial0 = &uart0; ethernet0 = &gmac0; + led-boot = &led_system_green; + led-failsafe = &led_system_blue; + led-running = &led_system_green; + led-upgrade = &led_system_blue; + mmc0 = &mmc0; + mmc1 = &mmc1; }; chosen { @@ -44,8 +50,8 @@ gpio-keys { compatible = "gpio-keys"; factory-key { - label = "factory"; - linux,code = ; + label = "reset"; + linux,code = ; gpios = <&pio 0 GPIO_ACTIVE_HIGH>; }; @@ -59,17 +65,17 @@ wps-key { leds { compatible = "gpio-leds"; - led-0 { + led_system_green: led-0 { label = "bpi-r64:pio:green"; color = ; gpios = <&pio 89 GPIO_ACTIVE_HIGH>; default-state = "off"; }; - led-1 { - label = "bpi-r64:pio:red"; - color = ; - gpios = <&pio 88 GPIO_ACTIVE_HIGH>; + led_system_blue: led-1 { + label = "bpi-r64:pio:blue"; + color = ; + gpios = <&pio 85 GPIO_ACTIVE_HIGH>; default-state = "off"; }; }; -- 2.51.0 From ead9f5e3bff60916a5920349f44eb821f71468da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:43 +0100 Subject: [PATCH 425/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/114-dts-bpi64-disable-rtc.patch --- arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 35b7f3b79d6b..77ecf5086c2c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -599,6 +599,10 @@ &pwrap { status = "okay"; }; +&rtc { + status = "disabled"; +}; + &sata { status = "disabled"; }; -- 2.51.0 From 1b51556c1ab773999e0472f79357ae4595364e61 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 1 Feb 2025 04:24:17 +0000 Subject: [PATCH 426/517] Revert "arm64: dts: mediatek: fix t-phy unit name" This reverts commit 963c3b0c47ec29b4c49c9f45965cd066f419d17f. --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index 9aeca60effc0..c1fb43eefc83 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -908,7 +908,7 @@ sata: sata@1a200000 { status = "disabled"; }; - sata_phy: t-phy { + sata_phy: t-phy@1a243000 { compatible = "mediatek,mt7622-tphy", "mediatek,generic-tphy-v1"; #address-cells = <2>; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 559990dcd1d1..f9aaf3f20cd7 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -428,7 +428,7 @@ pcie_intc: interrupt-controller { }; }; - pcie_phy: t-phy { + pcie_phy: t-phy@11c00000 { compatible = "mediatek,mt7986-tphy", "mediatek,generic-tphy-v2"; ranges; -- 2.51.0 From fb543ac462d31ffc4d6ed11dad784849cf06b7c4 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 28 Jun 2024 12:55:40 +0200 Subject: [PATCH 427/517] arm64: dts: mediatek: mt7622: readd syscon to pciesys node Sata node reference the pciesys with the property mediatek,phy-node and that is used as a syscon to access the pciesys regs. Readd the syscon compatible to pciesys node to restore correct functionality of the SATA interface. Fixes: 3ba5a6159434 ("arm64: dts: mediatek: mt7622: fix clock controllers") Reported-by: Frank Wunderlich Co-developed-by: Frank Wunderlich Signed-off-by: Frank Wunderlich Signed-off-by: Christian Marangi Cc: stable@vger.kernel.org --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index c1fb43eefc83..f2e526840582 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -798,7 +798,7 @@ u2port1: usb-phy@1a0c5000 { }; pciesys: clock-controller@1a100800 { - compatible = "mediatek,mt7622-pciesys"; + compatible = "mediatek,mt7622-pciesys", "syscon"; reg = <0 0x1a100800 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; -- 2.51.0 From e5cb89538893dfe9c929bda92a429a768aff7b94 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 28 Dec 2022 23:44:42 +0000 Subject: [PATCH 428/517] complete mt7981 dts working: * Ethernet (fully working incl. ppe) * UART * SPI-NAND flash * thermal sensors (SoC and mxl-gpy) * random number generator via SMC * USB 1.1, 2.0 and 3.0 * WiFi with MT7976C 2.4G+5G DBDC incl. WED offloading * PWM --- arch/arm64/boot/dts/mediatek/mt7981b.dtsi | 566 +++++++++++++++++++++- 1 file changed, 554 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi index 5cbea9cd411f..6a816e5c1f46 100644 --- a/arch/arm64/boot/dts/mediatek/mt7981b.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7981b.dtsi @@ -1,7 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT #include +#include +#include #include +#include +#include +#include +#include +#include #include / { @@ -41,6 +48,57 @@ psci { method = "smc"; }; + fan: pwm-fan { + compatible = "pwm-fan"; + /* cooling level (0, 1, 2, 3) : (0% duty, 50% duty, 75% duty, 100% duty) */ + cooling-levels = <0 128 192 255>; + #cooling-cells = <2>; + status = "disabled"; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 64 KiB reserved for ramoops/pstore */ + ramoops@42ff0000 { + compatible = "ramoops"; + reg = <0 0x42ff0000 0 0x10000>; + record-size = <0x1000>; + }; + + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; + no-map; + }; + + wmcpu_emi: wmcpu-reserved@47c80000 { + reg = <0 0x47c80000 0 0x100000>; + no-map; + }; + + wo_emi0: wo-emi@47d80000 { + reg = <0 0x47d80000 0 0x40000>; + no-map; + }; + + wo_data: wo-data@47dc0000 { + reg = <0 0x47dc0000 0 0x240000>; + no-map; + }; + }; + soc { compatible = "simple-bus"; ranges; @@ -76,13 +134,13 @@ watchdog: watchdog@1001c000 { #reset-cells = <1>; }; - clock-controller@1001e000 { - compatible = "mediatek,mt7981-apmixedsys"; + apmixedsys: clock-controller@1001e000 { + compatible = "mediatek,mt7981-apmixedsys", "syscon"; reg = <0 0x1001e000 0 0x1000>; #clock-cells = <1>; }; - pwm@10048000 { + pwm: pwm@10048000 { compatible = "mediatek,mt7981-pwm"; reg = <0 0x10048000 0 0x1000>; clocks = <&infracfg CLK_INFRA_PWM_STA>, @@ -94,7 +152,21 @@ pwm@10048000 { #pwm-cells = <2>; }; - serial@11002000 { + crypto: crypto@10320000 { + compatible = "inside-secure,safexcel-eip97"; + reg = <0 0x10320000 0 0x40000>; + interrupts = , + , + , + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <&topckgen CLK_TOP_EIP97B>; + clock-names = "top_eip97_ck"; + assigned-clocks = <&topckgen CLK_TOP_EIP97B_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_NET1_D5>; + }; + + uart0: serial@11002000 { compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; reg = <0 0x11002000 0 0x100>; interrupts = ; @@ -105,7 +177,7 @@ serial@11002000 { status = "disabled"; }; - serial@11003000 { + uart1: serial@11003000 { compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; reg = <0 0x11003000 0 0x100>; interrupts = ; @@ -116,7 +188,7 @@ serial@11003000 { status = "disabled"; }; - serial@11004000 { + uart2: serial@11004000 { compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart"; reg = <0 0x11004000 0 0x100>; interrupts = ; @@ -127,11 +199,12 @@ serial@11004000 { status = "disabled"; }; - i2c@11007000 { + i2c0: i2c@11007000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11007000 0 0x1000>, <0 0x10217080 0 0x80>; interrupts = ; + clock-div = <1>; clocks = <&infracfg CLK_INFRA_I2C0_CK>, <&infracfg CLK_INFRA_AP_DMA_CK>, <&infracfg CLK_INFRA_I2C_MCK_CK>, @@ -142,7 +215,32 @@ i2c@11007000 { status = "disabled"; }; - spi@11009000 { + thermal: thermal@1100c800 { + #thermal-sensor-cells = <1>; + compatible = "mediatek,mt7981-thermal", "mediatek,mt7986-thermal"; + reg = <0 0x1100c800 0 0x800>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM_CK>, + <&infracfg CLK_INFRA_ADC_26M_CK>; + clock-names = "therm", "auxadc"; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration>; + nvmem-cell-names = "calibration-data"; + }; + + auxadc: adc@1100d000 { + compatible = "mediatek,mt7981-auxadc", + "mediatek,mt7986-auxadc", + "mediatek,mt7622-auxadc"; + reg = <0 0x1100d000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_ADC_26M_CK>, + <&infracfg CLK_INFRA_ADC_FRC_CK>; + clock-names = "main", "32k"; + #io-channel-cells = <1>; + }; + + spi2: spi@11009000 { compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; reg = <0 0x11009000 0 0x1000>; interrupts = ; @@ -156,7 +254,7 @@ spi@11009000 { status = "disabled"; }; - spi@1100a000 { + spi0: spi@1100a000 { compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; reg = <0 0x1100a000 0 0x1000>; interrupts = ; @@ -170,7 +268,7 @@ spi@1100a000 { status = "disabled"; }; - spi@1100b000 { + spi1: spi@1100b000 { compatible = "mediatek,mt7981-spi-ipm", "mediatek,spi-ipm"; reg = <0 0x1100b000 0 0x1000>; interrupts = ; @@ -184,6 +282,41 @@ spi@1100b000 { status = "disabled"; }; + pcie: pcie@11280000 { + compatible = "mediatek,mt7981-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + reg = <0 0x11280000 0 0x4000>; + reg-names = "pcie-mac"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 + 0x0 0x20000000 0 0x10000000>; + status = "disabled"; + + clocks = <&infracfg CLK_INFRA_IPCIE_CK>, + <&infracfg CLK_INFRA_IPCIE_PIPE_CK>, + <&infracfg CLK_INFRA_IPCIER_CK>, + <&infracfg CLK_INFRA_IPCIEB_CK>; + + phys = <&u3port0 PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 0>, + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + pio: pinctrl@11d00000 { compatible = "mediatek,mt7981-pinctrl"; reg = <0 0x11d00000 0 0x1000>, @@ -204,6 +337,49 @@ pio: pinctrl@11d00000 { gpio-controller; #gpio-cells = <2>; #interrupt-cells = <2>; + + mdio_pins: mdc-mdio-pins { + mux { + function = "eth"; + groups = "smi_mdc_mdio"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; + + wifi_dbdc_pins: wifi-dbdc-pins { + mux { + function = "eth"; + groups = "wf0_mode1"; + }; + conf { + pins = "WF_HB1", "WF_HB2", "WF_HB3", "WF_HB4", + "WF_HB0", "WF_HB0_B", "WF_HB5", "WF_HB6", + "WF_HB7", "WF_HB8", "WF_HB9", "WF_HB10", + "WF_TOP_CLK", "WF_TOP_DATA", "WF_XO_REQ", + "WF_CBA_RESETB", "WF_DIG_RESETB"; + drive-strength = ; + }; + }; + + gbe_led0_pins: gbe-led0-pins { + mux { + function = "led"; + groups = "gbe_led0"; + }; + }; + + gbe_led1_pins: gbe-led1-pins { + mux { + function = "led"; + groups = "gbe_led1"; + }; + }; }; efuse@11f20000 { @@ -211,17 +387,318 @@ efuse@11f20000 { reg = <0 0x11f20000 0 0x1000>; #address-cells = <1>; #size-cells = <1>; + + thermal_calibration: thermal-calib@274 { + reg = <0x274 0xc>; + }; + + phy_calibration: phy-calib@8dc { + reg = <0x8dc 0x10>; + }; + + comb_rx_imp_p0: usb3-rx-imp@8c8 { + reg = <0x8c8 1>; + bits = <0 5>; + }; + + comb_tx_imp_p0: usb3-tx-imp@8c8 { + reg = <0x8c8 2>; + bits = <5 5>; + }; + + comb_intr_p0: usb3-intr@8c9 { + reg = <0x8c9 1>; + bits = <2 6>; + }; }; - clock-controller@15000000 { + ethsys: clock-controller@15000000 { compatible = "mediatek,mt7981-ethsys", "syscon"; reg = <0 0x15000000 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; }; - wifi@18000000 { + wed: wed@15010000 { + compatible = "mediatek,mt7981-wed", + "mediatek,mt7986-wed", + "syscon"; + reg = <0 0x15010000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi0>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; + mediatek,wo-ilm = <&wo_ilm0>; + mediatek,wo-dlm = <&wo_dlm0>; + mediatek,wo-cpuboot = <&wo_cpuboot>; + }; + + eth: ethernet@15100000 { + compatible = "mediatek,mt7981-eth"; + reg = <0 0x15100000 0 0x80000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = , + , + , + ; + clocks = <ðsys CLK_ETH_FE_EN>, + <ðsys CLK_ETH_GP2_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_WOCPU0_EN>, + <&sgmiisys0 CLK_SGM0_TX_EN>, + <&sgmiisys0 CLK_SGM0_RX_EN>, + <&sgmiisys0 CLK_SGM0_CK0_EN>, + <&sgmiisys0 CLK_SGM0_CDR_CK0_EN>, + <&sgmiisys1 CLK_SGM1_TX_EN>, + <&sgmiisys1 CLK_SGM1_RX_EN>, + <&sgmiisys1 CLK_SGM1_CK1_EN>, + <&sgmiisys1 CLK_SGM1_CDR_CK1_EN>, + <&topckgen CLK_TOP_SGM_REG>, + <&topckgen CLK_TOP_NETSYS_SEL>, + <&topckgen CLK_TOP_NETSYS_500M_SEL>; + clock-names = "fe", "gp2", "gp1", "wocpu0", + "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "netsys0", "netsys1"; + assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, + <&topckgen CLK_TOP_SGM_325M_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_NET2_800M>, + <&topckgen CLK_TOP_CB_SGM_325M>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,infracfg = <&topmisc>; + mediatek,wed = <&wed>; + status = "disabled"; + + mdio_bus: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + int_gbe_phy: ethernet-phy@0 { + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c22"; + phy-mode = "gmii"; + phy-is-integrated; + nvmem-cells = <&phy_calibration>; + nvmem-cell-names = "phy-cal-data"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + int_gbe_phy_led0: int-gbe-phy-led0@0 { + reg = <0>; + function = LED_FUNCTION_LAN; + pinctrl-0 = <&gbe_led0_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + + int_gbe_phy_led1: int-gbe-phy-led1@1 { + reg = <1>; + function = LED_FUNCTION_LAN; + pinctrl-0 = <&gbe_led1_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + }; + }; + }; + }; + + wdma: wdma@15104800 { + compatible = "mediatek,wed-wdma"; + reg = <0 0x15104800 0 0x400>, + <0 0x15104c00 0 0x400>; + }; + + ap2woccif: ap2woccif@151a5000 { + compatible = "mediatek,ap2woccif"; + reg = <0 0x151a5000 0 0x1000>, + <0 0x151ad000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; + + wo_dlm0: syscon@151e8000 { + compatible = "mediatek,mt7986-wo-dlm", "syscon"; + reg = <0 0x151e8000 0 0x2000>; + }; + + wo_ilm0: syscon@151e0000 { + compatible = "mediatek,mt7986-wo-ilm", "syscon"; + reg = <0 0x151e0000 0 0x8000>; + }; + + wo_cpuboot: syscon@15194000 { + compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; + reg = <0 0x15194000 0 0x1000>; + }; + + wo_ccif0: syscon@151a5000 { + compatible = "mediatek,mt7986-wo-ccif", "syscon"; + reg = <0 0x151a5000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + sgmiisys0: syscon@10060000 { + compatible = "mediatek,mt7981-sgmiisys_0", "mediatek,mt7986-sgmiisys_0", "syscon"; + reg = <0 0x10060000 0 0x1000>; + mediatek,pnswap; + #clock-cells = <1>; + }; + + sgmiisys1: syscon@10070000 { + compatible = "mediatek,mt7981-sgmiisys_1", "mediatek,mt7986-sgmiisys_1", "syscon"; + reg = <0 0x10070000 0 0x1000>; + #clock-cells = <1>; + }; + + topmisc: topmisc@11d10000 { + compatible = "mediatek,mt7981-topmisc", "syscon"; + reg = <0 0x11d10000 0 0x10000>; + #clock-cells = <1>; + }; + + snand: snfi@11005000 { + compatible = "mediatek,mt7986-snand"; + reg = <0 0x11005000 0 0x1000>, <0 0x11006000 0 0x1000>; + reg-names = "nfi", "ecc"; + interrupts = ; + clocks = <&infracfg CLK_INFRA_SPINFI1_CK>, + <&infracfg CLK_INFRA_NFI1_CK>, + <&infracfg CLK_INFRA_NFI_HCK_CK>; + clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; + assigned-clocks = <&topckgen CLK_TOP_SPINFI_SEL>, + <&topckgen CLK_TOP_NFI1X_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D8>, + <&topckgen CLK_TOP_CB_M_D8>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + mmc0: mmc@11230000 { + compatible = "mediatek,mt7986-mmc", + "mediatek,mt7981-mmc"; + reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_MSDC_CK>, + <&infracfg CLK_INFRA_MSDC_HCK_CK>, + <&infracfg CLK_INFRA_MSDC_66M_CK>, + <&infracfg CLK_INFRA_MSDC_133M_CK>; + assigned-clocks = <&topckgen CLK_TOP_EMMC_208M_SEL>, + <&topckgen CLK_TOP_EMMC_400M_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D2>, + <&topckgen CLK_TOP_CB_NET2_D2>; + clock-names = "source", "hclk", "axi_cg", "ahb_cg"; + status = "disabled"; + }; + + wed_pcie: wed_pcie@10003000 { + compatible = "mediatek,wed_pcie"; + reg = <0 0x10003000 0 0x10>; + }; + + consys: consys@10000000 { + compatible = "mediatek,mt7981-consys"; + reg = <0 0x10000000 0 0x8600000>; + memory-region = <&wmcpu_emi>; + }; + + xhci: usb@11200000 { + compatible = "mediatek,mt7986-xhci", + "mediatek,mtk-xhci"; + reg = <0 0x11200000 0 0x2e00>, + <0 0x11203e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + clocks = <&infracfg CLK_INFRA_IUSB_SYS_CK>, + <&infracfg CLK_INFRA_IUSB_CK>, + <&infracfg CLK_INFRA_IUSB_133_CK>, + <&infracfg CLK_INFRA_IUSB_66M_CK>, + <&topckgen CLK_TOP_U2U3_XHCI_SEL>; + clock-names = "sys_ck", + "ref_ck", + "mcu_ck", + "dma_ck", + "xhci_ck"; + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>; + vusb33-supply = <®_3p3v>; + status = "disabled"; + }; + + usb_phy: usb-phy@11e10000 { + compatible = "mediatek,mt7981", + "mediatek,generic-tphy-v2"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x11e10000 0x1700>; + status = "disabled"; + + u2port0: usb-phy@0 { + reg = <0x0 0x700>; + clocks = <&topckgen CLK_TOP_USB_FRMCNT_SEL>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + u3port0: usb-phy@700 { + reg = <0x700 0x900>; + clocks = <&topckgen CLK_TOP_USB3_PHY_SEL>; + clock-names = "ref"; + #phy-cells = <1>; + mediatek,syscon-type = <&topmisc 0x218 0>; + status = "okay"; + }; + }; + + + afe: audio-controller@11210000 { + compatible = "mediatek,mt79xx-audio"; + reg = <0 0x11210000 0 0x9000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, + <&infracfg CLK_INFRA_AUD_26M_CK>, + <&infracfg CLK_INFRA_AUD_L_CK>, + <&infracfg CLK_INFRA_AUD_AUD_CK>, + <&infracfg CLK_INFRA_AUD_EG2_CK>, + <&topckgen CLK_TOP_AUD_SEL>; + clock-names = "aud_bus_ck", + "aud_26m_ck", + "aud_l_ck", + "aud_aud_ck", + "aud_eg2_ck", + "aud_sel"; + assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, + <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_CB_APLL2_196M>, + <&topckgen CLK_TOP_APLL2_D4>, + <&topckgen CLK_TOP_CB_APLL2_196M>, + <&topckgen CLK_TOP_APLL2_D4>; + status = "disabled"; + }; + + ice: ice_debug { + compatible = "mediatek,mt7981-ice_debug", + "mediatek,mt2701-ice_debug"; + clocks = <&infracfg CLK_INFRA_DBG_CK>; + clock-names = "ice_dbg"; + }; + + wifi: wifi@18000000 { compatible = "mediatek,mt7981-wmac"; + pinctrl-0 = <&wifi_dbdc_pins>; + pinctrl-names = "dbdc"; reg = <0 0x18000000 0 0x1000000>, <0 0x10003000 0 0x1000>, <0 0x11d10000 0 0x1000>; @@ -234,6 +711,67 @@ wifi@18000000 { clock-names = "mcu", "ap2conn"; resets = <&watchdog MT7986_TOPRGU_CONSYS_SW_RST>; reset-names = "consys"; + memory-region = <&wmcpu_emi>; + status = "disabled"; + }; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <1000>; + thermal-sensors = <&thermal 0>; + trips { + cpu_trip_crit: crit { + temperature = <125000>; + hysteresis = <2000>; + type = "critical"; + }; + + cpu_trip_hot: hot { + temperature = <120000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_trip_active_high: active-high { + temperature = <115000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_med: active-med { + temperature = <85000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_low: active-low { + temperature = <60000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + cpu-active-high { + /* active: set fan to cooling level 3 */ + cooling-device = <&fan 3 3>; + trip = <&cpu_trip_active_high>; + }; + + cpu-active-med { + /* active: set fan to cooling level 2 */ + cooling-device = <&fan 2 2>; + trip = <&cpu_trip_active_med>; + }; + + cpu-active-low { + /* passive: set fan to cooling level 1 */ + cooling-device = <&fan 1 1>; + trip = <&cpu_trip_active_low>; + }; + }; }; }; @@ -245,4 +783,8 @@ timer { , ; }; + + trng { + compatible = "mediatek,mt7981-rng"; + }; }; -- 2.51.0 From 7d19b9de2f9cfb1e02cd61673bfe0a1f8b8453e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:44 +0100 Subject: [PATCH 429/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/121-hack-spi-nand-1b-bbm.patch --- drivers/mtd/nand/spi/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 8e56ca65ac4f..8a3c9db90c6f 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -913,7 +913,7 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to, static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) { struct spinand_device *spinand = nand_to_spinand(nand); - u8 marker[2] = { }; + u8 marker[1] = { }; struct nand_page_io_req req = { .pos = *pos, .ooblen = sizeof(marker), @@ -924,7 +924,7 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) spinand_select_target(spinand, pos->target); spinand_read_page(spinand, &req); - if (marker[0] != 0xff || marker[1] != 0xff) + if (marker[0] != 0xff) return true; return false; -- 2.51.0 From f657099ea98f26165a6c283903770c12936addc6 Mon Sep 17 00:00:00 2001 From: Xiangsheng Hou Date: Thu, 6 Jun 2019 16:29:04 +0800 Subject: [PATCH 430/517] spi: spi-mem: Mediatek: Add SPI Nand support for MT7629 Signed-off-by: Xiangsheng Hou --- arch/arm/boot/dts/mediatek/mt7629-rfb.dts | 44 +++++++++++++++++++++++ arch/arm/boot/dts/mediatek/mt7629.dtsi | 21 +++++++++++ 2 files changed, 65 insertions(+) diff --git a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts index c1a306268730..b999fae80fed 100644 --- a/arch/arm/boot/dts/mediatek/mt7629-rfb.dts +++ b/arch/arm/boot/dts/mediatek/mt7629-rfb.dts @@ -255,6 +255,50 @@ mux { }; }; +&bch { + status = "okay"; +}; + +&snfi { + pinctrl-names = "default"; + pinctrl-0 = <&serial_nand_pins>; + status = "okay"; + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + nand-ecc-engine = <&snfi>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Bootloader"; + reg = <0x00000 0x0100000>; + read-only; + }; + + partition@100000 { + label = "Config"; + reg = <0x100000 0x0040000>; + }; + + partition@140000 { + label = "factory"; + reg = <0x140000 0x0080000>; + }; + + partition@1c0000 { + label = "firmware"; + reg = <0x1c0000 0x1000000>; + }; + }; + }; +}; + &spi { pinctrl-names = "default"; pinctrl-0 = <&spi_pins>; diff --git a/arch/arm/boot/dts/mediatek/mt7629.dtsi b/arch/arm/boot/dts/mediatek/mt7629.dtsi index acab0883a3bb..cdbe85d8b030 100644 --- a/arch/arm/boot/dts/mediatek/mt7629.dtsi +++ b/arch/arm/boot/dts/mediatek/mt7629.dtsi @@ -271,6 +271,27 @@ i2c: i2c@11007000 { status = "disabled"; }; + snfi: spi@1100d000 { + compatible = "mediatek,mt7629-snand"; + reg = <0x1100d000 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFI_PD>, <&pericfg CLK_PERI_SNFI_PD>; + clock-names = "nfi_clk", "pad_clk"; + nand-ecc-engine = <&bch>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + bch: ecc@1100e000 { + compatible = "mediatek,mt7622-ecc"; + reg = <0x1100e000 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFIECC_PD>; + clock-names = "nfiecc_clk"; + status = "disabled"; + }; + spi: spi@1100a000 { compatible = "mediatek,mt7629-spi", "mediatek,mt7622-spi"; -- 2.51.0 From cac818b46d4cc0b9162576bf3e338ac2bdca1d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:44 +0100 Subject: [PATCH 431/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/131-dts-mt7622-add-snand-support.patch --- arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index 06b708e8fd0e..e64201b79292 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -558,6 +558,65 @@ &sata_phy { status = "disabled"; }; +&bch { + status = "okay"; +}; + +&snfi { + pinctrl-names = "default"; + pinctrl-0 = <&serial_nand_pins>; + status = "okay"; + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + nand-ecc-engine = <&snfi>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Preloader"; + reg = <0x00000 0x0080000>; + read-only; + }; + + partition@80000 { + label = "ATF"; + reg = <0x80000 0x0040000>; + }; + + partition@c0000 { + label = "Bootloader"; + reg = <0xc0000 0x0080000>; + }; + + partition@140000 { + label = "Config"; + reg = <0x140000 0x0080000>; + }; + + partition@1c0000 { + label = "Factory"; + reg = <0x1c0000 0x0100000>; + }; + + partition@200000 { + label = "firmware"; + reg = <0x2c0000 0x2000000>; + }; + + partition@2200000 { + label = "User_data"; + reg = <0x22c0000 0x4000000>; + }; + }; + }; +}; + &spi0 { pinctrl-names = "default"; pinctrl-0 = <&spic0_pins>; -- 2.51.0 From 01d5c5c6ba4d56b1908d51aa9327727440bdb0ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:45 +0100 Subject: [PATCH 432/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/140-dts-fix-wmac-support-for-mt7622-rfb1.patch --- arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index e64201b79292..a478bab2e8cf 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -599,7 +599,7 @@ partition@140000 { reg = <0x140000 0x0080000>; }; - partition@1c0000 { + factory: partition@1c0000 { label = "Factory"; reg = <0x1c0000 0x0100000>; }; @@ -660,5 +660,6 @@ &watchdog { &wmac { pinctrl-names = "default"; pinctrl-0 = <&wmac_pins>; + mediatek,mtd-eeprom = <&factory 0x0000>; status = "okay"; }; -- 2.51.0 From 1669509614ddf5ffb64bde85f4bcaafeefb65f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:45 +0100 Subject: [PATCH 433/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/150-dts-mt7623-eip97-inside-secure-support.patch --- arch/arm/boot/dts/mediatek/mt7623.dtsi | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi index fd7a89cc337d..c6b7d1713096 100644 --- a/arch/arm/boot/dts/mediatek/mt7623.dtsi +++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi @@ -995,17 +995,15 @@ gmac1: mac@1 { }; crypto: crypto@1b240000 { - compatible = "mediatek,eip97-crypto"; + compatible = "inside-secure,safexcel-eip97"; reg = <0 0x1b240000 0 0x20000>; interrupts = , , , - , - ; + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; clocks = <ðsys CLK_ETHSYS_CRYPTO>; - clock-names = "cryp"; - power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; - status = "disabled"; + status = "okay"; }; bdpsys: syscon@1c000000 { -- 2.51.0 From 260ac5379c33a9757834519325577441a7b062cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:46 +0100 Subject: [PATCH 434/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/160-dts-mt7623-bpi-r2-earlycon.patch --- arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index 4275d1214f49..f68e99ca7027 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -19,7 +19,7 @@ aliases { chosen { stdout-path = "serial2:115200n8"; - bootargs = "console=ttyS2,115200n8 console=tty1"; + bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; }; connector { -- 2.51.0 From 5303571fd150e453bf13f523f4fc32bc946807e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:46 +0100 Subject: [PATCH 435/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/161-dts-mt7623-bpi-r2-mmc-device-order.patch --- arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index f68e99ca7027..fdec3d8170e6 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -15,6 +15,8 @@ / { aliases { serial2 = &uart2; + mmc0 = &mmc0; + mmc1 = &mmc1; }; chosen { -- 2.51.0 From 2e82a39d56d22f1dc86a594687ebdb74b18910ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:47 +0100 Subject: [PATCH 436/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/162-dts-mt7623-bpi-r2-led-aliases.patch --- arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index fdec3d8170e6..d980f068bde9 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -17,6 +17,10 @@ aliases { serial2 = &uart2; mmc0 = &mmc0; mmc1 = &mmc1; + led-boot = &led_system_green; + led-failsafe = &led_system_blue; + led-running = &led_system_green; + led-upgrade = &led_system_blue; }; chosen { @@ -112,13 +116,13 @@ leds { pinctrl-names = "default"; pinctrl-0 = <&led_pins_a>; - blue { + led_system_blue: blue { label = "bpi-r2:pio:blue"; gpios = <&pio 240 GPIO_ACTIVE_LOW>; default-state = "off"; }; - green { + led_system_green: green { label = "bpi-r2:pio:green"; gpios = <&pio 241 GPIO_ACTIVE_LOW>; default-state = "off"; -- 2.51.0 From c0a89fcb4019825cf792107ebf3295f058f3d0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:47 +0100 Subject: [PATCH 437/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/163-dts-mt7623-bpi-r2-ethernet-alias.patch --- arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index d980f068bde9..7ff310fdb138 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -15,6 +15,7 @@ / { aliases { serial2 = &uart2; + ethernet0 = &gmac0; mmc0 = &mmc0; mmc1 = &mmc1; led-boot = &led_system_green; -- 2.51.0 From 820e8b578867d75a0221837af059984f72a348c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:47 +0100 Subject: [PATCH 438/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/164-dts-mt7623-bpi-r2-rootdisk-for-fitblk.patch --- .../dts/mediatek/mt7623n-bananapi-bpi-r2.dts | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts index 7ff310fdb138..9b1cf2c7f672 100644 --- a/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mediatek/mt7623n-bananapi-bpi-r2.dts @@ -26,7 +26,9 @@ aliases { chosen { stdout-path = "serial2:115200n8"; - bootargs = "earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; + bootargs = "root=/dev/fit0 rootwait earlycon=uart8250,mmio32,0x11004000 console=ttyS2,115200n8 console=tty1"; + rootdisk-emmc = <&emmc_rootdisk>; + rootdisk-sd = <&sd_rootdisk>; }; connector { @@ -338,6 +340,20 @@ &mmc0 { vmmc-supply = <®_3p3v>; vqmmc-supply = <®_1p8v>; non-removable; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "msdos-partitions"; + emmc_rootdisk: block-partition-fit { + partno = <3>; + }; + }; + }; }; &mmc1 { @@ -351,6 +367,20 @@ &mmc1 { cd-gpios = <&pio 261 GPIO_ACTIVE_LOW>; vmmc-supply = <®_3p3v>; vqmmc-supply = <®_3p3v>; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "msdos-partitions"; + sd_rootdisk: block-partition-fit { + partno = <3>; + }; + }; + }; }; &mt6323keys { -- 2.51.0 From 39278041735b59e066bd4440b141b69aaddc07ee Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 22 Apr 2025 15:24:25 +0200 Subject: [PATCH 439/517] arm64: dts: mediatek: mt7988a-bpi-r4: allow hw variants of bpi-r4 Sinovoip has released other variants of Bananapi-R4 board. The known changes affecting only the LAN SFP+ slot which is replaced by a 2.5G phy with optional PoE. Just move the common parts to a new dtsi and keep differences (only i2c for lan-sfp) in dts. Signed-off-by: Frank Wunderlich Acked-by: Krzysztof Kozlowski Reviewed-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/Makefile | 6 + .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 11 + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 400 +----------------- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 399 +++++++++++++++++ 4 files changed, 421 insertions(+), 395 deletions(-) create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index 8fd7b2bb7a15..cd70066352b6 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -21,6 +21,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-2g5.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-emmc.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-sd.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb @@ -90,3 +93,6 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8516-pumpkin.dtb # Device tree overlays support DTC_FLAGS_mt7986a-bananapi-bpi-r3 := -@ DTC_FLAGS_mt7986a-bananapi-bpi-r3-mini := -@ +DTC_FLAGS_mt7988a-bananapi-bpi-r4 := -@ +DTC_FLAGS_mt7988a-bananapi-bpi-r4-2g5 := -@ +DTC_FLAGS_mt8395-radxa-nio-12l := -@ diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts new file mode 100644 index 000000000000..53de9c113f60 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +/dts-v1/; + +#include "mt7988a-bananapi-bpi-r4.dtsi" + +/ { + compatible = "bananapi,bpi-r4-2g5", "bananapi,bpi-r4", "mediatek,mt7988a"; + model = "Banana Pi BPI-R4 (1x SFP+, 1x 2.5GbE)"; + chassis-type = "embedded"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 6623112c24c7..36bd1ef2efab 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -2,408 +2,18 @@ /dts-v1/; -#include -#include - -#include "mt7988a.dtsi" +#include "mt7988a-bananapi-bpi-r4.dtsi" / { compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; - model = "Banana Pi BPI-R4"; + model = "Banana Pi BPI-R4 (2x SFP+)"; chassis-type = "embedded"; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - reg_1p8v: regulator-1p8v { - compatible = "regulator-fixed"; - regulator-name = "fixed-1.8V"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - - reg_3p3v: regulator-3p3v { - compatible = "regulator-fixed"; - regulator-name = "fixed-3.3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - }; }; -&cpu0 { - proc-supply = <&rt5190_buck3>; -}; - -&cpu1 { - proc-supply = <&rt5190_buck3>; -}; - -&cpu2 { - proc-supply = <&rt5190_buck3>; -}; - -&cpu3 { - proc-supply = <&rt5190_buck3>; -}; - -&cpu_thermal { - trips { - cpu_trip_hot: hot { - temperature = <120000>; - hysteresis = <2000>; - type = "hot"; - }; - - cpu_trip_active_high: active-high { - temperature = <115000>; - hysteresis = <2000>; - type = "active"; - }; - - cpu_trip_active_med: active-med { - temperature = <85000>; - hysteresis = <2000>; - type = "active"; - }; - - cpu_trip_active_low: active-low { - temperature = <40000>; - hysteresis = <2000>; - type = "active"; - }; - }; -}; - -&i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pins>; - status = "okay"; - - rt5190a_64: rt5190a@64 { - compatible = "richtek,rt5190a"; - reg = <0x64>; - vin2-supply = <&rt5190_buck1>; - vin3-supply = <&rt5190_buck1>; - vin4-supply = <&rt5190_buck1>; - - regulators { - rt5190_buck1: buck1 { - regulator-name = "rt5190a-buck1"; - regulator-min-microvolt = <5090000>; - regulator-max-microvolt = <5090000>; - regulator-allowed-modes = - , ; - regulator-boot-on; - regulator-always-on; - }; - buck2 { - regulator-name = "vcore"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1400000>; - regulator-boot-on; - regulator-always-on; - }; - rt5190_buck3: buck3 { - regulator-name = "vproc"; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1400000>; - regulator-boot-on; - }; - buck4 { - regulator-name = "rt5190a-buck4"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-allowed-modes = - , ; - regulator-boot-on; - regulator-always-on; - }; - ldo { - regulator-name = "rt5190a-ldo"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - }; - }; -}; - -&i2c2 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c2_1_pins>; - status = "okay"; - - pca9545: i2c-mux@70 { - compatible = "nxp,pca9545"; - reg = <0x70>; - reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; +&pca9545 { + i2c_sfp2: i2c@2 { #address-cells = <1>; #size-cells = <0>; - - i2c@0 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - pcf8563: rtc@51 { - compatible = "nxp,pcf8563"; - reg = <0x51>; - #clock-cells = <0>; - }; - - eeprom@57 { - compatible = "atmel,24c02"; - reg = <0x57>; - size = <256>; - }; - - }; - - i2c_sfp1: i2c@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - }; - - i2c_sfp2: i2c@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - }; - }; -}; - -/* mPCIe SIM2 */ -&pcie0 { - status = "okay"; -}; - -/* mPCIe SIM3 */ -&pcie1 { - status = "okay"; -}; - -/* M.2 key-B SIM1 */ -&pcie2 { - status = "okay"; -}; - -/* M.2 key-M SSD */ -&pcie3 { - status = "okay"; -}; - -&pio { - mdio0_pins: mdio0-pins { - mux { - function = "eth"; - groups = "mdc_mdio0"; - }; - - conf { - pins = "SMI_0_MDC", "SMI_0_MDIO"; - drive-strength = <8>; - }; - }; - - i2c0_pins: i2c0-g0-pins { - mux { - function = "i2c"; - groups = "i2c0_1"; - }; - }; - - i2c1_pins: i2c1-g0-pins { - mux { - function = "i2c"; - groups = "i2c1_0"; - }; - }; - - i2c1_sfp_pins: i2c1-sfp-g0-pins { - mux { - function = "i2c"; - groups = "i2c1_sfp"; - }; - }; - - i2c2_0_pins: i2c2-g0-pins { - mux { - function = "i2c"; - groups = "i2c2_0"; - }; + reg = <2>; }; - - i2c2_1_pins: i2c2-g1-pins { - mux { - function = "i2c"; - groups = "i2c2_1"; - }; - }; - - gbe0_led0_pins: gbe0-led0-pins { - mux { - function = "led"; - groups = "gbe0_led0"; - }; - }; - - gbe1_led0_pins: gbe1-led0-pins { - mux { - function = "led"; - groups = "gbe1_led0"; - }; - }; - - gbe2_led0_pins: gbe2-led0-pins { - mux { - function = "led"; - groups = "gbe2_led0"; - }; - }; - - gbe3_led0_pins: gbe3-led0-pins { - mux { - function = "led"; - groups = "gbe3_led0"; - }; - }; - - gbe0_led1_pins: gbe0-led1-pins { - mux { - function = "led"; - groups = "gbe0_led1"; - }; - }; - - gbe1_led1_pins: gbe1-led1-pins { - mux { - function = "led"; - groups = "gbe1_led1"; - }; - }; - - gbe2_led1_pins: gbe2-led1-pins { - mux { - function = "led"; - groups = "gbe2_led1"; - }; - }; - - gbe3_led1_pins: gbe3-led1-pins { - mux { - function = "led"; - groups = "gbe3_led1"; - }; - }; - - i2p5gbe_led0_pins: 2p5gbe-led0-pins { - mux { - function = "led"; - groups = "2p5gbe_led0"; - }; - }; - - i2p5gbe_led1_pins: 2p5gbe-led1-pins { - mux { - function = "led"; - groups = "2p5gbe_led1"; - }; - }; - - mmc0_pins_emmc_45: mmc0-emmc-45-pins { - mux { - function = "flash"; - groups = "emmc_45"; - }; - }; - - mmc0_pins_emmc_51: mmc0-emmc-51-pins { - mux { - function = "flash"; - groups = "emmc_51"; - }; - }; - - mmc0_pins_sdcard: mmc0-sdcard-pins { - mux { - function = "flash"; - groups = "sdcard"; - }; - }; - - uart0_pins: uart0-pins { - mux { - function = "uart"; - groups = "uart0"; - }; - }; - - snfi_pins: snfi-pins { - mux { - function = "flash"; - groups = "snfi"; - }; - }; - - spi0_pins: spi0-pins { - mux { - function = "spi"; - groups = "spi0"; - }; - }; - - spi0_flash_pins: spi0-flash-pins { - mux { - function = "spi"; - groups = "spi0", "spi0_wp_hold"; - }; - }; - - spi1_pins: spi1-pins { - mux { - function = "spi"; - groups = "spi1"; - }; - }; - - spi2_pins: spi2-pins { - mux { - function = "spi"; - groups = "spi2"; - }; - }; - - spi2_flash_pins: spi2-flash-pins { - mux { - function = "spi"; - groups = "spi2", "spi2_wp_hold"; - }; - }; -}; - -&pwm { - status = "okay"; -}; - -&serial0 { - status = "okay"; -}; - -&ssusb1 { - status = "okay"; -}; - -&tphy { - status = "okay"; -}; - -&watchdog { - status = "okay"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi new file mode 100644 index 000000000000..0d332822971d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +/dts-v1/; + +#include +#include + +#include "mt7988a.dtsi" + +/ { + chosen { + stdout-path = "serial0:115200n8"; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +&cpu0 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu1 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu2 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu3 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu_thermal { + trips { + cpu_trip_hot: hot { + temperature = <120000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpu_trip_active_high: active-high { + temperature = <115000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_med: active-med { + temperature = <85000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_trip_active_low: active-low { + temperature = <40000>; + hysteresis = <2000>; + type = "active"; + }; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + rt5190a_64: rt5190a@64 { + compatible = "richtek,rt5190a"; + reg = <0x64>; + vin2-supply = <&rt5190_buck1>; + vin3-supply = <&rt5190_buck1>; + vin4-supply = <&rt5190_buck1>; + + regulators { + rt5190_buck1: buck1 { + regulator-name = "rt5190a-buck1"; + regulator-min-microvolt = <5090000>; + regulator-max-microvolt = <5090000>; + regulator-allowed-modes = + , ; + regulator-boot-on; + regulator-always-on; + }; + buck2 { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + rt5190_buck3: buck3 { + regulator-name = "vproc"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + buck4 { + regulator-name = "rt5190a-buck4"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-allowed-modes = + , ; + regulator-boot-on; + regulator-always-on; + }; + ldo { + regulator-name = "rt5190a-ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_1_pins>; + status = "okay"; + + pca9545: i2c-mux@70 { + compatible = "nxp,pca9545"; + reg = <0x70>; + reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; + }; + + eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + size = <256>; + }; + + }; + + i2c_sfp1: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; +}; + +/* mPCIe SIM2 */ +&pcie0 { + status = "okay"; +}; + +/* mPCIe SIM3 */ +&pcie1 { + status = "okay"; +}; + +/* M.2 key-B SIM1 */ +&pcie2 { + status = "okay"; +}; + +/* M.2 key-M SSD */ +&pcie3 { + status = "okay"; +}; + +&pio { + mdio0_pins: mdio0-pins { + mux { + function = "eth"; + groups = "mdc_mdio0"; + }; + + conf { + pins = "SMI_0_MDC", "SMI_0_MDIO"; + drive-strength = <8>; + }; + }; + + i2c0_pins: i2c0-g0-pins { + mux { + function = "i2c"; + groups = "i2c0_1"; + }; + }; + + i2c1_pins: i2c1-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c1_sfp_pins: i2c1-sfp-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_sfp"; + }; + }; + + i2c2_0_pins: i2c2-g0-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2c2_1_pins: i2c2-g1-pins { + mux { + function = "i2c"; + groups = "i2c2_1"; + }; + }; + + gbe0_led0_pins: gbe0-led0-pins { + mux { + function = "led"; + groups = "gbe0_led0"; + }; + }; + + gbe1_led0_pins: gbe1-led0-pins { + mux { + function = "led"; + groups = "gbe1_led0"; + }; + }; + + gbe2_led0_pins: gbe2-led0-pins { + mux { + function = "led"; + groups = "gbe2_led0"; + }; + }; + + gbe3_led0_pins: gbe3-led0-pins { + mux { + function = "led"; + groups = "gbe3_led0"; + }; + }; + + gbe0_led1_pins: gbe0-led1-pins { + mux { + function = "led"; + groups = "gbe0_led1"; + }; + }; + + gbe1_led1_pins: gbe1-led1-pins { + mux { + function = "led"; + groups = "gbe1_led1"; + }; + }; + + gbe2_led1_pins: gbe2-led1-pins { + mux { + function = "led"; + groups = "gbe2_led1"; + }; + }; + + gbe3_led1_pins: gbe3-led1-pins { + mux { + function = "led"; + groups = "gbe3_led1"; + }; + }; + + i2p5gbe_led0_pins: 2p5gbe-led0-pins { + mux { + function = "led"; + groups = "2p5gbe_led0"; + }; + }; + + i2p5gbe_led1_pins: 2p5gbe-led1-pins { + mux { + function = "led"; + groups = "2p5gbe_led1"; + }; + }; + + mmc0_pins_emmc_45: mmc0-emmc-45-pins { + mux { + function = "flash"; + groups = "emmc_45"; + }; + }; + + mmc0_pins_emmc_51: mmc0-emmc-51-pins { + mux { + function = "flash"; + groups = "emmc_51"; + }; + }; + + mmc0_pins_sdcard: mmc0-sdcard-pins { + mux { + function = "flash"; + groups = "sdcard"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; + + snfi_pins: snfi-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + spi0_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0"; + }; + }; + + spi0_flash_pins: spi0-flash-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + }; + + spi1_pins: spi1-pins { + mux { + function = "spi"; + groups = "spi1"; + }; + }; + + spi2_pins: spi2-pins { + mux { + function = "spi"; + groups = "spi2"; + }; + }; + + spi2_flash_pins: spi2-flash-pins { + mux { + function = "spi"; + groups = "spi2", "spi2_wp_hold"; + }; + }; +}; + +&pwm { + status = "okay"; +}; + +&serial0 { + status = "okay"; +}; + +&ssusb1 { + status = "okay"; +}; + +&tphy { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; -- 2.51.0 From 85dec32b37881f3eb8fa393afcc9c32d1a685667 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 22 Apr 2025 15:24:30 +0200 Subject: [PATCH 440/517] arm64: dts: mediatek: mt7988: Add xsphy for ssusb0/pcie2 First usb and third pcie controller on mt7988 need a xs-phy to work properly. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 88b56a24efca..a59f8708f0ef 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -334,6 +334,8 @@ usb@11190000 { <&infracfg CLK_INFRA_133M_USB_HCK>, <&infracfg CLK_INFRA_USB_XHCI>; clock-names = "sys_ck", "ref_ck", "mcu_ck", "dma_ck", "xhci_ck"; + phys = <&xphyu2port0 PHY_TYPE_USB2>, + <&xphyu3port0 PHY_TYPE_USB3>; status = "disabled"; }; @@ -398,6 +400,9 @@ pcie2: pcie@11280000 { pinctrl-0 = <&pcie2_pins>; status = "disabled"; + phys = <&xphyu3port0 PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &pcie_intc2 0>, @@ -548,6 +553,37 @@ tphyu3port0: usb-phy@11c50700 { }; }; + + topmisc: system-controller@11d10084 { + compatible = "mediatek,mt7988-topmisc", + "syscon"; + reg = <0 0x11d10084 0 0xff80>; + }; + + xs-phy@11e10000 { + compatible = "mediatek,mt7988-xsphy", + "mediatek,xsphy"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + xphyu2port0: usb-phy@11e10000 { + reg = <0 0x11e10000 0 0x400>; + clocks = <&infracfg CLK_INFRA_USB_UTMI>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + xphyu3port0: usb-phy@11e13000 { + reg = <0 0x11e13400 0 0x500>; + clocks = <&infracfg CLK_INFRA_USB_PIPE>; + clock-names = "ref"; + #phy-cells = <1>; + mediatek,syscon-type = <&topmisc 0x194 0>; + }; + }; + clock-controller@11f40000 { compatible = "mediatek,mt7988-xfi-pll"; reg = <0 0x11f40000 0 0x1000>; -- 2.51.0 From 72b8292bf3f9f14d1effee2ba565704bd95cdaa2 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Tue, 22 Apr 2025 15:24:31 +0200 Subject: [PATCH 441/517] arm64: dts: mediatek: mt7988a-bpi-r4: enable xsphy Enable XS-Phy on Bananapi R4 for pcie2. Signed-off-by: Frank Wunderlich Reviewed-by: AngeloGioacchino Del Regno --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 4 ++++ arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index 0d332822971d..37e541a98ee1 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -397,3 +397,7 @@ &tphy { &watchdog { status = "okay"; }; + +&xsphy { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index a59f8708f0ef..8f6d1dfae24a 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -560,7 +560,7 @@ topmisc: system-controller@11d10084 { reg = <0 0x11d10084 0 0xff80>; }; - xs-phy@11e10000 { + xsphy: xs-phy@11e10000 { compatible = "mediatek,mt7988-xsphy", "mediatek,xsphy"; #address-cells = <2>; -- 2.51.0 From ac56a2fb07e5a0cc06c96d60801d5f6f88a05715 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Wed, 19 Feb 2025 16:39:09 +0800 Subject: [PATCH 442/517] dts: mt7988a: Add built-in ethernet phy firmware node Add built-in ethernet phy firmware node in mt7988a.dtsi. Signed-off-by: Sky Huang --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 8f6d1dfae24a..1bd5f6f7cab9 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -322,6 +322,12 @@ lvts: lvts@1100a000 { nvmem-cell-names = "lvts-calib-data-1"; }; + phyfw: phy-firmware@f000000 { + compatible = "mediatek,2p5gphy-fw"; + reg = <0 0x0f100000 0 0x20000>, + <0 0x0f0f0018 0 0x20>; + }; + usb@11190000 { compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; reg = <0 0x11190000 0 0x2e00>, -- 2.51.0 From 963d669897db001e98a3beda0efdc1c36c416c8f Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:20 +0200 Subject: [PATCH 443/517] arm64: dts: mediatek: mt7988: add spi controllers Add SPI controllers for mt7988. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 1bd5f6f7cab9..00804f5d7cfb 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -311,6 +311,51 @@ i2c2: i2c@11005000 { status = "disabled"; }; + spi0: spi@11007000 { + compatible = "mediatek,mt7988-spi-quad", "mediatek,spi-ipm"; + reg = <0 0x11007000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&infracfg CLK_INFRA_104M_SPI0>, + <&infracfg CLK_INFRA_66M_SPI0_HCK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", + "hclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@11008000 { + compatible = "mediatek,mt7988-spi-single", "mediatek,spi-ipm"; + reg = <0 0x11008000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPIM_MST_SEL>, + <&infracfg CLK_INFRA_104M_SPI1>, + <&infracfg CLK_INFRA_66M_SPI1_HCK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", + "hclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@11009000 { + compatible = "mediatek,mt7988-spi-quad", "mediatek,spi-ipm"; + reg = <0 0x11009000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&infracfg CLK_INFRA_104M_SPI2_BCK>, + <&infracfg CLK_INFRA_66M_SPI2_HCK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", + "hclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + lvts: lvts@1100a000 { compatible = "mediatek,mt7988-lvts-ap"; #thermal-sensor-cells = <1>; -- 2.51.0 From bf8119d36aa8a45ef759d007d1f380559ce5c75b Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:21 +0200 Subject: [PATCH 444/517] arm64: dts: mediatek: mt7988: move uart0 and spi1 pins to soc dtsi In order to use uart0 or spi1 there is only 1 possible pin definition so move them to soc dtsi to reuse them in other boards and avoiding conflict if defined twice. Suggested-by: Daniel Golle Signed-off-by: Frank Wunderlich --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 14 -------------- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index 37e541a98ee1..23b267cd47ac 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -328,13 +328,6 @@ mux { }; }; - uart0_pins: uart0-pins { - mux { - function = "uart"; - groups = "uart0"; - }; - }; - snfi_pins: snfi-pins { mux { function = "flash"; @@ -356,13 +349,6 @@ mux { }; }; - spi1_pins: spi1-pins { - mux { - function = "spi"; - groups = "spi1"; - }; - }; - spi2_pins: spi2-pins { mux { function = "spi"; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 00804f5d7cfb..e6f453cba690 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -209,6 +209,20 @@ mux { "pcie_wake_n3_0"; }; }; + + spi1_pins: spi1-pins { + mux { + function = "spi"; + groups = "spi1"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; }; pwm: pwm@10048000 { @@ -244,6 +258,8 @@ serial0: serial@11000000 { clocks = <&topckgen CLK_TOP_UART_SEL>, <&infracfg CLK_INFRA_52M_UART0_CK>; clock-names = "baud", "bus"; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; status = "disabled"; }; @@ -338,6 +354,8 @@ spi1: spi@11008000 { "hclk"; #address-cells = <1>; #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; status = "disabled"; }; -- 2.51.0 From 47332041261f52b7abadb9697e530606ae4a04d1 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:22 +0200 Subject: [PATCH 445/517] arm64: dts: mediatek: mt7988: add cci node Add cci devicetree node for cpu frequency scaling. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index e6f453cba690..c0012ecc0279 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -12,6 +12,35 @@ / { #address-cells = <2>; #size-cells = <2>; + cci: cci { + compatible = "mediatek,mt8183-cci"; + clocks = <&mcusys CLK_MCU_BUS_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cci", "intermediate"; + operating-points-v2 = <&cci_opp>; + }; + + cci_opp: opp-table-cci { + compatible = "operating-points-v2"; + opp-shared; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <850000>; + }; + opp-660000000 { + opp-hz = /bits/ 64 <660000000>; + opp-microvolt = <850000>; + }; + opp-900000000 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <850000>; + }; + opp-1080000000 { + opp-hz = /bits/ 64 <1080000000>; + opp-microvolt = <900000>; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -25,6 +54,7 @@ cpu0: cpu@0 { <&topckgen CLK_TOP_XTAL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; }; cpu1: cpu@1 { @@ -36,6 +66,7 @@ cpu1: cpu@1 { <&topckgen CLK_TOP_XTAL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; }; cpu2: cpu@2 { @@ -47,6 +78,7 @@ cpu2: cpu@2 { <&topckgen CLK_TOP_XTAL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; }; cpu3: cpu@3 { @@ -58,6 +90,7 @@ cpu3: cpu@3 { <&topckgen CLK_TOP_XTAL>; clock-names = "cpu", "intermediate"; operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; }; cluster0_opp: opp-table-0 { -- 2.51.0 From 8eaa49fa6b1ad51e5ff86d8996611202f0b91f60 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:23 +0200 Subject: [PATCH 446/517] arm64: dts: mediatek: mt7988: add phy calibration efuse subnodes MT7988 contains buildin mt753x switch which needs calibration data from efuse. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index c0012ecc0279..9b5f1d8b7a5e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -702,6 +702,22 @@ efuse@11f50000 { lvts_calibration: calib@918 { reg = <0x918 0x28>; }; + + phy_calibration_p0: calib@940 { + reg = <0x940 0x10>; + }; + + phy_calibration_p1: calib@954 { + reg = <0x954 0x10>; + }; + + phy_calibration_p2: calib@968 { + reg = <0x968 0x10>; + }; + + phy_calibration_p3: calib@97c { + reg = <0x97c 0x10>; + }; }; clock-controller@15000000 { -- 2.51.0 From 55218122074b172b336b24d381b46308fcfef693 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:24 +0200 Subject: [PATCH 447/517] arm64: dts: mediatek: mt7988: add basic ethernet-nodes Add basic ethernet related nodes. Mac1+2 needs pcs (sgmii+usxgmii) to work correctly which will be linked later when driver is merged. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 124 +++++++++++++++++++++- 1 file changed, 121 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 9b5f1d8b7a5e..87c39335c528 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -686,7 +686,28 @@ xphyu3port0: usb-phy@11e13000 { }; }; - clock-controller@11f40000 { + xfi_tphy0: phy@11f20000 { + compatible = "mediatek,mt7988-xfi-tphy"; + reg = <0 0x11f20000 0 0x10000>; + resets = <&watchdog 14>; + clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, + <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>; + clock-names = "xfipll", "topxtal"; + mediatek,usxgmii-performance-errata; + #phy-cells = <0>; + }; + + xfi_tphy1: phy@11f30000 { + compatible = "mediatek,mt7988-xfi-tphy"; + reg = <0 0x11f30000 0 0x10000>; + resets = <&watchdog 15>; + clocks = <&xfi_pll CLK_XFIPLL_PLL_EN>, + <&topckgen CLK_TOP_XFI_PHY_1_XTAL_SEL>; + clock-names = "xfipll", "topxtal"; + #phy-cells = <0>; + }; + + xfi_pll: clock-controller@11f40000 { compatible = "mediatek,mt7988-xfi-pll"; reg = <0 0x11f40000 0 0x1000>; resets = <&watchdog 16>; @@ -720,19 +741,116 @@ phy_calibration_p3: calib@97c { }; }; - clock-controller@15000000 { + ethsys: clock-controller@15000000 { compatible = "mediatek,mt7988-ethsys", "syscon"; reg = <0 0x15000000 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; }; - clock-controller@15031000 { + ethwarp: clock-controller@15031000 { compatible = "mediatek,mt7988-ethwarp"; reg = <0 0x15031000 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; }; + + eth: ethernet@15100000 { + compatible = "mediatek,mt7988-eth"; + reg = <0 0x15100000 0 0x80000>, + <0 0x15400000 0 0x200000>; + interrupts = , + , + , + ; + clocks = <ðsys CLK_ETHDMA_CRYPT0_EN>, + <ðsys CLK_ETHDMA_FE_EN>, + <ðsys CLK_ETHDMA_GP2_EN>, + <ðsys CLK_ETHDMA_GP1_EN>, + <ðsys CLK_ETHDMA_GP3_EN>, + <ðwarp CLK_ETHWARP_WOCPU2_EN>, + <ðwarp CLK_ETHWARP_WOCPU1_EN>, + <ðwarp CLK_ETHWARP_WOCPU0_EN>, + <ðsys CLK_ETHDMA_ESW_EN>, + <&topckgen CLK_TOP_ETH_GMII_SEL>, + <&topckgen CLK_TOP_ETH_REFCK_50M_SEL>, + <&topckgen CLK_TOP_ETH_SYS_200M_SEL>, + <&topckgen CLK_TOP_ETH_SYS_SEL>, + <&topckgen CLK_TOP_ETH_XGMII_SEL>, + <&topckgen CLK_TOP_ETH_MII_SEL>, + <&topckgen CLK_TOP_NETSYS_SEL>, + <&topckgen CLK_TOP_NETSYS_500M_SEL>, + <&topckgen CLK_TOP_NETSYS_PAO_2X_SEL>, + <&topckgen CLK_TOP_NETSYS_SYNC_250M_SEL>, + <&topckgen CLK_TOP_NETSYS_PPEFB_250M_SEL>, + <&topckgen CLK_TOP_NETSYS_WARP_SEL>, + <ðsys CLK_ETHDMA_XGP1_EN>, + <ðsys CLK_ETHDMA_XGP2_EN>, + <ðsys CLK_ETHDMA_XGP3_EN>; + clock-names = "crypto", "fe", "gp2", "gp1", + "gp3", + "ethwarp_wocpu2", "ethwarp_wocpu1", + "ethwarp_wocpu0", "esw", "top_eth_gmii_sel", + "top_eth_refck_50m_sel", "top_eth_sys_200m_sel", + "top_eth_sys_sel", "top_eth_xgmii_sel", + "top_eth_mii_sel", "top_netsys_sel", + "top_netsys_500m_sel", "top_netsys_pao_2x_sel", + "top_netsys_sync_250m_sel", + "top_netsys_ppefb_250m_sel", + "top_netsys_warp_sel","xgp1", "xgp2", "xgp3"; + assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, + <&topckgen CLK_TOP_NETSYS_GSW_SEL>, + <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>, + <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>, + <&topckgen CLK_TOP_SGM_0_SEL>, + <&topckgen CLK_TOP_SGM_1_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>, + <&topckgen CLK_TOP_NET1PLL_D4>, + <&topckgen CLK_TOP_NET1PLL_D8_D4>, + <&topckgen CLK_TOP_NET1PLL_D8_D4>, + <&apmixedsys CLK_APMIXED_SGMPLL>, + <&apmixedsys CLK_APMIXED_SGMPLL>; + mediatek,ethsys = <ðsys>; + mediatek,infracfg = <&topmisc>; + #address-cells = <1>; + #size-cells = <0>; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "internal"; + + fixed-link { + speed = <10000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + status = "disabled"; + }; + + gmac2: mac@2 { + compatible = "mediatek,eth-mac"; + reg = <2>; + status = "disabled"; + }; + + mdio_bus: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + /* internal 2.5G PHY */ + int_2p5g_phy: ethernet-phy@f { + reg = <15>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "internal"; + }; + }; + }; }; thermal-zones { -- 2.51.0 From 19b301d95660bf872d694d0180f3e1fc9eb51a5a Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:19:25 +0200 Subject: [PATCH 448/517] arm64: dts: mediatek: mt7988: add switch node Add mt7988 builtin mt753x switch nodes. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 154 ++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 87c39335c528..f19e884f13be 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -5,6 +5,7 @@ #include #include #include +#include / { compatible = "mediatek,mt7988a"; @@ -748,6 +749,159 @@ ethsys: clock-controller@15000000 { #reset-cells = <1>; }; + switch: switch@15020000 { + compatible = "mediatek,mt7988-switch"; + reg = <0 0x15020000 0 0x8000>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + resets = <ðwarp MT7988_ETHWARP_RST_SWITCH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + gsw_port0: port@0 { + reg = <0>; + phy-mode = "internal"; + phy-handle = <&gsw_phy0>; + }; + + gsw_port1: port@1 { + reg = <1>; + phy-mode = "internal"; + phy-handle = <&gsw_phy1>; + }; + + gsw_port2: port@2 { + reg = <2>; + phy-mode = "internal"; + phy-handle = <&gsw_phy2>; + }; + + gsw_port3: port@3 { + reg = <3>; + phy-mode = "internal"; + phy-handle = <&gsw_phy3>; + }; + + port@6 { + reg = <6>; + ethernet = <&gmac0>; + phy-mode = "internal"; + + fixed-link { + speed = <10000>; + full-duplex; + pause; + }; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + mediatek,pio = <&pio>; + + gsw_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + interrupts = <0>; + phy-mode = "internal"; + nvmem-cells = <&phy_calibration_p0>; + nvmem-cell-names = "phy-cal-data"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + gsw_phy0_led0: led@0 { + reg = <0>; + status = "disabled"; + }; + + gsw_phy0_led1: led@1 { + reg = <1>; + status = "disabled"; + }; + }; + }; + + gsw_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + interrupts = <1>; + phy-mode = "internal"; + nvmem-cells = <&phy_calibration_p1>; + nvmem-cell-names = "phy-cal-data"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + gsw_phy1_led0: led@0 { + reg = <0>; + status = "disabled"; + }; + + gsw_phy1_led1: led@1 { + reg = <1>; + status = "disabled"; + }; + }; + }; + + gsw_phy2: ethernet-phy@2 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <2>; + interrupts = <2>; + phy-mode = "internal"; + nvmem-cells = <&phy_calibration_p2>; + nvmem-cell-names = "phy-cal-data"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + gsw_phy2_led0: led@0 { + reg = <0>; + status = "disabled"; + }; + + gsw_phy2_led1: led@1 { + reg = <1>; + status = "disabled"; + }; + }; + }; + + gsw_phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + interrupts = <3>; + phy-mode = "internal"; + nvmem-cells = <&phy_calibration_p3>; + nvmem-cell-names = "phy-cal-data"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + gsw_phy3_led0: led@0 { + reg = <0>; + status = "disabled"; + }; + + gsw_phy3_led1: led@1 { + reg = <1>; + status = "disabled"; + }; + }; + }; + }; + }; + ethwarp: clock-controller@15031000 { compatible = "mediatek,mt7988-ethwarp"; reg = <0 0x15031000 0 0x1000>; -- 2.51.0 From 7991a17ef4b6834d4ecc1bfb7fa2df0bc2ffff4d Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:26:50 +0200 Subject: [PATCH 449/517] arm64: dts: mediatek: mt7988a-bpi-r4: Add fan and coolingmaps Add Fan and cooling maps for Bananpi-R4 board. Signed-off-by: Frank Wunderlich --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index 23b267cd47ac..c6f84de82a4d 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -12,6 +12,15 @@ chosen { stdout-path = "serial0:115200n8"; }; + fan: pwm-fan { + compatible = "pwm-fan"; + /* cooling level (0, 1, 2, 3) : (0% duty, 30% duty, 50% duty, 100% duty) */ + cooling-levels = <0 80 128 255>; + #cooling-cells = <2>; + pwms = <&pwm 0 50000>; + status = "okay"; + }; + reg_1p8v: regulator-1p8v { compatible = "regulator-fixed"; regulator-name = "fixed-1.8V"; @@ -73,6 +82,26 @@ cpu_trip_active_low: active-low { type = "active"; }; }; + + cooling-maps { + map-cpu-active-high { + /* active: set fan to cooling level 2 */ + cooling-device = <&fan 3 3>; + trip = <&cpu_trip_active_high>; + }; + + map-cpu-active-med { + /* active: set fan to cooling level 1 */ + cooling-device = <&fan 2 2>; + trip = <&cpu_trip_active_med>; + }; + + map-cpu-active-low { + /* active: set fan to cooling level 0 */ + cooling-device = <&fan 1 1>; + trip = <&cpu_trip_active_low>; + }; + }; }; &i2c0 { -- 2.51.0 From 34036bee1ee2975448782b641760094739edb0b2 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:26:51 +0200 Subject: [PATCH 450/517] arm64: dts: mediatek: mt7988a-bpi-r4: configure spi-nodes Configure and enable SPI nodes on Bananapi R4 board. Signed-off-by: Frank Wunderlich --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index c6f84de82a4d..81ba045e0e0e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -401,6 +401,38 @@ &serial0 { status = "okay"; }; +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + status = "okay"; + + spi_nand: flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + }; +}; + +&spi1 { + status = "okay"; +}; + +&spi_nand { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl2"; + reg = <0x0 0x200000>; + read-only; + }; + }; +}; + &ssusb1 { status = "okay"; }; -- 2.51.0 From b3d73b099fe717cb56b4a817cb25f08484f84568 Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:26:52 +0200 Subject: [PATCH 451/517] arm64: dts: mediatek: mt7988a-bpi-r4: add proc-supply for cci CCI requires proc-supply. Add it on board level. Signed-off-by: Frank Wunderlich --- arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index 81ba045e0e0e..afa9e3b2b16a 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -40,6 +40,10 @@ reg_3p3v: regulator-3p3v { }; }; +&cci { + proc-supply = <&rt5190_buck3>; +}; + &cpu0 { proc-supply = <&rt5190_buck3>; }; -- 2.51.0 From 0f84f4d23dd468c858924446723397acf590d0dc Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:26:53 +0200 Subject: [PATCH 452/517] arm64: dts: mediatek: mt7988a-bpi-r4: add sfp cages and link to gmac Add SFP cages to Bananapi-R4 board. The 2.5g phy variant only contains the wan-SFP, so add this to common dtsi and the lan-sfp only to the dual-SFP variant. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 11 +++++++++++ .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 18 ++++++++++++++++++ .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts index 53de9c113f60..574ac1b853a6 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts @@ -9,3 +9,14 @@ / { model = "Banana Pi BPI-R4 (1x SFP+, 1x 2.5GbE)"; chassis-type = "embedded"; }; + +&gmac1 { + phy-mode = "internal"; + phy-connection-type = "internal"; + phy = <&int_2p5g_phy>; +}; + +&int_2p5g_phy { + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 36bd1ef2efab..3136dc4ba4cc 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -8,6 +8,24 @@ / { compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; model = "Banana Pi BPI-R4 (2x SFP+)"; chassis-type = "embedded"; + + /* SFP2 cage (LAN) */ + sfp2: sfp2 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp2>; + los-gpios = <&pio 2 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 83 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 0 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 1 GPIO_ACTIVE_HIGH>; + rate-select0-gpios = <&pio 3 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; +}; + +&gmac1 { + sfp = <&sfp2>; + managed = "in-band-status"; + phy-mode = "usxgmii"; }; &pca9545 { diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index afa9e3b2b16a..d40c8dbcd18e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -38,6 +38,18 @@ reg_3p3v: regulator-3p3v { regulator-boot-on; regulator-always-on; }; + + /* SFP1 cage (WAN) */ + sfp1: sfp1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp1>; + los-gpios = <&pio 54 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 70 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 69 GPIO_ACTIVE_HIGH>; + rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; }; &cci { @@ -108,6 +120,12 @@ map-cpu-active-low { }; }; +&gmac2 { + sfp = <&sfp1>; + managed = "in-band-status"; + phy-mode = "usxgmii"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; -- 2.51.0 From 2fb0f965b31d743d149659417366d2dc2fead79e Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Sun, 11 May 2025 16:26:54 +0200 Subject: [PATCH 453/517] arm64: dts: mediatek: mt7988a-bpi-r4: configure switch phys and leds Assign pinctrl to switch phys and leds. Signed-off-by: Daniel Golle Signed-off-by: Frank Wunderlich --- .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index d40c8dbcd18e..7258039fda58 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -126,6 +126,54 @@ &gmac2 { phy-mode = "usxgmii"; }; +&gsw_phy0 { + pinctrl-names = "gbe-led"; + label = "wan"; + pinctrl-0 = <&gbe0_led0_pins>; +}; + +&gsw_phy0_led0 { + status = "okay"; + function = LED_FUNCTION_WAN; + color = ; +}; + +&gsw_phy1 { + pinctrl-names = "gbe-led"; + label = "lan1"; + pinctrl-0 = <&gbe1_led0_pins>; +}; + +&gsw_phy1_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_phy2 { + pinctrl-names = "gbe-led"; + label = "lan2"; + pinctrl-0 = <&gbe2_led0_pins>; +}; + +&gsw_phy2_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_phy3 { + pinctrl-names = "gbe-led"; + label = "lan3"; + pinctrl-0 = <&gbe3_led0_pins>; +}; + +&gsw_phy3_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; -- 2.51.0 From 1760d4553e831d99af6db3e3d8825f8930d39c0d Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 8 May 2025 04:03:58 +0100 Subject: [PATCH 454/517] arm64: dts: mt7988a: add serial1 and serial2 aliases Add aliases serial1 and serial2, so boards can make use of the auxilary UARTs of the MediaTek MT7988 SoC. Signed-off-by: Daniel Golle --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index f19e884f13be..52b640f31249 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -297,7 +297,7 @@ serial0: serial@11000000 { status = "disabled"; }; - serial@11000100 { + serial1: serial@11000100 { compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; reg = <0 0x11000100 0 0x100>; interrupts = ; @@ -308,7 +308,7 @@ serial@11000100 { status = "disabled"; }; - serial@11000200 { + serial2: serial@11000200 { compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; reg = <0 0x11000200 0 0x100>; interrupts = ; -- 2.51.0 From 6161581d6eeb1e01aefde06e5872308860e1100f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 26 Jun 2025 00:54:32 +0100 Subject: [PATCH 455/517] arm64: dts: mt7988a: complete dtsi Work-in-progress patch to complete mt7988a.dtsi --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 156 +++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 52b640f31249..b2338231fab4 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -193,7 +193,7 @@ apmixedsys: clock-controller@1001e000 { }; pio: pinctrl@1001f000 { - compatible = "mediatek,mt7988-pinctrl"; + compatible = "mediatek,mt7988-pinctrl", "syscon"; reg = <0 0x1001f000 0 0x1000>, <0 0x11c10000 0 0x1000>, <0 0x11d00000 0 0x1000>, @@ -212,6 +212,13 @@ pio: pinctrl@1001f000 { interrupt-parent = <&gic>; #interrupt-cells = <2>; + snfi_pins: snfi-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + pcie0_pins: pcie0-pins { mux { function = "pcie"; @@ -278,6 +285,60 @@ pwm: pwm@10048000 { status = "disabled"; }; + sgmiisys0: syscon@10060000 { + compatible = "mediatek,mt7988-sgmiisys", + "mediatek,mt7988-sgmiisys0", + "syscon", + "simple-mfd"; + reg = <0 0x10060000 0 0x1000>; + resets = <&watchdog 1>; + #clock-cells = <1>; + + sgmiipcs0: pcs { + compatible = "mediatek,mt7988-sgmii"; + clocks = <&topckgen CLK_TOP_SGM_0_SEL>, + <&sgmiisys0 CLK_SGM0_TX_EN>, + <&sgmiisys0 CLK_SGM0_RX_EN>; + clock-names = "sgmii_sel", "sgmii_tx", "sgmii_rx"; + #pcs-cells = <0>; + }; + }; + + sgmiisys1: syscon@10070000 { + compatible = "mediatek,mt7988-sgmiisys", + "mediatek,mt7988-sgmiisys1", + "syscon", + "simple-mfd"; + reg = <0 0x10070000 0 0x1000>; + resets = <&watchdog 2>; + #clock-cells = <1>; + + sgmiipcs1: pcs { + compatible = "mediatek,mt7988-sgmii"; + clocks = <&topckgen CLK_TOP_SGM_1_SEL>, + <&sgmiisys1 CLK_SGM1_TX_EN>, + <&sgmiisys1 CLK_SGM1_RX_EN>; + clock-names = "sgmii_sel", "sgmii_tx", "sgmii_rx"; + #pcs-cells = <0>; + }; + }; + + usxgmiisys0: pcs@10080000 { + compatible = "mediatek,mt7988-usxgmiisys"; + reg = <0 0x10080000 0 0x1000>; + resets = <&watchdog 12>; + clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>; + #pcs-cells = <0>; + }; + + usxgmiisys1: pcs@10081000 { + compatible = "mediatek,mt7988-usxgmiisys"; + reg = <0 0x10081000 0 0x1000>; + resets = <&watchdog 13>; + clocks = <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>; + #pcs-cells = <0>; + }; + mcusys: mcusys@100e0000 { compatible = "mediatek,mt7988-mcusys", "syscon"; reg = <0 0x100e0000 0 0x1000>; @@ -319,6 +380,32 @@ serial2: serial@11000200 { status = "disabled"; }; + snand: spi@11001000 { + compatible = "mediatek,mt7986-snand"; + reg = <0 0x11001000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_SPINFI>, + <&infracfg CLK_INFRA_NFI>, + <&infracfg CLK_INFRA_66M_NFI_HCK>; + clock-names = "pad_clk", "nfi_clk", "nfi_hclk"; + nand-ecc-engine = <&bch>; + mediatek,quad-spi; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&snfi_pins>; + status = "disabled"; + }; + + bch: ecc@11002000 { + compatible = "mediatek,mt7686-ecc"; + reg = <0 0x11002000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_NFI>; + clock-names = "nfiecc_clk"; + status = "disabled"; + }; + i2c0: i2c@11003000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11003000 0 0x1000>, @@ -425,7 +512,7 @@ phyfw: phy-firmware@f000000 { <0 0x0f0f0018 0 0x20>; }; - usb@11190000 { + ssusb0: usb@11190000 { compatible = "mediatek,mt7988-xhci", "mediatek,mtk-xhci"; reg = <0 0x11190000 0 0x2e00>, <0 0x11193e00 0 0x0100>; @@ -459,6 +546,35 @@ ssusb1: usb@11200000 { status = "disabled"; }; + afe: audio-controller@11210000 { + compatible = "mediatek,mt79xx-audio"; + reg = <0 0x11210000 0 0x9000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_66M_AUD_SLV_BCK>, + <&infracfg CLK_INFRA_AUD_26M>, + <&infracfg CLK_INFRA_AUD_L>, + <&infracfg CLK_INFRA_AUD_AUD>, + <&infracfg CLK_INFRA_AUD_EG2>, + <&topckgen CLK_TOP_AUD_SEL>, + <&topckgen CLK_TOP_AUD_I2S_M>; + clock-names = "aud_bus_ck", + "aud_26m_ck", + "aud_l_ck", + "aud_aud_ck", + "aud_eg2_ck", + "aud_sel", + "aud_i2s_m"; + assigned-clocks = <&topckgen CLK_TOP_AUD_SEL>, + <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL2_D4>, + <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL2_D4>; + status = "disabled"; + }; + mmc0: mmc@11230000 { compatible = "mediatek,mt7988-mmc"; reg = <0 0x11230000 0 0x1000>, @@ -721,6 +837,10 @@ efuse@11f50000 { #address-cells = <1>; #size-cells = <1>; + cpufreq_calibration: calib@278 { + reg = <0x278 0x1>; + }; + lvts_calibration: calib@918 { reg = <0x918 0x28>; }; @@ -984,12 +1104,16 @@ fixed-link { gmac1: mac@1 { compatible = "mediatek,eth-mac"; reg = <1>; + pcs-handle = <&sgmiipcs1>, <&usxgmiisys1>; + phys = <&xfi_tphy1>; status = "disabled"; }; gmac2: mac@2 { compatible = "mediatek,eth-mac"; reg = <2>; + pcs-handle = <&sgmiipcs0>, <&usxgmiisys0>; + phys = <&xfi_tphy0>; status = "disabled"; }; @@ -1002,9 +1126,37 @@ int_2p5g_phy: ethernet-phy@f { reg = <15>; compatible = "ethernet-phy-ieee802.3-c45"; phy-mode = "internal"; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + i2p5gbe_led0: i2p5gbe-led0@0 { + reg = <0>; + function = LED_FUNCTION_LAN; + status = "disabled"; + }; + + i2p5gbe_led1: i2p5gbe-led1@1 { + reg = <1>; + function = LED_FUNCTION_LAN; + status = "disabled"; + }; + }; }; }; }; + + crypto: crypto@15600000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0 0x15600000 0 0x180000>; + interrupts = , + , + , + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3"; + status = "okay"; + }; }; thermal-zones { -- 2.51.0 From 35fcc31a8c177e9f346b6556757d3e565c83a136 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 22 Feb 2023 19:15:49 +0000 Subject: [PATCH 456/517] dts: arm64: mediatek: add MT7988A reference board device tree Complete device tree include for the MediaTek MT7988A SoC and make use of it by adding the device tree of the MediaTek MT7988A Reference Board as well as overlays for various options regarding the connected network interfaces and storage devices present. Available options for GMAC1 (eth0): * internal 4-port 1GE switch Available options for GMAC2 (eth1): * internal 2.5G PHY * external MaxLinear 2.5G PHY * external Aquantia AQR113C PHY * SFP+ cage Available options for GMAC3 (eth2): * external MaxLinear 2.5G PHY * external Aquantia AQR113C PHY * SFP+ cage Available storage options: * eMMC * SNFI (ECC-less SPI-NAND with BCH done in SoC) * SPI-NAND (with ECC done by the flash die) * SPI-NOR * SD card Signed-off-by: Sam Shih Signed-off-by: Daniel Golle --- arch/arm64/boot/dts/mediatek/Makefile | 13 + .../boot/dts/mediatek/mt7988a-rfb-emmc.dtso | 62 +++ .../dts/mediatek/mt7988a-rfb-eth1-aqr.dtso | 41 ++ .../mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso | 30 ++ .../dts/mediatek/mt7988a-rfb-eth1-mxl.dtso | 39 ++ .../dts/mediatek/mt7988a-rfb-eth1-sfp.dtso | 47 ++ .../dts/mediatek/mt7988a-rfb-eth2-aqr.dtso | 41 ++ .../dts/mediatek/mt7988a-rfb-eth2-mxl.dtso | 39 ++ .../dts/mediatek/mt7988a-rfb-eth2-sfp.dtso | 47 ++ .../boot/dts/mediatek/mt7988a-rfb-sd.dtso | 60 +++ .../dts/mediatek/mt7988a-rfb-snfi-nand.dtso | 85 ++++ .../mt7988a-rfb-spim-nand-factory.dtso | 87 ++++ .../dts/mediatek/mt7988a-rfb-spim-nand.dtso | 77 +++ .../dts/mediatek/mt7988a-rfb-spim-nor.dtso | 69 +++ arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts | 471 ++++++++++++++++++ 15 files changed, 1208 insertions(+) create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index cd70066352b6..82f7332077c4 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -24,6 +24,19 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-2g5.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-emmc.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4-sd.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-emmc.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-aqr.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-i2p5g-phy.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-mxl.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth1-sfp.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-aqr.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-mxl.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-eth2-sfp.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-sd.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-snfi-nand.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-spim-nand.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-rfb-spim-nor.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt8167-pumpkin.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8173-elm-hana.dtb diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso new file mode 100644 index 000000000000..b430ec3f27b8 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&mmc0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_emmc_51>; + pinctrl-1 = <&mmc0_pins_emmc_51>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + hs400-ds-delay = <0x12814>; + vqmmc-supply = <®_1p8v>; + vmmc-supply = <®_3p3v>; + non-removable; + no-sd; + no-sdio; + status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + + emmc_root: block-partition-production { + partname = "production"; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/chosen"; + __overlay__ { + rootdisk-emmc = <&emmc_root>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso new file mode 100644 index 000000000000..d21a61ad19fe --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-aqr.dtso @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + /* external Aquantia AQR113C */ + phy0: ethernet-phy@0 { + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c45"; + reset-gpios = <&pio 72 GPIO_ACTIVE_LOW>; + reset-assert-us = <100000>; + reset-deassert-us = <221000>; + }; + }; + }; + + fragment@1 { + target = <&gmac1>; + __overlay__ { + phy-mode = "usxgmii"; + phy-connection-type = "usxgmii"; + phy = <&phy0>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso new file mode 100644 index 000000000000..86ab7566dc29 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-i2p5g-phy.dtso @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&gmac1>; + __overlay__ { + phy-mode = "internal"; + phy-connection-type = "internal"; + phy = <&int_2p5g_phy>; + status = "okay"; + }; + }; + + fragment@1 { + target = <&int_2p5g_phy>; + __overlay__ { + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso new file mode 100644 index 000000000000..34a23bbd7eb0 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-mxl.dtso @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + /* external Maxlinear GPY211C */ + phy13: ethernet-phy@13 { + reg = <13>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + }; + }; + + fragment@1 { + target = <&gmac1>; + __overlay__ { + phy-mode = "2500base-x"; + phy-connection-type = "2500base-x"; + phy = <&phy13>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso new file mode 100644 index 000000000000..ef5e4b360441 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth1-sfp.dtso @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&i2c2>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + status = "okay"; + }; + }; + + fragment@1 { + target-path = "/"; + __overlay__ { + sfp_esp1: sfp@1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c2>; + mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; + los-gpios = <&pio 81 GPIO_ACTIVE_HIGH>; + tx-disable-gpios = <&pio 36 GPIO_ACTIVE_HIGH>; + maximum-power-milliwatt = <3000>; + }; + }; + }; + + fragment@2 { + target = <&gmac1>; + __overlay__ { + phy-mode = "10gbase-r"; + managed = "in-band-status"; + sfp = <&sfp_esp1>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso new file mode 100644 index 000000000000..140391fc45a8 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-aqr.dtso @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + /* external Aquantia AQR113C */ + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "ethernet-phy-ieee802.3-c45"; + reset-gpios = <&pio 71 GPIO_ACTIVE_LOW>; + reset-assert-us = <100000>; + reset-deassert-us = <221000>; + }; + }; + }; + + fragment@1 { + target = <&gmac2>; + __overlay__ { + phy-mode = "usxgmii"; + phy-connection-type = "usxgmii"; + phy = <&phy8>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso new file mode 100644 index 000000000000..19e0b2799fc8 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-mxl.dtso @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&mdio_bus>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + /* external Maxlinear GPY211C */ + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + }; + }; + + fragment@1 { + target = <&gmac2>; + __overlay__ { + phy-mode = "2500base-x"; + phy-connection-type = "2500base-x"; + phy = <&phy5>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso new file mode 100644 index 000000000000..83d65322eb0e --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-eth2-sfp.dtso @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&i2c1>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; + }; + }; + + fragment@1 { + target-path = "/"; + __overlay__ { + sfp_esp0: sfp@0 { + compatible = "sff,sfp"; + i2c-bus = <&i2c1>; + mod-def0-gpios = <&pio 35 GPIO_ACTIVE_LOW>; + los-gpios = <&pio 33 GPIO_ACTIVE_HIGH>; + tx-disable-gpios = <&pio 29 GPIO_ACTIVE_HIGH>; + maximum-power-milliwatt = <3000>; + }; + }; + }; + + fragment@2 { + target = <&gmac2>; + __overlay__ { + phy-mode = "10gbase-r"; + managed = "in-band-status"; + sfp = <&sfp_esp0>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso new file mode 100644 index 000000000000..9a06c425a0b2 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target-path = <&mmc0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_sdcard>; + pinctrl-1 = <&mmc0_pins_sdcard>; + cd-gpios = <&pio 69 GPIO_ACTIVE_LOW>; + bus-width = <4>; + max-frequency = <52000000>; + cap-sd-highspeed; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + no-mmc; + status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + + sd_root: block-partition-production { + partname = "production"; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/chosen"; + __overlay__ { + rootdisk-sd = <&sd_root>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso new file mode 100644 index 000000000000..f334de82e9d4 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-snfi-nand.dtso @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&snand>; + __overlay__ { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x00000 0x0200000>; + read-only; + }; + + ubi_part: partition@200000 { + label = "ubi"; + reg = <0x0200000 0x7e00000>; + compatible = "linux,ubi"; + + volumes { + ubi-volume-ubootenv { + volname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + ubi-volume-ubootenv2 { + volname = "ubootenv2"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + snfi_root: ubi-volume-fit { + volname = "fit"; + }; + }; + }; + }; + }; + }; + }; + + fragment@1 { + target = <&bch>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@2 { + target-path = "/chosen"; + __overlay__ { + /* + * U-Boot currently cannot detect diffrentiate between + * SD and SNFI boot media and always uses rootdisk-sd in + * both cases + */ + rootdisk-sd = <&snfi_root>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso new file mode 100644 index 000000000000..4b554a1bdeb4 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-factory.dtso @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&ubi_part>; + + __overlay__ { + volumes { + ubi_factory: ubi-volume-factory { + volname = "factory"; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eeprom_wmac: eeprom@0 { + reg = <0x0 0x1e00>; + }; + + gmac2_mac: eeprom@fffee { + reg = <0xfffee 0x6>; + }; + + gmac1_mac: eeprom@ffff4 { + reg = <0xffff4 0x6>; + }; + + gmac0_mac: eeprom@ffffa { + reg = <0xffffa 0x6>; + }; + }; + }; + }; + }; + }; + + fragment@1 { + target = <&pcie0>; + __overlay__ { + #address-cells = <3>; + #size-cells = <2>; + + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + nvmem-cell-names = "eeprom"; + nvmem-cells = <&eeprom_wmac>; + }; + }; + }; + }; + + fragment@2 { + target = <&gmac0>; + __overlay__ { + nvmem-cell-names = "mac-address"; + nvmem-cells = <&gmac0_mac>; + }; + }; + + fragment@3 { + target = <&gmac1>; + __overlay__ { + nvmem-cell-names = "mac-address"; + nvmem-cells = <&gmac1_mac>; + }; + }; + + fragment@4 { + target = <&gmac2>; + __overlay__ { + nvmem-cell-names = "mac-address"; + nvmem-cells = <&gmac2_mac>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso new file mode 100644 index 000000000000..e7efd375620d --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&spi0>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x00000 0x0200000>; + read-only; + }; + + ubi_part: partition@200000 { + label = "ubi"; + reg = <0x0200000 0x7e00000>; + compatible = "linux,ubi"; + + volumes { + ubi-volume-ubootenv { + volname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + ubi-volume-ubootenv2 { + volname = "ubootenv2"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + ubi_root: ubi-volume-fit { + volname = "fit"; + }; + + }; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "/chosen"; + __overlay__ { + rootdisk-spim-nand = <&ubi_root>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso new file mode 100644 index 000000000000..4c9bc70ff712 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nor.dtso @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a"; + + fragment@0 { + target = <&spi2>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_flash_pins>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-cal-enable; + spi-cal-mode = "read-data"; + spi-cal-datalen = <7>; + spi-cal-data = /bits/ 8 < + 0x53 0x46 0x5F 0x42 0x4F 0x4F 0x54>; /* SF_BOOT */ + spi-cal-addrlen = <1>; + spi-cal-addr = /bits/ 32 <0x0>; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + partition@0 { + label = "BL2"; + reg = <0x0 0x40000>; + }; + partition@40000 { + label = "u-boot-env"; + reg = <0x40000 0x10000>; + }; + partition@50000 { + label = "Factory"; + reg = <0x50000 0x200000>; + }; + partition@250000 { + label = "FIP"; + reg = <0x250000 0x80000>; + }; + nor_root: partition@2D0000 { + label = "firmware"; + reg = <0x2d0000 0x1d30000>; + compatible = "denx,fit"; + }; + }; + }; + }; + + fragment@1 { + target-path = "/chosen"; + __overlay__ { + rootdisk-nor = <&nor_root>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts new file mode 100644 index 000000000000..01989041d9c2 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include +#include +#include + +#include "mt7988a.dtsi" + +/ { + model = "MediaTek MT7988A Reference Board"; + compatible = "mediatek,mt7988a-rfb", + "mediatek,mt7988a"; + + chosen { + bootargs = "console=ttyS0,115200n1 \ + earlycon=uart8250,mmio32,0x11000000 \ + pci=pcie_bus_perf"; + }; + + memory@40000000 { + reg = <0 0x40000000 0 0x40000000>; + device_type = "memory"; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +ð { + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; +}; + +&gmac0 { + status = "okay"; +}; + +&cpu0 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu1 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu2 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu3 { + proc-supply = <&rt5190_buck3>; +}; + +&cci { + proc-supply = <&rt5190_buck3>; +}; + +ð { + status = "okay"; +}; + +&switch { + status = "okay"; +}; + +&gsw_phy0 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe0_led0_pins>; +}; + +&gsw_phy0_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_port0 { + label = "lan0"; +}; + +&gsw_phy1 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe1_led0_pins>; +}; + +&gsw_phy1_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_port1 { + label = "lan1"; +}; + +&gsw_phy2 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe2_led0_pins>; +}; + +&gsw_phy2_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_port2 { + label = "lan2"; +}; + +&gsw_phy3 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe3_led0_pins>; +}; + +&gsw_phy3_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_port3 { + label = "lan3"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + rt5190a_64: rt5190a@64 { + compatible = "richtek,rt5190a"; + reg = <0x64>; + /*interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>;*/ + vin2-supply = <&rt5190_buck1>; + vin3-supply = <&rt5190_buck1>; + vin4-supply = <&rt5190_buck1>; + + regulators { + rt5190_buck1: buck1 { + regulator-name = "rt5190a-buck1"; + regulator-min-microvolt = <5090000>; + regulator-max-microvolt = <5090000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + buck2 { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + rt5190_buck3: buck3 { + regulator-name = "vproc"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + buck4 { + regulator-name = "rt5190a-buck4"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + ldo { + regulator-name = "rt5190a-ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "disabled"; +}; + +&pcie3 { + status = "okay"; +}; + +&pio { + mdio0_pins: mdio0-pins { + mux { + function = "eth"; + groups = "mdc_mdio0"; + }; + + conf { + groups = "mdc_mdio0"; + drive-strength = ; + }; + }; + + gbe0_led0_pins: gbe0-led0-pins { + mux { + function = "led"; + groups = "gbe0_led0"; + }; + }; + + gbe1_led0_pins: gbe1-led0-pins { + mux { + function = "led"; + groups = "gbe1_led0"; + }; + }; + + gbe2_led0_pins: gbe2-led0-pins { + mux { + function = "led"; + groups = "gbe2_led0"; + }; + }; + + gbe3_led0_pins: gbe3-led0-pins { + mux { + function = "led"; + groups = "gbe3_led0"; + }; + }; + + gbe0_led1_pins: gbe0-led1-pins { + mux { + function = "led"; + groups = "gbe0_led1"; + }; + }; + + gbe1_led1_pins: gbe1-led1-pins { + mux { + function = "led"; + groups = "gbe1_led1"; + }; + }; + + gbe2_led1_pins: gbe2-led1-pins { + mux { + function = "led"; + groups = "gbe2_led1"; + }; + }; + + gbe3_led1_pins: gbe3-led1-pins { + mux { + function = "led"; + groups = "gbe3_led1"; + }; + }; + + i2c0_pins: i2c0-g0-pins { + mux { + function = "i2c"; + groups = "i2c0_1"; + }; + }; + + i2c1_pins: i2c1-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c1_sfp_pins: i2c1-sfp-g0-pins { + mux { + function = "i2c"; + groups = "i2c1_sfp"; + }; + }; + + i2c2_0_pins: i2c2-g0-pins { + mux { + function = "i2c"; + groups = "i2c2_0"; + }; + }; + + i2c2_1_pins: i2c2-g1-pins { + mux { + function = "i2c"; + groups = "i2c2_1"; + }; + }; + + i2p5gbe_led0_pins: 2p5gbe-led0-pins { + mux { + function = "led"; + groups = "2p5gbe_led0"; + }; + }; + + i2p5gbe_led1_pins: 2p5gbe-led1-pins { + mux { + function = "led"; + groups = "2p5gbe_led1"; + }; + }; + + mmc0_pins_emmc_51: mmc0-emmc-51-pins { + mux { + function = "flash"; + groups = "emmc_51"; + }; + }; + + mmc0_pins_sdcard: mmc0-sdcard-pins { + mux { + function = "flash"; + groups = "sdcard"; + }; + }; + + spi0_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0"; + }; + }; + + spi0_flash_pins: spi0-flash-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + }; + + spi2_pins: spi2-pins { + mux { + function = "spi"; + groups = "spi2"; + }; + }; + + spi2_flash_pins: spi2-flash-pins { + mux { + function = "spi"; + groups = "spi2", "spi2_wp_hold"; + }; + }; + + uart0_pins: uart0-pins { + mux { + function = "uart"; + groups = "uart0"; + }; + }; + + uart1_0_pins: uart1-0-pins { + mux { + function = "uart"; + groups = "uart1_0"; + }; + }; + + uart1_1_pins: uart1-1-pins { + mux { + function = "uart"; + groups = "uart1_1"; + }; + }; + + uart1_2_pins: uart1-2-pins { + mux { + function = "uart"; + groups = "uart1_2"; + }; + }; + + uart1_2_lite_pins: uart1-2-lite-pins { + mux { + function = "uart"; + groups = "uart1_2_lite"; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2"; + }; + }; + + uart2_0_pins: uart2-0-pins { + mux { + function = "uart"; + groups = "uart2_0"; + }; + }; + + uart2_1_pins: uart2-1-pins { + mux { + function = "uart"; + groups = "uart2_1"; + }; + }; + + uart2_2_pins: uart2-2-pins { + mux { + function = "uart"; + groups = "uart2_2"; + }; + }; + + uart2_3_pins: uart2-3-pins { + mux { + function = "uart"; + groups = "uart2_3"; + }; + }; +}; + +&ssusb0 { + status = "okay"; +}; + +&ssusb1 { + status = "okay"; +}; + +&tphy { + status = "okay"; +}; + +&serial0 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&xsphy { + status = "okay"; +}; -- 2.51.0 From bee4aa5461f67063cafc2a29b4049e844c637b7e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 26 Jul 2023 14:56:28 +0100 Subject: [PATCH 457/517] WIP: add BPi-R4 --- .../mediatek/mt7988a-bananapi-bpi-r4-2g5.dts | 13 + .../mt7988a-bananapi-bpi-r4-emmc.dtso | 56 ++++ .../mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso | 19 ++ .../mediatek/mt7988a-bananapi-bpi-r4-sd.dtso | 54 ++++ .../dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 8 + .../dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 241 +++++++++++++----- 6 files changed, 328 insertions(+), 63 deletions(-) create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts index 574ac1b853a6..a88bc88576d6 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-2g5.dts @@ -20,3 +20,16 @@ &int_2p5g_phy { pinctrl-names = "i2p5gbe-led"; pinctrl-0 = <&i2p5gbe_led0_pins>; }; + +&gmac1 { + phy-mode = "internal"; + phy-connection-type = "internal"; + phy = <&int_2p5g_phy>; + openwrt,netdev-name = "lan4"; + status = "okay"; +}; + +&int_2p5g_phy { + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso new file mode 100644 index 000000000000..92cf2a2e2b53 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtso @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; +}; + +&{/soc/mmc@11230000} { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_emmc_51>; + pinctrl-1 = <&mmc0_pins_emmc_51>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + hs400-ds-delay = <0x12814>; + vqmmc-supply = <®_1p8v>; + vmmc-supply = <®_3p3v>; + non-removable; + no-sd; + no-sdio; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + + emmc_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; +}; + +&{/chosen} { + rootdisk-emmc = <&emmc_rootfs>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso new file mode 100644 index 000000000000..39910b8cfee1 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-rtc.dtso @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 + * Author: Daniel Golle + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; + + fragment@0 { + target = <&pcf8563>; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso new file mode 100644 index 000000000000..8c74010998cb --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4-sd.dtso @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Frank Wunderlich + */ + +/dts-v1/; +/plugin/; + +#include + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; +}; + +&{/soc/mmc@11230000} { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_sdcard>; + pinctrl-1 = <&mmc0_pins_sdcard>; + cd-gpios = <&pio 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + max-frequency = <52000000>; + cap-sd-highspeed; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + no-mmc; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-layout"; + }; + }; + + sd_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; +}; + +&{/chosen} { + rootdisk-sd = <&sd_rootfs>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts index 3136dc4ba4cc..bab30961d6c4 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts @@ -35,3 +35,11 @@ i2c_sfp2: i2c@2 { reg = <2>; }; }; + +&gmac1 { + sfp = <&sfp2>; + managed = "in-band-status"; + phy-mode = "usxgmii"; + openwrt,netdev-name = "sfp-lan"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi index 7258039fda58..f22e5737750c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi @@ -3,6 +3,8 @@ /dts-v1/; #include +#include +#include #include #include "mt7988a.dtsi" @@ -10,6 +12,8 @@ / { chosen { stdout-path = "serial0:115200n8"; + bootargs = "console=ttyS0,115200n1 pci=pcie_bus_perf ubi.block=0,fit root=/dev/fit0"; + rootdisk-spim-nand = <&ubi_rootfs>; }; fan: pwm-fan { @@ -50,6 +54,142 @@ sfp1: sfp1 { rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; maximum-power-milliwatt = <3000>; }; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + ethernet2 = &gmac2; + serial0 = &serial0; + led-boot = &led_green; + led-failsafe = &led_green; + led-running = &led_green; + led-upgrade = &led_green; + }; + + memory@40000000 { + reg = <0x00 0x40000000 0x00 0x10000000>; + device_type = "memory"; + }; + + /* SFP1 cage (WAN) */ + sfp1: sfp1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c_sfp1>; + los-gpios = <&pio 54 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&pio 82 GPIO_ACTIVE_LOW>; + tx-disable-gpios = <&pio 70 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&pio 69 GPIO_ACTIVE_HIGH>; + rate-select0-gpios = <&pio 21 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <3000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + + wps { + label = "WPS"; + linux,code = ; + gpios = <&pio 14 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led_green: led-green { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 79 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + led_blue: led-blue { + function = LED_FUNCTION_WPS; + color = ; + gpios = <&pio 63 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; +}; + +ð { + status = "okay"; +}; + +&gmac0 { + status = "okay"; +}; + +&gmac2 { + sfp = <&sfp1>; + managed = "in-band-status"; + phy-mode = "usxgmii"; + openwrt,netdev-name = "sfp-wan"; + status = "okay"; +}; + +&switch { + status = "okay"; +}; + +&gsw_phy0 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe0_led0_pins>; +}; + +&gsw_port0 { + label = "wan"; +}; + +&gsw_phy0_led0 { + status = "okay"; + function = LED_FUNCTION_WAN; + color = ; +}; + +&gsw_phy1 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe1_led0_pins>; +}; + +&gsw_port1 { + label = "lan1"; +}; + +&gsw_phy1_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_phy2 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe2_led0_pins>; +}; + +&gsw_port2 { + label = "lan2"; +}; + +&gsw_phy2_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; +}; + +&gsw_phy3 { + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe3_led0_pins>; +}; + +&gsw_port3 { + label = "lan3"; +}; + +&gsw_phy3_led0 { + status = "okay"; + function = LED_FUNCTION_LAN; + color = ; }; &cci { @@ -174,6 +314,10 @@ &gsw_phy3_led0 { color = ; }; +&cci { + proc-supply = <&rt5190_buck3>; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; @@ -265,6 +409,14 @@ i2c_sfp1: i2c@1 { #size-cells = <0>; reg = <1>; }; + + i2c_wifi: i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + status = "disabled"; + }; }; }; @@ -364,34 +516,6 @@ mux { }; }; - gbe0_led1_pins: gbe0-led1-pins { - mux { - function = "led"; - groups = "gbe0_led1"; - }; - }; - - gbe1_led1_pins: gbe1-led1-pins { - mux { - function = "led"; - groups = "gbe1_led1"; - }; - }; - - gbe2_led1_pins: gbe2-led1-pins { - mux { - function = "led"; - groups = "gbe2_led1"; - }; - }; - - gbe3_led1_pins: gbe3-led1-pins { - mux { - function = "led"; - groups = "gbe3_led1"; - }; - }; - i2p5gbe_led0_pins: 2p5gbe-led0-pins { mux { function = "led"; @@ -399,13 +523,6 @@ mux { }; }; - i2p5gbe_led1_pins: 2p5gbe-led1-pins { - mux { - function = "led"; - groups = "2p5gbe_led1"; - }; - }; - mmc0_pins_emmc_45: mmc0-emmc-45-pins { mux { function = "flash"; @@ -427,40 +544,12 @@ mux { }; }; - snfi_pins: snfi-pins { - mux { - function = "flash"; - groups = "snfi"; - }; - }; - - spi0_pins: spi0-pins { - mux { - function = "spi"; - groups = "spi0"; - }; - }; - spi0_flash_pins: spi0-flash-pins { mux { function = "spi"; groups = "spi0", "spi0_wp_hold"; }; }; - - spi2_pins: spi2-pins { - mux { - function = "spi"; - groups = "spi2"; - }; - }; - - spi2_flash_pins: spi2-flash-pins { - mux { - function = "spi"; - groups = "spi2", "spi2_wp_hold"; - }; - }; }; &pwm { @@ -500,6 +589,32 @@ partition@0 { reg = <0x0 0x200000>; read-only; }; + + partition@200000 { + label = "ubi"; + reg = <0x200000 0x7e00000>; + compatible = "linux,ubi"; + + volumes { + ubi-volume-ubootenv { + volname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool-layout"; + }; + }; + + ubi-volume-ubootenv2 { + volname = "ubootenv2"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool-layout"; + }; + }; + + ubi_rootfs: ubi-volume-fit { + volname = "fit"; + }; + }; + }; }; }; -- 2.51.0 From e9a4d50305620d1f59c45d3294121bddcff090c7 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 26 Apr 2022 20:51:36 +0100 Subject: [PATCH 458/517] arm64: dts: mediatek: mt7622: fix GICv2 range With the current range specified for the CPU interface there is an error message at boot: GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set Setting irqchip.gicv2_force_probe=1 in bootargs results in: GIC: Aliased GICv2 at 0x0000000010320000, trying to find the canonical range over 128kB GIC: Adjusting CPU interface base to 0x000000001032f000 GIC: Using split EOI/Deactivate mode Using the adjusted CPU interface base and 8K size results in only the final line remaining and fully working system as well as /proc/interrupts showing additional IPI3,4,5,6: IPI3: 0 0 CPU stop (for crash dump) interrupts IPI4: 0 0 Timer broadcast interrupts IPI5: 0 0 IRQ work interrupts IPI6: 0 0 CPU wake-up interrupts Signed-off-by: Daniel Golle --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index f2e526840582..39c57987412e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -345,7 +345,7 @@ gic: interrupt-controller@10300000 { #interrupt-cells = <3>; interrupt-parent = <&gic>; reg = <0 0x10310000 0 0x1000>, - <0 0x10320000 0 0x1000>, + <0 0x1032f000 0 0x2000>, <0 0x10340000 0 0x2000>, <0 0x10360000 0 0x2000>; }; -- 2.51.0 From 0e859ccadea781e3c84c4891d729beb5b5ced245 Mon Sep 17 00:00:00 2001 From: Bruno Umuarama Date: Thu, 13 Oct 2022 21:18:21 +0000 Subject: [PATCH 459/517] mediatek: mt7623: fix thermal zone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Raising the temperatures for passive and active trips. @VA1DER proposed at issue 9396 to remove passive trip. This commit relates to his suggestion. Without this patch. the CPU will be throttled all the way down to 98MHz if the temperature rises even a degree above the trip point, and it was further discovered that if the internal temperature of the device is above the first trip point temperature when it boots then it will start in a throttled state and even $ echo disabled > /sys/class/thermal/thermal_zone0/mode will have no effect. The patch increases the passive trip point and active cooling map. The throttling temperature will then be at 77°C and 82°C, which is still a low enough temperature for ARM devices to not be in the real danger zone, and gives some operational headroom. Signed-off-by: Bruno Umuarama --- arch/arm/boot/dts/mediatek/mt7623.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/mediatek/mt7623.dtsi b/arch/arm/boot/dts/mediatek/mt7623.dtsi index c6b7d1713096..94e1ca43fee9 100644 --- a/arch/arm/boot/dts/mediatek/mt7623.dtsi +++ b/arch/arm/boot/dts/mediatek/mt7623.dtsi @@ -160,13 +160,13 @@ cpu_thermal: cpu-thermal { trips { cpu_passive: cpu-passive { - temperature = <57000>; + temperature = <77000>; hysteresis = <2000>; type = "passive"; }; cpu_active: cpu-active { - temperature = <67000>; + temperature = <82000>; hysteresis = <2000>; type = "active"; }; -- 2.51.0 From 003346fae7e183886b6a3f9e991816b9758ab316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:54 +0100 Subject: [PATCH 460/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/194-dts-mt7968a-add-ramoops.patch --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index f9aaf3f20cd7..39c4cee4b270 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -68,6 +68,14 @@ reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; + + /* 64 KiB reserved for ramoops/pstore */ + ramoops@42ff0000 { + compatible = "ramoops"; + reg = <0 0x42ff0000 0 0x10000>; + record-size = <0x1000>; + }; + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ secmon_reserved: secmon@43000000 { reg = <0 0x43000000 0 0x30000>; -- 2.51.0 From 7a4997adcfa4baacbc3101f5a46b9afcc9ce3fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:54 +0100 Subject: [PATCH 461/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/195-dts-mt7986a-bpi-r3-leds-port-names-and-wifi-eeprom.patch --- .../mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 1 + .../dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 146 +++++++++++++++++- 2 files changed, 140 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso index 6a0d529b54ac..7cbdd574aa9a 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso @@ -55,6 +55,7 @@ partition@180000 { partition@c00000 { label = "fit"; reg = <0xc00000 0x1400000>; + compatible = "denx,fit"; }; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts index ed79ad1ae871..5e0c2941928d 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts @@ -23,6 +23,10 @@ aliases { serial0 = &uart0; ethernet0 = &gmac0; ethernet1 = &gmac1; + led-boot = &green_led; + led-failsafe = &green_led; + led-running = &green_led; + led-upgrade = &blue_led; }; chosen { @@ -418,27 +422,27 @@ port@0 { port@1 { reg = <1>; - label = "lan0"; + label = "lan1"; }; port@2 { reg = <2>; - label = "lan1"; + label = "lan2"; }; port@3 { reg = <3>; - label = "lan2"; + label = "lan3"; }; port@4 { reg = <4>; - label = "lan3"; + label = "lan4"; }; port5: port@5 { reg = <5>; - label = "lan4"; + label = "sfp2"; phy-mode = "2500base-x"; sfp = <&sfp2>; managed = "in-band-status"; @@ -489,9 +493,137 @@ &watchdog { &wifi { status = "okay"; - pinctrl-names = "default", "dbdc"; + pinctrl-names = "default"; pinctrl-0 = <&wf_2g_5g_pins>, <&wf_led_pins>; - pinctrl-1 = <&wf_dbdc_pins>, <&wf_led_pins>; + + mediatek,eeprom-data = <0x86790900 0x000c4326 0x60000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x01000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000800 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x24649090 0x00280000 0x05100000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00021e00 0x021e0002 0x1e00021e 0x00022800 0x02280002 0x28000228 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00008080 0x8080fdf7 + 0x0903150d 0x80808080 0x80808080 0x05050d0d 0x1313c6c6 0xc3c3c200 0x00c200c2 0x00008182 + 0x8585c2c2 0x82828282 0x858500c2 0xc2000081 0x82858587 0x87c2c200 0x81818285 0x858787c2 + 0xc2000081 0x82858587 0x87c2c200 0x00818285 0x858787c2 0xc2000081 0x82858587 0x87c4c4c2 + 0xc100c300 0xc3c3c100 0x818383c3 0xc3c3c100 0x81838300 0xc2c2c2c0 0x81828484 0x000000c3 + 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x838686c2 0xc2c2c081 0x82848486 0x86c3c3c3 + 0xc1008183 0x838686c3 0xc3c3c100 0x81838386 0x86c3c3c3 0xc1008183 0x83868622 0x28002228 + 0x00222800 0x22280000 0xdddddddd 0xdddddddd 0xddbbbbbb 0xccccccdd 0xdddddddd 0xdddddddd + 0xeeeeeecc 0xccccdddd 0xdddddddd 0x004a5662 0x0000004a 0x56620000 0x004a5662 0x0000004a + 0x56620000 0x88888888 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600 + 0x33333326 0x26262626 0x26262600 0x33333326 0x26262626 0x26262600 0x00000000 0xf0f0cc00 + 0x00000000 0x0000aaaa 0xaabbbbbb 0xcccccccc 0xccccbbbb 0xbbbbbbbb 0xbbbbbbaa 0xaaaabbbb + 0xbbaaaaaa 0x999999aa 0xaaaabbbb 0xbbcccccc 0x00000000 0x0000aaaa 0xaa000000 0xbbbbbbbb + 0xbbbbaaaa 0xaa999999 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb + 0x00000000 0x00000000 0x00000000 0x99999999 0x9999aaaa 0xaaaaaaaa 0x999999aa 0xaaaaaaaa + 0xaaaaaaaa 0xaaaaaaaa 0xaaaabbbb 0xbbbbbbbb 0x00000000 0x0000eeee 0xeeffffff 0xcccccccc + 0xccccdddd 0xddbbbbbb 0xccccccbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbbbbb 0xbbbbcccc 0xccdddddd + 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 + 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 + 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e + 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 + 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 + 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e 0x00516200 0x686e0051 0x6200686e + 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 0x88888888 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x06000100 0x01050002 0x00ff0300 + 0xf900fe03 0x00000000 0x00000000 0x0000009b 0x6e370000 0x00000000 0x00fc0009 0x0a00fe00 + 0x060700fe 0x00070800 0x05000b0a 0x00000000 0x00000000 0x000000e2 0x96460000 0x00000000 + 0x000400f7 0xf8000300 0xfcfe0003 0x00fbfc00 0xee00e3f2 0x00000000 0x00000000 0x00000011 + 0xbb550000 0x00000000 0x000600f6 0xfc000300 0xfbfe0004 0x00fafe00 0xf600ecf2 0x00000000 + 0x00000000 0x0000001f 0xbf580000 0x00000000 0x000600f5 0xf6000400 0xf8f90004 0x00f7f800 + 0xf700f0f4 0x00000000 0x00000000 0x00000024 0xbe570000 0x00000000 0x000800f8 0xfe000600 + 0xf8fd0007 0x00f9fe00 0xf500f0f4 0x00000000 0x00000000 0x0000002d 0xd6610000 0x00000000 + 0x000400f7 0xfc000500 0xf7fc0005 0x00f7fc00 0xf900f5f8 0x00000000 0x00000000 0x00000026 + 0xd96e0000 0x00000000 0x000400f7 0xf9000600 0xf5f70005 0x00f5f800 0xf900f4f7 0x00000000 + 0x00000000 0x0000001b 0xce690000 0x00000000 0x000300f8 0xf8000600 0xf6f60004 0x00f6f700 + 0xf900f4f7 0x00000000 0x00000000 0x00000018 0xd8720000 0x00000000 0x00000000 0x02404002 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0xc1c2c1c2 0x41c341c3 0x3fc13fc1 0x40c13fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c13fc2 + 0x3fc140c0 0x41c040c0 0x3fc33fc3 0x40c23fc2 0x3fc240c1 0x41c040c0 0x3fc23fc2 0x40c23fc2 + 0x3fc140c1 0x41c040c0 0x00000000 0x00000000 0x41c741c7 0xc1c7c1c7 0x00000000 0x00000000 + 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 + 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 0x3fc03fc0 + 0x00a0ce00 0x00000000 0xb6840000 0x00000000 0x00000000 0x00000000 0x18181818 0x18181818 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x004b5763 0x0000004b 0x57630000 0x004b5763 0x0000004b 0x57630000 0x88888888 0x08474759 + 0x69780849 0x49596d7a 0x0849495a 0x6d790848 0x48596c78 0x08484858 0x6a780848 0x48586a78 + 0x08484858 0x6c78084a 0x4a5b6d79 0x08474759 0x697a0848 0x48596b79 0x08484859 0x6c7a0848 + 0x48586c79 0x08484857 0x68770848 0x48576877 0x08484857 0x6a77084a 0x4a5a6a77 0x08464659 + 0x69790848 0x48586b79 0x08484858 0x6c7a0848 0x48596c79 0x08484857 0x68770848 0x48576877 + 0x08494958 0x6d7a084b 0x4b5c6c77 0x0847475a 0x6a7b0849 0x495a6e7c 0x0849495a 0x6e7c0849 + 0x495b6e7c 0x08494959 0x6a7a0849 0x49596a7a 0x084a4a5a 0x6f7d084b 0x4b5c6e7b 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x85848484 + 0xc3c4c4c5 0xc4c3c33f 0xc3c3c2c2 0xc2c2c03f 0xc3c3c3c4 0xc4c4c33f 0xc2c2c2c2 0xc1c3c1c1 + 0xc0c08282 0x83848686 0x88880000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00001111 0x00000000 + 0x8080f703 0x10808080 0x80050d13 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x000000a4 0xce000000 0x0000b684 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000>; led { led-active-low; -- 2.51.0 From 9301b8648c259afbd936ca0d82993486c7f8621c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:55 +0100 Subject: [PATCH 462/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/196-dts-mt7986a-bpi-r3-use-all-ubi-nand-layout.patch --- .../mt7986a-bananapi-bpi-r3-emmc.dtso | 19 ++++++++++++ .../mt7986a-bananapi-bpi-r3-nand.dtso | 29 +++++++++---------- .../mediatek/mt7986a-bananapi-bpi-r3-nor.dtso | 6 +++- .../mediatek/mt7986a-bananapi-bpi-r3-sd.dtso | 19 ++++++++++++ 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso index 047a8388811e..888f1e20374b 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-emmc.dtso @@ -21,5 +21,24 @@ / { non-removable; no-sd; no-sdio; + #address-cells = <1>; + #size-cells = <0>; status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + emmc_rootdisk: block-partition-production { + partname = "production"; + }; + }; + }; +}; + +&{/chosen} { + rootdisk-emmc = <&emmc_rootdisk>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso index 24398f8a7da4..2b998cc9b054 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nand.dtso @@ -29,25 +29,24 @@ partitions { partition@0 { label = "bl2"; - reg = <0x0 0x100000>; - read-only; + reg = <0x0 0x200000>; }; - partition@100000 { - label = "reserved"; - reg = <0x100000 0x280000>; - }; - - partition@380000 { - label = "fip"; - reg = <0x380000 0x200000>; - read-only; - }; - - partition@580000 { + partition@200000 { label = "ubi"; - reg = <0x580000 0x7a80000>; + reg = <0x200000 0x7e00000>; + compatible = "linux,ubi"; + + volumes { + nand_rootdisk: ubi-volume-fit { + volname = "fit"; + }; + }; }; }; }; }; + +&{/chosen} { + rootdisk-spim-nand = <&nand_rootdisk>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso index 7cbdd574aa9a..384ceab38e3f 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-nor.dtso @@ -52,7 +52,7 @@ partition@180000 { reg = <0x180000 0xa80000>; }; - partition@c00000 { + nor_rootdisk: partition@c00000 { label = "fit"; reg = <0xc00000 0x1400000>; compatible = "denx,fit"; @@ -60,3 +60,7 @@ partition@c00000 { }; }; }; + +&{/chosen} { + rootdisk-nor = <&nor_rootdisk>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso index d9e01967acc4..98be406ecae1 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-sd.dtso @@ -15,5 +15,24 @@ / { bus-width = <4>; max-frequency = <52000000>; cap-sd-highspeed; + #address-cells = <1>; + #size-cells = <0>; status = "okay"; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + partitions { + compatible = "gpt-partitions"; + + sd_rootdisk: block-partition-production { + partname = "production"; + }; + }; + }; +}; + +&{/chosen} { + rootdisk-sd = <&sd_rootdisk>; }; -- 2.51.0 From a3d2dc6ef2ff5f5cb44223775f18f400b3d25f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:55 +0100 Subject: [PATCH 463/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/198-dts-mt7988a-enable-wed.patch --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 137 ++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index b2338231fab4..5717729f563c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -145,6 +145,32 @@ secmon@43000000 { reg = <0 0x43000000 0 0x50000>; no-map; }; + + wmcpu_emi: wmcpu-reserved@47cc0000 { + reg = <0 0x47cc0000 0 0x00100000>; + no-map; + }; + + wo_emi0: wo-emi@4f600000 { + reg = <0 0x4f600000 0 0x40000>; + no-map; + }; + + wo_emi1: wo-emi@4f640000 { + reg = <0 0x4f640000 0 0x40000>; + no-map; + }; + + wo_emi2: wo-emi@4f680000 { + reg = <0 0x4f680000 0 0x40000>; + no-map; + }; + + wo_data: wo-data@4f700000 { + reg = <0 0x4f700000 0 0x800000>; + no-map; + shared = <1>; + }; }; soc { @@ -867,6 +893,50 @@ ethsys: clock-controller@15000000 { reg = <0 0x15000000 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + }; + + wed0: wed@15010000 { + compatible = "mediatek,mt7988-wed", + "syscon"; + reg = <0 0x15010000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi0>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif0>; + mediatek,wo-ilm = <&wo_ilm0>; + mediatek,wo-dlm = <&wo_dlm0>; + mediatek,wo-cpuboot = <&wo_cpuboot0>; + }; + + wed1: wed@15012000 { + compatible = "mediatek,mt7988-wed", + "syscon"; + reg = <0 0x15012000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi1>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif1>; + mediatek,wo-ilm = <&wo_ilm1>; + mediatek,wo-dlm = <&wo_dlm1>; + mediatek,wo-cpuboot = <&wo_cpuboot1>; + }; + + wed2: wed@15014000 { + compatible = "mediatek,mt7988-wed", + "syscon"; + reg = <0 0x15014000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = ; + memory-region = <&wo_emi2>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; + mediatek,wo-ccif = <&wo_ccif2>; + mediatek,wo-ilm = <&wo_ilm2>; + mediatek,wo-dlm = <&wo_dlm2>; + mediatek,wo-cpuboot = <&wo_cpuboot2>; }; switch: switch@15020000 { @@ -1086,6 +1156,7 @@ eth: ethernet@15100000 { <&apmixedsys CLK_APMIXED_SGMPLL>; mediatek,ethsys = <ðsys>; mediatek,infracfg = <&topmisc>; + mediatek,wed = <&wed0>, <&wed1>, <&wed2>; #address-cells = <1>; #size-cells = <0>; @@ -1147,6 +1218,72 @@ i2p5gbe_led1: i2p5gbe-led1@1 { }; }; + wo_ccif0: syscon@151a5000 { + compatible = "mediatek,mt7988-wo-ccif", "syscon"; + reg = <0 0x151a5000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + wo_ccif1: syscon@152a5000 { + compatible = "mediatek,mt7988-wo-ccif", "syscon"; + reg = <0 0x152a5000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + wo_ccif2: syscon@153a5000 { + compatible = "mediatek,mt7988-wo-ccif", "syscon"; + reg = <0 0x153a5000 0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + }; + + wo_ilm0: syscon@151e0000 { + compatible = "mediatek,mt7988-wo-ilm", "syscon"; + reg = <0 0x151e0000 0 0x8000>; + }; + + wo_ilm1: syscon@152e0000 { + compatible = "mediatek,mt7988-wo-ilm", "syscon"; + reg = <0 0x152e0000 0 0x8000>; + }; + + wo_ilm2: syscon@153e0000 { + compatible = "mediatek,mt7988-wo-ilm", "syscon"; + reg = <0 0x153e0000 0 0x8000>; + }; + + wo_dlm0: syscon@151e8000 { + compatible = "mediatek,mt7988-wo-dlm", "syscon"; + reg = <0 0x151e8000 0 0x2000>; + }; + + wo_dlm1: syscon@152e8000 { + compatible = "mediatek,mt7988-wo-dlm", "syscon"; + reg = <0 0x152e8000 0 0x2000>; + }; + + wo_dlm2: syscon@153e8000 { + compatible = "mediatek,mt7988-wo-dlm", "syscon"; + reg = <0 0x153e8000 0 0x2000>; + }; + + wo_cpuboot0: syscon@15194000 { + compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; + reg = <0 0x15194000 0 0x1000>; + }; + + wo_cpuboot1: syscon@15294000 { + compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; + reg = <0 0x15294000 0 0x1000>; + }; + + wo_cpuboot2: syscon@15394000 { + compatible = "mediatek,mt7988-wo-cpuboot", "syscon"; + reg = <0 0x15394000 0 0x1000>; + }; + crypto: crypto@15600000 { compatible = "inside-secure,safexcel-eip197b"; reg = <0 0x15600000 0 0x180000>; -- 2.51.0 From a578fcc5a7b10a8a40c829a21a9d9db28b7c8cd7 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sun, 10 Aug 2025 18:11:01 +0800 Subject: [PATCH 464/517] arm64: dts: mediatek: mt7986: increase ATF reserved memory to 256 kiB The latest Mediatek open-source Trusted Firmware-A project has reserved 256 KiB for BL2 and BL31. It is better to increase the reserved memory region in the Linux kernel to protect the data. Signed-off-by: Shiji Yang --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 39c4cee4b270..9a8d7db31261 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -76,9 +76,9 @@ ramoops@42ff0000 { record-size = <0x1000>; }; - /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + /* 256 KiB reserved for ARM Trusted Firmware (BL31 + BL32) */ secmon_reserved: secmon@43000000 { - reg = <0 0x43000000 0 0x30000>; + reg = <0 0x43000000 0 0x40000>; no-map; }; -- 2.51.0 From 58d452682aae8137393174cc17db1b3277413904 Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Mon, 30 Apr 2018 14:38:01 +0200 Subject: [PATCH 465/517] phy: phy-mtk-tphy: Add hifsys-support --- drivers/phy/mediatek/phy-mtk-tphy.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 3f7095ec5978..4662518a38ed 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "phy-mtk-io.h" @@ -271,6 +273,9 @@ #define USER_BUF_LEN(count) min_t(size_t, 8, (count)) +#define HIF_SYSCFG1 0x14 +#define HIF_SYSCFG1_PHY2_MASK (0x3 << 20) + enum mtk_phy_version { MTK_PHY_V1 = 1, MTK_PHY_V2, @@ -339,6 +344,7 @@ struct mtk_tphy { void __iomem *sif_base; /* only shared sif */ const struct mtk_phy_pdata *pdata; struct mtk_phy_instance **phys; + struct regmap *hif; int nphys; int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */ int src_coef; /* coefficient for slew rate calibrate */ @@ -973,6 +979,10 @@ static void pcie_phy_instance_init(struct mtk_tphy *tphy, if (tphy->pdata->version != MTK_PHY_V1) return; + if (tphy->hif) + regmap_update_bits(tphy->hif, HIF_SYSCFG1, + HIF_SYSCFG1_PHY2_MASK, 0); + mtk_phy_update_bits(phya + U3P_U3_PHYA_DA_REG0, P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, FIELD_PREP(P3A_RG_XTAL_EXT_PE1H, 0x2) | @@ -1621,6 +1631,16 @@ static int mtk_tphy_probe(struct platform_device *pdev) &tphy->src_coef); } + if (of_find_property(np, "mediatek,phy-switch", NULL)) { + tphy->hif = syscon_regmap_lookup_by_phandle(np, + "mediatek,phy-switch"); + if (IS_ERR(tphy->hif)) { + dev_err(&pdev->dev, + "missing \"mediatek,phy-switch\" phandle\n"); + return PTR_ERR(tphy->hif); + } + } + port = 0; for_each_child_of_node_scoped(np, child_np) { struct mtk_phy_instance *instance; -- 2.51.0 From e45d21bc40ab81b4a082310763c9f0ef19f980ec Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 1 Nov 2024 03:19:39 +0000 Subject: [PATCH 466/517] clk: mediatek: mt7988-infracfg: SPI0 clocks are not critical SPI0 clocks have wrongly been marked as critical while, probably due to the SPI driver not requesting them. This can (and should) be addressed in device tree instead. Remove CLK_IS_CRITICAL flag from clocks related to SPI0. Fixes: 4b4719437d85 ("clk: mediatek: add drivers for MT7988 SoC") Signed-off-by: Daniel Golle --- drivers/clk/mediatek/clk-mt7988-infracfg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c index ef8267319d91..c40e18c27f12 100644 --- a/drivers/clk/mediatek/clk-mt7988-infracfg.c +++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c @@ -196,12 +196,10 @@ static const struct mtk_gate infra_clks[] = { GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10), GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", "sysaxi_sel", 11, CLK_IS_CRITICAL), - GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12, - CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12), GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", "infra_mux_spi1_sel", 13), GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", "infra_mux_spi2_sel", 14), - GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15, - CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15), GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", "sysaxi_sel", 16), GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", "sysaxi_sel", 17), GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", "sysaxi_sel", 18), -- 2.51.0 From 2635aa94e576bbcaf5fdfe2a2ac47d35203f0ff1 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 25 Jan 2023 00:27:49 +0000 Subject: [PATCH 467/517] hwrng: add driver for MediaTek TRNG SMC Add driver providing kernel-side support for the Random Number Generator hardware found on Mediatek SoCs which have a driver in ARM TrustedFirmware-A allowing Linux to read random numbers using a non-standard vendor-defined Secure Monitor Call. Signed-off-by: Daniel Golle --- drivers/char/hw_random/Kconfig | 17 +++++++ drivers/char/hw_random/Makefile | 1 + drivers/char/hw_random/mtk-rng-v2.c | 76 +++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 drivers/char/hw_random/mtk-rng-v2.c diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index f0dde77f50b4..fc19371e6217 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -452,6 +452,23 @@ config HW_RANDOM_MTK If unsure, say Y. +config HW_RANDOM_MTK_V2 + tristate "Mediatek Random Number Generator support (v2/SMC)" + depends on HAVE_ARM_SMCCC + depends on HW_RANDOM + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + default y + help + This driver provides kernel-side support for the Random Number + Generator hardware found on Mediatek SoCs which have a driver + in ARM TrustedFirmware-A allowing Linux to read using a non- + standard vendor-defined Secure Monitor Call. + + To compile this driver as a module, choose M here. the + module will be called mtk-rng-v2. + + If unsure, say Y. + config HW_RANDOM_S390 tristate "S390 True Random Number Generator support" depends on S390 diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 01f012eab440..3403f6b9282a 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o +obj-$(CONFIG_HW_RANDOM_MTK_V2) += mtk-rng-v2.o obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o diff --git a/drivers/char/hw_random/mtk-rng-v2.c b/drivers/char/hw_random/mtk-rng-v2.c new file mode 100644 index 000000000000..8c506a7897d0 --- /dev/null +++ b/drivers/char/hw_random/mtk-rng-v2.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Mediatek Hardware Random Number Generator (v2/SMCC) + * + * Copyright (C) 2023 Daniel Golle + * based on patch from Mingming Su + */ +#define MTK_RNG_DEV KBUILD_MODNAME + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MTK_SIP_KERNEL_GET_RND MTK_SIP_SMC_CMD(0x550) + +static int mtk_rng_v2_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct arm_smccc_res res; + int retval = 0; + + while (max >= sizeof(u32)) { + arm_smccc_smc(MTK_SIP_KERNEL_GET_RND, 0, 0, 0, 0, 0, 0, 0, + &res); + if (res.a0) + break; + + *(u32 *)buf = res.a1; + retval += sizeof(u32); + buf += sizeof(u32); + max -= sizeof(u32); + } + + return retval || !wait ? retval : -EIO; +} + +static int mtk_rng_v2_probe(struct platform_device *pdev) +{ + struct hwrng *trng; + + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + return -ENOMEM; + + trng->name = pdev->name; + trng->read = mtk_rng_v2_read; + trng->quality = 900; + + return devm_hwrng_register(&pdev->dev, trng); +} + +static const struct of_device_id mtk_rng_v2_match[] = { + { .compatible = "mediatek,mt7981-rng" }, + { .compatible = "mediatek,mt7987-rng" }, + { .compatible = "mediatek,mt7988-rng" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_rng_v2_match); + +static struct platform_driver mtk_rng_v2_driver = { + .probe = mtk_rng_v2_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = mtk_rng_v2_match, + }, +}; +module_platform_driver(mtk_rng_v2_driver); + +MODULE_DESCRIPTION("Mediatek Random Number Generator Driver (v2/SMC)"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_LICENSE("GPL"); -- 2.51.0 From 7ab0a6fa1cbc0955011ee9d40ee6dd4ab9e3eade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:56 +0100 Subject: [PATCH 468/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/330-snand-mtk-bmt-support.patch --- drivers/mtd/nand/spi/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 8a3c9db90c6f..685a92a50fe6 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -19,6 +19,7 @@ #include #include #include +#include static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { @@ -1574,6 +1575,7 @@ static int spinand_probe(struct spi_mem *mem) if (ret) return ret; + mtk_bmt_attach(mtd); ret = mtd_device_register(mtd, NULL, 0); if (ret) goto err_spinand_cleanup; @@ -1581,6 +1583,7 @@ static int spinand_probe(struct spi_mem *mem) return 0; err_spinand_cleanup: + mtk_bmt_detach(mtd); spinand_cleanup(spinand); return ret; @@ -1599,6 +1602,7 @@ static int spinand_remove(struct spi_mem *mem) if (ret) return ret; + mtk_bmt_detach(mtd); spinand_cleanup(spinand); return 0; -- 2.51.0 From 14a79939d2d384b4a9bf0ff262a01071e4e1b559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:57 +0100 Subject: [PATCH 469/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/331-mt7622-rfb1-enable-bmt.patch --- arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts index a478bab2e8cf..d6c52654e5ed 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts @@ -572,6 +572,7 @@ flash@0 { spi-tx-bus-width = <4>; spi-rx-bus-width = <4>; nand-ecc-engine = <&snfi>; + mediatek,bmt-v2; partitions { compatible = "fixed-partitions"; -- 2.51.0 From aa4935c265e21729b534f8fd79fe2411dec468a4 Mon Sep 17 00:00:00 2001 From: Davide Fioravanti Date: Fri, 8 Jan 2021 15:35:24 +0100 Subject: [PATCH 470/517] mtd: spinand: Add support for the Fidelix FM35X1GA Datasheet: http://www.hobos.com.cn/upload/datasheet/DS35X1GAXXX_100_rev00.pdf Signed-off-by: Davide Fioravanti --- drivers/mtd/nand/spi/Makefile | 2 +- drivers/mtd/nand/spi/core.c | 1 + drivers/mtd/nand/spi/fidelix.c | 76 ++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 1 + 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/spi/fidelix.c diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index f725f0c67307..27dc57924f19 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o +spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fidelix.o fmsh.o foresee.o gigadevice.o spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 685a92a50fe6..d0071aba4f77 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1162,6 +1162,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &esmt_c8_spinand_manufacturer, &etron_spinand_manufacturer, &fmsh_spinand_manufacturer, + &fidelix_spinand_manufacturer, &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/fidelix.c b/drivers/mtd/nand/spi/fidelix.c new file mode 100644 index 000000000000..039bf331813c --- /dev/null +++ b/drivers/mtd/nand/spi/fidelix.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Davide Fioravanti + */ + +#include +#include +#include + +#define SPINAND_MFR_FIDELIX 0xE5 +#define FIDELIX_ECCSR_MASK 0x0F + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static int fm35x1ga_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 8; + region->length = 8; + + return 0; +} + +static int fm35x1ga_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 2; + region->length = 6; + + return 0; +} + +static const struct mtd_ooblayout_ops fm35x1ga_ooblayout = { + .ecc = fm35x1ga_ooblayout_ecc, + .free = fm35x1ga_ooblayout_free, +}; + +static const struct spinand_info fidelix_spinand_table[] = { + SPINAND_INFO("FM35X1GA", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm35x1ga_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops fidelix_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer fidelix_spinand_manufacturer = { + .id = SPINAND_MFR_FIDELIX, + .name = "Fidelix", + .chips = fidelix_spinand_table, + .nchips = ARRAY_SIZE(fidelix_spinand_table), + .ops = &fidelix_spinand_manuf_ops, +}; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index e5b6ac340383..11f7a6a1a31f 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -265,6 +265,7 @@ extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; extern const struct spinand_manufacturer etron_spinand_manufacturer; extern const struct spinand_manufacturer fmsh_spinand_manufacturer; +extern const struct spinand_manufacturer fidelix_spinand_manufacturer; extern const struct spinand_manufacturer foresee_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; -- 2.51.0 From 3444bd6e424a34dfa604bd275471bbc90db46127 Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 19 Apr 2024 17:59:07 +0100 Subject: [PATCH 471/517] cpufreq: mediatek: Add support for MT7988A This add cpufreq support for mediatek MT7988A SoC. The platform data of MT7988A is different from previous MediaTek SoCs, so we add a new compatible and platform data for it. Signed-off-by: Sam Shih --- drivers/cpufreq/mediatek-cpufreq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c index 663f61565cf7..fa6633d44ac9 100644 --- a/drivers/cpufreq/mediatek-cpufreq.c +++ b/drivers/cpufreq/mediatek-cpufreq.c @@ -744,6 +744,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst __maybe_unus { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data }, { .compatible = "mediatek,mt7623", .data = &mt7623_platform_data }, { .compatible = "mediatek,mt7988a", .data = &mt7988_platform_data }, + { .compatible = "mediatek,mt7988d", .data = &mt7988_platform_data }, { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data }, { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, -- 2.51.0 From ee055daffe2d0aa9cdc5229ef49bd46c8cfb4078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:58 +0100 Subject: [PATCH 472/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/400-crypto-add-eip97-inside-secure-support.patch --- drivers/crypto/inside-secure/safexcel.c | 8 ++++++++ drivers/crypto/inside-secure/safexcel.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index f5c1912aa564..c0a1fa1f7169 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -608,6 +608,14 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv) val |= EIP197_MST_CTRL_TX_MAX_CMD(5); writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); } + /* + * Set maximum number of TX commands to 2^4 = 16 for EIP97 HW2.1/HW2.3 + */ + else { + val = 0; + val |= EIP97_MST_CTRL_TX_MAX_CMD(4); + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + } /* Configure wr/rd cache values */ writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 0c79ad78d1c0..2ad691a84180 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -315,6 +315,7 @@ #define EIP197_MST_CTRL_RD_CACHE(n) (((n) & 0xf) << 0) #define EIP197_MST_CTRL_WD_CACHE(n) (((n) & 0xf) << 4) #define EIP197_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 20) +#define EIP97_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 4) #define EIP197_MST_CTRL_BYTE_SWAP BIT(24) #define EIP197_MST_CTRL_NO_BYTE_SWAP BIT(25) #define EIP197_MST_CTRL_BYTE_SWAP_BITS GENMASK(25, 24) -- 2.51.0 From 6048c6fc7613b02d5f9b4ea8e3c18b08e33164f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:58 +0100 Subject: [PATCH 473/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/401-crypto-fix-eip97-cache-incoherent.patch --- drivers/crypto/inside-secure/safexcel.h | 3 +++ drivers/crypto/inside-secure/safexcel_hash.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 2ad691a84180..c2c1773104e3 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -743,6 +743,9 @@ struct safexcel_priv_data { /* Priority we use for advertising our algorithms */ #define SAFEXCEL_CRA_PRIORITY 300 +/* System cache line size */ +#define SYSTEM_CACHELINE_SIZE 64 + /* SM3 digest result for zero length message */ #define EIP197_SM3_ZEROM_HASH "\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \ "\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \ diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index af4b978189e5..eb640382e17b 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -55,9 +55,9 @@ struct safexcel_ahash_req { u8 block_sz; /* block size, only set once */ u8 digest_sz; /* output digest size, only set once */ __le32 state[SHA3_512_BLOCK_SIZE / - sizeof(__le32)] __aligned(sizeof(__le32)); + sizeof(__le32)] __aligned(SYSTEM_CACHELINE_SIZE); - u64 len; + u64 len __aligned(SYSTEM_CACHELINE_SIZE); u64 processed; u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32)); -- 2.51.0 From a97801fc420b739ae5139abf71e1016a1f09e646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:59 +0100 Subject: [PATCH 474/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/410-bt-mtk-serial-fix.patch --- drivers/tty/serial/8250/8250.h | 1 + drivers/tty/serial/8250/8250_port.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 10a706fe4b24..927a286d185a 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -86,6 +86,7 @@ struct serial8250_config { * STOP PARITY EPAR SPAR WLEN5 WLEN6 */ #define UART_CAP_NOTEMT BIT(18) /* UART without interrupt on TEMT available */ +#define UART_CAP_NMOD BIT(19) /* UART doesn't do termios */ #define UART_BUG_QUOT BIT(0) /* UART has buggy quot LSB */ #define UART_BUG_TXEN BIT(1) /* UART has buggy TX IIR status */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 03aca7eaca16..6005f78838e8 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -276,7 +276,7 @@ static const struct serial8250_config uart_config[] = { .tx_loadsz = 16, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - .flags = UART_CAP_FIFO, + .flags = UART_CAP_FIFO | UART_CAP_NMOD, }, [PORT_NPCM] = { .name = "Nuvoton 16550", @@ -2729,6 +2729,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int baud, quot, frac = 0; + if (up->capabilities & UART_CAP_NMOD) { + termios->c_cflag = 0; + return; + } + if (up->capabilities & UART_CAP_MINI) { termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); if ((termios->c_cflag & CSIZE) == CS5 || -- 2.51.0 From 4711a23773c1c01b04b8c28af3dd375e28e0c5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:50:59 +0100 Subject: [PATCH 475/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/411-mtd-spinand-fix-support-for-FORESEE.patch --- drivers/mtd/nand/spi/foresee.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c index 8a01582c0f53..f762d514a362 100644 --- a/drivers/mtd/nand/spi/foresee.c +++ b/drivers/mtd/nand/spi/foresee.c @@ -22,8 +22,8 @@ static SPINAND_OP_VARIANTS(write_cache_variants, SPINAND_PROG_LOAD(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) -- 2.51.0 From a40812a662070cc3134ec9bd21e5ca0bb42bd872 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:29:51 +0800 Subject: [PATCH 476/517] drivers: spi-mt65xx: Move chip_config to driver's private data Signed-off-by: SkyLake.Huang --- drivers/spi/spi-mt65xx.c | 29 +++++++++--------------- include/linux/platform_data/spi-mt65xx.h | 17 -------------- 2 files changed, 11 insertions(+), 35 deletions(-) delete mode 100644 include/linux/platform_data/spi-mt65xx.h diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index dfee244fc317..6830325cab71 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -172,6 +171,8 @@ struct mtk_spi { struct device *dev; dma_addr_t tx_dma; dma_addr_t rx_dma; + u32 sample_sel; + u32 get_tick_dly; }; static const struct mtk_spi_compatible mtk_common_compat; @@ -217,15 +218,6 @@ static const struct mtk_spi_compatible mt6893_compat = { .no_need_unprepare = true, }; -/* - * A piece of default chip info unless the platform - * supplies it. - */ -static const struct mtk_chip_config mtk_default_chip_info = { - .sample_sel = 0, - .tick_delay = 0, -}; - static const struct of_device_id mtk_spi_of_match[] = { { .compatible = "mediatek,spi-ipm", .data = (void *)&mtk_ipm_compat, @@ -353,7 +345,6 @@ static int mtk_spi_hw_init(struct spi_controller *host, { u16 cpha, cpol; u32 reg_val; - struct mtk_chip_config *chip_config = spi->controller_data; struct mtk_spi *mdata = spi_controller_get_devdata(host); cpha = spi->mode & SPI_CPHA ? 1 : 0; @@ -403,7 +394,7 @@ static int mtk_spi_hw_init(struct spi_controller *host, else reg_val &= ~SPI_CMD_CS_POL; - if (chip_config->sample_sel) + if (mdata->sample_sel) reg_val |= SPI_CMD_SAMPLE_SEL; else reg_val &= ~SPI_CMD_SAMPLE_SEL; @@ -430,20 +421,20 @@ static int mtk_spi_hw_init(struct spi_controller *host, if (mdata->dev_comp->ipm_design) { reg_val = readl(mdata->base + SPI_CMD_REG); reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK; - reg_val |= ((chip_config->tick_delay & 0x7) + reg_val |= ((mdata->get_tick_dly & 0x7) << SPI_CMD_IPM_GET_TICKDLY_OFFSET); writel(reg_val, mdata->base + SPI_CMD_REG); } else { reg_val = readl(mdata->base + SPI_CFG1_REG); reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; - reg_val |= ((chip_config->tick_delay & 0x7) + reg_val |= ((mdata->get_tick_dly & 0x7) << SPI_CFG1_GET_TICK_DLY_OFFSET); writel(reg_val, mdata->base + SPI_CFG1_REG); } } else { reg_val = readl(mdata->base + SPI_CFG1_REG); reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1; - reg_val |= ((chip_config->tick_delay & 0x3) + reg_val |= ((mdata->get_tick_dly & 0x3) << SPI_CFG1_GET_TICK_DLY_OFFSET_V1); writel(reg_val, mdata->base + SPI_CFG1_REG); } @@ -733,9 +724,6 @@ static int mtk_spi_setup(struct spi_device *spi) { struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller); - if (!spi->controller_data) - spi->controller_data = (void *)&mtk_default_chip_info; - if (mdata->dev_comp->need_pad_sel && spi_get_csgpiod(spi, 0)) /* CS de-asserted, gpiolib will handle inversion */ gpiod_direction_output(spi_get_csgpiod(spi, 0), 0); @@ -1146,6 +1134,11 @@ static int mtk_spi_probe(struct platform_device *pdev) host->use_gpio_descriptors = true; mdata = spi_controller_get_devdata(host); + + /* Set device configs to default first. Calibrate it later. */ + mdata->sample_sel = 0; + mdata->get_tick_dly = 2; + mdata->dev_comp = device_get_match_data(dev); if (mdata->dev_comp->enhance_timing) diff --git a/include/linux/platform_data/spi-mt65xx.h b/include/linux/platform_data/spi-mt65xx.h deleted file mode 100644 index f0db674f07b8..000000000000 --- a/include/linux/platform_data/spi-mt65xx.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * MTK SPI bus driver definitions - * - * Copyright (c) 2015 MediaTek Inc. - * Author: Leilk Liu - */ - -#ifndef ____LINUX_PLATFORM_DATA_SPI_MTK_H -#define ____LINUX_PLATFORM_DATA_SPI_MTK_H - -/* Board specific platform_data */ -struct mtk_chip_config { - u32 sample_sel; - u32 tick_delay; -}; -#endif -- 2.51.0 From 5d3efaf4850193f1e68e7cba13464ff909cbbb10 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:35:52 +0800 Subject: [PATCH 477/517] drivers: spi: Add support for dynamic calibration Signed-off-by: SkyLake.Huang --- drivers/spi/spi.c | 137 ++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 42 ++++++++++++ 2 files changed, 179 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5ad9f4a2148f..8d5144801178 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1494,6 +1494,70 @@ static int spi_transfer_wait(struct spi_controller *ctlr, return 0; } +int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi, + int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv) +{ + int datalen = ctlr->cal_rule->datalen; + int addrlen = ctlr->cal_rule->addrlen; + u8 *buf; + int ret; + int i; + struct list_head *cal_head, *listptr; + struct spi_cal_target *target; + + /* Calculate calibration result */ + int hit_val, total_hit, origin; + bool hit; + + /* Make sure we can start calibration */ + if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata) + return 0; + + buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL); + if(!buf) + return -ENOMEM; + + ret = ctlr->append_caldata(ctlr); + if (ret) + goto cal_end; + + cal_head = ctlr->cal_target; + list_for_each(listptr, cal_head) { + target = list_entry(listptr, struct spi_cal_target, list); + + hit = false; + hit_val = 0; + total_hit = 0; + origin = *target->cal_item; + + for(i=target->cal_min; i<=target->cal_max; i+=target->step) { + *target->cal_item = i; + ret = (*cal_read)(drv_priv, ctlr->cal_rule->addr, addrlen, buf, datalen); + if(ret) + break; + dev_dbg(&spi->dev, "controller cal item value: 0x%x\n", i); + if(memcmp(ctlr->cal_rule->match_data, buf, datalen * sizeof(u8)) == 0) { + hit = true; + hit_val += i; + total_hit++; + dev_dbg(&spi->dev, "golden data matches data read!\n"); + } + } + if(hit) { + *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit); + dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item); + } else { + *target->cal_item = origin; + dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin); + } + } + +cal_end: + kfree(buf); + return ret? ret: 0; +} +EXPORT_SYMBOL_GPL(spi_do_calibration); + static void _spi_transfer_delay_ns(u32 ns) { if (!ns) @@ -2352,6 +2416,75 @@ void spi_flush_queue(struct spi_controller *ctlr) /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) +static inline void alloc_cal_data(struct list_head **cal_target, + struct spi_cal_rule **cal_rule, bool enable) +{ + if(enable) { + *cal_target = kmalloc(sizeof(struct list_head), GFP_KERNEL); + INIT_LIST_HEAD(*cal_target); + *cal_rule = kmalloc(sizeof(struct spi_cal_rule), GFP_KERNEL); + } else { + kfree(*cal_target); + kfree(*cal_rule); + } +} + +static int of_spi_parse_cal_dt(struct spi_controller *ctlr, struct spi_device *spi, + struct device_node *nc) +{ + u32 value; + int rc; + const char *cal_mode; + + rc = of_property_read_bool(nc, "spi-cal-enable"); + if (rc) + alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, true); + else + return 0; + + rc = of_property_read_string(nc, "spi-cal-mode", &cal_mode); + if(!rc) { + if(strcmp("read-data", cal_mode) == 0){ + ctlr->cal_rule->mode = SPI_CAL_READ_DATA; + } else if(strcmp("read-pp", cal_mode) == 0) { + ctlr->cal_rule->mode = SPI_CAL_READ_PP; + return 0; + } else if(strcmp("read-sfdp", cal_mode) == 0){ + ctlr->cal_rule->mode = SPI_CAL_READ_SFDP; + return 0; + } + } else + goto err; + + ctlr->cal_rule->datalen = 0; + rc = of_property_read_u32(nc, "spi-cal-datalen", &value); + if(!rc && value > 0) { + ctlr->cal_rule->datalen = value; + + ctlr->cal_rule->match_data = kzalloc(value * sizeof(u8), GFP_KERNEL); + rc = of_property_read_u8_array(nc, "spi-cal-data", + ctlr->cal_rule->match_data, value); + if(rc) + kfree(ctlr->cal_rule->match_data); + } + + rc = of_property_read_u32(nc, "spi-cal-addrlen", &value); + if(!rc && value > 0) { + ctlr->cal_rule->addrlen = value; + + ctlr->cal_rule->addr = kzalloc(value * sizeof(u32), GFP_KERNEL); + rc = of_property_read_u32_array(nc, "spi-cal-addr", + ctlr->cal_rule->addr, value); + if(rc) + kfree(ctlr->cal_rule->addr); + } + return 0; + +err: + alloc_cal_data(&ctlr->cal_target, &ctlr->cal_rule, false); + return 0; +} + static void of_spi_parse_dt_cs_delay(struct device_node *nc, struct spi_delay *delay, const char *prop) { @@ -2516,6 +2649,10 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc) if (rc) goto err_out; + rc = of_spi_parse_cal_dt(ctlr, spi, nc); + if (rc) + goto err_out; + /* Store a pointer to the node in the device structure */ of_node_get(nc); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 71ad766932d3..9ccc08819613 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -348,6 +348,40 @@ struct spi_driver { struct device_driver driver; }; +enum { + SPI_CAL_READ_DATA = 0, + SPI_CAL_READ_PP = 1, /* only for SPI-NAND */ + SPI_CAL_READ_SFDP = 2, /* only for SPI-NOR */ +}; + +struct nand_addr { + unsigned int lun; + unsigned int plane; + unsigned int eraseblock; + unsigned int page; + unsigned int dataoffs; +}; + +/** + * Read calibration rule from device dts node. + * Once calibration result matches the rule, we regard is as success. + */ +struct spi_cal_rule { + int datalen; + u8 *match_data; + int addrlen; + u32 *addr; + int mode; +}; + +struct spi_cal_target { + u32 *cal_item; + int cal_min; /* min of cal_item */ + int cal_max; /* max of cal_item */ + int step; /* Increase/decrease cal_item */ + struct list_head list; +}; + #define to_spi_driver(__drv) \ ( __drv ? container_of_const(__drv, struct spi_driver, driver) : NULL ) @@ -754,6 +788,11 @@ struct spi_controller { void *dummy_rx; void *dummy_tx; + /* For calibration */ + int (*append_caldata)(struct spi_controller *ctlr); + struct list_head *cal_target; + struct spi_cal_rule *cal_rule; + int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs); /* @@ -1657,6 +1696,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) { return 0; } #endif +extern int spi_do_calibration(struct spi_controller *ctlr, + struct spi_device *spi, int (*cal_read)(void *, u32 *, int, u8 *, int), void *drv_priv); + /* * If you're hotplugging an adapter with devices (parport, USB, etc) * use spi_new_device() to describe each device. You can also call -- 2.51.0 From 98ba0b15846cc6f0664d651a42a650cf5af8ce71 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:37:55 +0800 Subject: [PATCH 478/517] drivers: spi-mem: Add spi calibration hook Signed-off-by: SkyLake.Huang --- drivers/spi/spi-mem.c | 8 ++++++++ include/linux/spi/spi-mem.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 17b8baf749e6..597e6157d051 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -466,6 +466,14 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) } EXPORT_SYMBOL_GPL(spi_mem_exec_op); +int spi_mem_do_calibration(struct spi_mem *mem, + int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), + void *priv) +{ + return spi_do_calibration(mem->spi->controller, mem->spi, cal_read, priv); +} +EXPORT_SYMBOL_GPL(spi_mem_do_calibration); + /** * spi_mem_get_name() - Return the SPI mem device name to be used by the * upper layer if necessary diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index f866d5c8ed32..821ab7055640 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -372,6 +372,10 @@ bool spi_mem_supports_op(struct spi_mem *mem, int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op); +int spi_mem_do_calibration(struct spi_mem *mem, + int (*cal_read)(void *, u32 *, int, u8 *, int), + void *priv); + const char *spi_mem_get_name(struct spi_mem *mem); struct spi_mem_dirmap_desc * -- 2.51.0 From 4471f9130681170008741e9988d8a96767a3b5ba Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:39:03 +0800 Subject: [PATCH 479/517] drivers: spi-mt65xx: Add controller's calibration paramter Signed-off-by: SkyLake.Huang --- drivers/spi/spi-mt65xx.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 6830325cab71..906e188987c8 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -842,6 +842,21 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) return IRQ_WAKE_THREAD; } +static int mtk_spi_append_caldata(struct spi_controller *ctlr) +{ + struct spi_cal_target *cal_target = kmalloc(sizeof(*cal_target), GFP_KERNEL); + struct mtk_spi *mdata = spi_controller_get_devdata(ctlr); + + cal_target->cal_item = &mdata->get_tick_dly; + cal_target->cal_min = 0; + cal_target->cal_max = 7; + cal_target->step = 1; + + list_add(&cal_target->list, ctlr->cal_target); + + return 0; +} + static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { @@ -1132,6 +1147,7 @@ static int mtk_spi_probe(struct platform_device *pdev) host->setup = mtk_spi_setup; host->set_cs_timing = mtk_spi_set_hw_cs_timing; host->use_gpio_descriptors = true; + host->append_caldata = mtk_spi_append_caldata; mdata = spi_controller_get_devdata(host); -- 2.51.0 From 12093e201819865a1a75fad0932a37f7213f0195 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:39:56 +0800 Subject: [PATCH 480/517] drivers: mtd: spinand: Add calibration support for spinand Signed-off-by: SkyLake.Huang --- drivers/mtd/nand/spi/core.c | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index d0071aba4f77..ed8a2d2b2dd2 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1200,6 +1200,56 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, return -EOPNOTSUPP; } +static int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) { + struct spinand_device *spinand = (struct spinand_device *)priv; + struct device *dev = &spinand->spimem->spi->dev; + struct spi_mem_op op = SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, buf, readlen); + struct nand_pos pos; + struct nand_page_io_req req; + u8 status; + int ret; + + if(addrlen != sizeof(struct nand_addr)/sizeof(unsigned int)) { + dev_err(dev, "Must provide correct addr(length) for spinand calibration\n"); + return -EINVAL; + } + + ret = spinand_reset_op(spinand); + if (ret) + return ret; + + /* We should store our golden data in first target because + * we can't switch target at this moment. + */ + pos = (struct nand_pos){ + .target = 0, + .lun = *addr, + .plane = *(addr+1), + .eraseblock = *(addr+2), + .page = *(addr+3), + }; + + req = (struct nand_page_io_req){ + .pos = pos, + .dataoffs = *(addr+4), + .datalen = readlen, + .databuf.in = buf, + .mode = MTD_OPS_AUTO_OOB, + }; + + ret = spinand_load_page_op(spinand, &req); + if (ret) + return ret; + + ret = spinand_wait(spinand, &status); + if (ret < 0) + return ret; + + ret = spi_mem_exec_op(spinand->spimem, &op); + + return 0; +} + static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; @@ -1451,6 +1501,10 @@ static int spinand_init(struct spinand_device *spinand) if (!spinand->scratchbuf) return -ENOMEM; + ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand); + if (ret) + dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret); + ret = spinand_detect(spinand); if (ret) goto err_free_bufs; -- 2.51.0 From 4041e34414c85a3f4bbfd292b255cce4eb722b49 Mon Sep 17 00:00:00 2001 From: "SkyLake.Huang" Date: Thu, 23 Jun 2022 18:40:59 +0800 Subject: [PATCH 481/517] drivers: mtd: spi-nor: Add calibration support for spi-nor Signed-off-by: SkyLake.Huang --- drivers/mtd/nand/spi/core.c | 5 ++++- drivers/mtd/spi-nor/core.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index ed8a2d2b2dd2..a74bda5c4965 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1241,7 +1241,10 @@ static int spinand_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int rea if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, + &status); if (ret < 0) return ret; diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 5bb7da0ef34d..de146408e605 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3300,6 +3300,18 @@ static const struct flash_info *spi_nor_match_name(struct spi_nor *nor, return NULL; } +static int spi_nor_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen) +{ + struct spi_nor *nor = (struct spi_nor *)priv; + + nor->reg_proto = SNOR_PROTO_1_1_1; + nor->read_proto = SNOR_PROTO_1_1_1; + nor->read_opcode = SPINOR_OP_READ; + nor->read_dummy = 0; + + return nor->controller_ops->read(nor, *addr, readlen, buf); +} + static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor, const char *name) { @@ -3474,6 +3486,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; + if(nor->spimem) + spi_mem_do_calibration(nor->spimem, spi_nor_cal_read, nor); + info = spi_nor_get_flash_info(nor, name); if (IS_ERR(info)) return PTR_ERR(info); -- 2.51.0 From 989bc477ae72c09f5068823fd74d038b4219c6f2 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 12 Jul 2023 13:38:35 +0100 Subject: [PATCH 482/517] nvmem: add layout for Adtran devices Adtran stores unique factory data on GPT partitions on the eMMC. Using blk-nvmem the 'mfginfo' partition gets exposes as NVMEM provider. Add layout driver to parse mfginfo, mainly to provide MAC addresses to Ethernet and wireless interfaces. Variable names are converted to lower-case and '_' is replaced with '-' in order to comply with the device tree node naming convention. The main MAC address always ends on a 0 and up to 16 addresses are alocated for each device to use for various interfaces. Implement post-processing function for 'MFG_MAC' variable ('mfg-mac' node name in device tree) adding the nvmem cell index to the least significant digit of the MAC address. Signed-off-by: Daniel Golle --- drivers/nvmem/layouts/Kconfig | 9 +++ drivers/nvmem/layouts/Makefile | 1 + drivers/nvmem/layouts/adtran.c | 135 +++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/nvmem/layouts/adtran.c diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig index 58df4ad61e13..3b8ef65629b7 100644 --- a/drivers/nvmem/layouts/Kconfig +++ b/drivers/nvmem/layouts/Kconfig @@ -8,6 +8,15 @@ if NVMEM_LAYOUTS menu "Layout Types" +config NVMEM_LAYOUT_ADTRAN + tristate "Adtran mfginfo layout support" + select GENERIC_NET_UTILS + help + Say Y here if you want to support the layout used by Adtran for + mfginfo. + + If unsure, say N. + config NVMEM_LAYOUT_SL28_VPD tristate "Kontron sl28 VPD layout support" select CRC8 diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile index 060ddf18d05a..75902980e89a 100644 --- a/drivers/nvmem/layouts/Makefile +++ b/drivers/nvmem/layouts/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o +obj-$(CONFIG_NVMEM_LAYOUT_ADTRAN) += adtran.o obj-$(CONFIG_NVMEM_LAYOUT_ASCII_ENV) += ascii-env.o diff --git a/drivers/nvmem/layouts/adtran.c b/drivers/nvmem/layouts/adtran.c new file mode 100644 index 000000000000..65f55f413917 --- /dev/null +++ b/drivers/nvmem/layouts/adtran.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include + +/* + * Adtran devices usually come with a main MAC address ending on 0 and + * hence may have up to 16 MAC addresses per device. + * The main MAC address is stored as variable MFG_MAC in ASCII format. + */ +static int adtran_mac_address_pp(void *priv, const char *id, int index, + unsigned int offset, void *buf, + size_t bytes) +{ + u8 mac[ETH_ALEN]; + + if (WARN_ON(bytes != 3 * ETH_ALEN - 1)) + return -EINVAL; + + if (!mac_pton(buf, mac)) + return -EINVAL; + + if (index) + eth_addr_add(mac, index); + + ether_addr_copy(buf, mac); + + return 0; +} + +static int adtran_add_cells(struct nvmem_layout *layout) +{ + struct nvmem_device *nvmem = layout->nvmem; + struct nvmem_cell_info info; + struct device_node *layout_np; + char mfginfo[1024], *c, *t, *p; + int ret = -EINVAL; + + ret = nvmem_device_read(nvmem, 0, sizeof(mfginfo), mfginfo); + if (ret < 0) + return ret; + else if (ret != sizeof(mfginfo)) + return -EIO; + + layout_np = of_nvmem_layout_get_container(nvmem); + if (!layout_np) + return -ENOENT; + + c = mfginfo; + while (*c != 0xff) { + memset(&info, 0, sizeof(info)); + if (*c == '#') + goto nextline; + + t = strchr(c, '='); + if (!t) + goto nextline; + + *t = '\0'; + ++t; + info.offset = t - mfginfo; + /* process variable name: convert to lower-case, '_' -> '-' */ + p = c; + do { + *p = tolower(*p); + if (*p == '_') + *p = '-'; + } while (*++p); + info.name = c; + c = strchr(t, 0xa); /* find newline */ + if (!c) + break; + + info.bytes = c - t; + if (!strcmp(info.name, "mfg-mac")) { + info.raw_len = info.bytes; + info.bytes = ETH_ALEN; + info.read_post_process = adtran_mac_address_pp; + } + + info.np = of_get_child_by_name(layout_np, info.name); + ret = nvmem_add_one_cell(nvmem, &info); + if (ret) + break; + + ++c; + continue; + +nextline: + c = strchr(c, 0xa); /* find newline */ + if (!c) + break; + ++c; + } + + of_node_put(layout_np); + + return ret; +} + +static int adtran_probe(struct nvmem_layout *layout) +{ + layout->add_cells = adtran_add_cells; + + return nvmem_layout_register(layout); +} + +static void adtran_remove(struct nvmem_layout *layout) +{ + nvmem_layout_unregister(layout); +} + +static const struct of_device_id adtran_of_match_table[] = { + { .compatible = "adtran,mfginfo" }, + {}, +}; +MODULE_DEVICE_TABLE(of, adtran_of_match_table); + +static struct nvmem_layout_driver adtran_layout = { + .driver = { + .owner = THIS_MODULE, + .name = "adtran-layout", + .of_match_table = adtran_of_match_table, + }, + .probe = adtran_probe, + .remove = adtran_remove, +}; +module_nvmem_layout_driver(adtran_layout); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_DESCRIPTION("NVMEM layout driver for Adtran mfginfo"); -- 2.51.0 From 21831b4ae092e1a34c89accb466796f284aecccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:02 +0100 Subject: [PATCH 483/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/500-gsw-rtl8367s-mt7622-support.patch --- drivers/net/phy/Kconfig | 6 ++++++ drivers/net/phy/Makefile | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 0e672540a0fa..2fcb9544a3b0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -443,6 +443,12 @@ config ROCKCHIP_PHY help Currently supports the integrated Ethernet PHY. +config RTL8367S_GSW + tristate "rtl8367 Gigabit Switch support for mt7622" + depends on NET_VENDOR_MEDIATEK + help + This driver supports rtl8367s in mt7622 + config SMSC_PHY tristate "SMSC PHYs" select CRC16 diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index d0f2b36d5c87..f869dd4a7ff4 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_REALTEK_PHY) += realtek/ obj-y += rtl8261n/ obj-$(CONFIG_RENESAS_PHY) += uPD60620.o obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o +obj-$(CONFIG_RTL8367S_GSW) += rtk/ obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_STE10XP) += ste10Xp.o obj-$(CONFIG_TERANETICS_PHY) += teranetics.o -- 2.51.0 From 3e406f4731e75b7970b37050aacbeba4dec6adbc Mon Sep 17 00:00:00 2001 From: qizhong cheng Date: Mon, 27 Dec 2021 21:31:10 +0800 Subject: [PATCH 484/517] PCI: mediatek: Assert PERST# for 100ms for power and clock to stabilize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Described in PCIe CEM specification sections 2.2 (PERST# Signal) and 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should be delayed 100ms (TPVPERL) for the power and clock to become stable. Link: https://lore.kernel.org/r/20211227133110.14500-1-qizhong.cheng@mediatek.com Signed-off-by: qizhong cheng Signed-off-by: Lorenzo Pieralisi Acked-by: Pali Rohár --- drivers/pci/controller/pcie-mediatek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 7f7d04c2ea57..bebad5744f6a 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -700,6 +700,13 @@ static int mtk_pcie_startup_port_v2(struct mtk_pcie_port *port) */ msleep(100); + /* + * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and + * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# should + * be delayed 100ms (TPVPERL) for the power and clock to become stable. + */ + msleep(100); + /* De-assert PHY, PE, PIPE, MAC and configuration reset */ val = readl(port->base + PCIE_RST_CTRL); val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | -- 2.51.0 From 2b9d1f47e69e82aed8f0bd2a2d90058b0e3d419d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:03 +0100 Subject: [PATCH 485/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/602-arm64-dts-mediatek-add-mt7622-pcie-slot-node.patch --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index 39c57987412e..ce802c3b22df 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -844,6 +844,12 @@ pcie_intc0: interrupt-controller { #address-cells = <0>; #interrupt-cells = <1>; }; + + slot0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + }; }; pcie1: pcie@1a145000 { @@ -882,6 +888,12 @@ pcie_intc1: interrupt-controller { #address-cells = <0>; #interrupt-cells = <1>; }; + + slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + }; }; sata: sata@1a200000 { -- 2.51.0 From 69fde5ab7287db38c278acdb564529d89ad28e10 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 4 Sep 2020 18:33:27 +0200 Subject: [PATCH 486/517] pcie-mediatek: fix clearing interrupt status Clearing the status needs to happen after running the handler, otherwise we will get an extra spurious interrupt after the cause has been cleared Signed-off-by: Felix Fietkau --- drivers/pci/controller/pcie-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index bebad5744f6a..b723cdfab3a0 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -599,9 +599,9 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc) if (status & INTX_MASK) { for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) { /* Clear the INTx */ - writel(1 << bit, port->base + PCIE_INT_STATUS); generic_handle_domain_irq(port->irq_domain, bit - INTX_SHIFT); + writel(1 << bit, port->base + PCIE_INT_STATUS); } } -- 2.51.0 From 02b4f75a67349d0d6d444424714f3af80ee1d8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:03 +0100 Subject: [PATCH 487/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/611-pcie-mediatek-gen3-PERST-for-100ms.patch --- drivers/pci/controller/pcie-mediatek-gen3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 66ce4b5d309b..ebc9f95871f9 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -416,7 +416,13 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie) msleep(100); /* De-assert reset signals */ - val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB); + val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB); + writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG); + + msleep(100); + + /* De-assert PERST# signals */ + val &= ~(PCIE_PE_RSTB); writel_relaxed(val, pcie->base + PCIE_RST_CTRL_REG); /* Check if the link is up or not */ -- 2.51.0 From c4fd81f1dc30a95d6edce67a6cbc0fa933c403b2 Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Wed, 19 Feb 2025 16:39:08 +0800 Subject: [PATCH 488/517] net: phy: mediatek: Add 2.5Gphy firmware dt-bindings and dts node Add 2.5Gphy firmware dt-bindings and dts node since mtk-2p5ge driver requires firmware to run. Also, update MAINTAINERS for MediaTek's built-in 2.5Gphy dt-bindings and change MAINTAINER's name. Signed-off-by: Sky Huang --- .../bindings/net/mediatek,2p5gphy-fw.yaml | 37 +++++++++++++++++++ MAINTAINERS | 3 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml diff --git a/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml b/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml new file mode 100644 index 000000000000..56ebe88b8921 --- /dev/null +++ b/Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/mediatek,2p5gphy-fw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Built-in 2.5G Ethernet PHY + +maintainers: + - Sky Huang + +description: | + MediaTek Built-in 2.5G Ethernet PHY needs to load firmware so it can + run correctly. + +properties: + compatible: + const: "mediatek,2p5gphy-fw" + + reg: + items: + - description: pmb firmware load address + - description: firmware trigger register + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + phyfw: phy-firmware@f000000 { + compatible = "mediatek,2p5gphy-fw"; + reg = <0 0x0f100000 0 0x20000>, + <0 0x0f0f0018 0 0x20>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 3a22c29b35a6..f04fc126dd78 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14426,9 +14426,10 @@ F: include/linux/pcs/pcs-mtk-usxgmii.h MEDIATEK ETHERNET PHY DRIVERS M: Daniel Golle M: Qingfang Deng -M: SkyLake Huang +M: Sky Huang L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml F: drivers/net/phy/mediatek/mtk-ge-soc.c F: drivers/net/phy/mediatek/mtk-phy-lib.c F: drivers/net/phy/mediatek/mtk-ge.c -- 2.51.0 From 6b90226390bcd6d572873fe141aa5eec27f598ba Mon Sep 17 00:00:00 2001 From: Sky Huang Date: Wed, 19 Feb 2025 16:39:10 +0800 Subject: [PATCH 489/517] net: phy: mediatek: add driver for built-in 2.5G ethernet PHY on MT7988 Add support for internal 2.5Gphy on MT7988. This driver will load necessary firmware and add appropriate time delay to make sure that firmware works stably. Also, certain control registers will be set to fix link-up issues. Signed-off-by: Sky Huang --- MAINTAINERS | 1 + drivers/net/phy/mediatek/Kconfig | 11 + drivers/net/phy/mediatek/Makefile | 1 + drivers/net/phy/mediatek/mtk-2p5ge.c | 342 +++++++++++++++++++++++++++ 4 files changed, 355 insertions(+) create mode 100644 drivers/net/phy/mediatek/mtk-2p5ge.c diff --git a/MAINTAINERS b/MAINTAINERS index f04fc126dd78..8495e72f363b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14430,6 +14430,7 @@ M: Sky Huang L: netdev@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/net/mediatek,2p5gphy-fw.yaml +F: drivers/net/phy/mediatek/mtk-2p5ge.c F: drivers/net/phy/mediatek/mtk-ge-soc.c F: drivers/net/phy/mediatek/mtk-phy-lib.c F: drivers/net/phy/mediatek/mtk-ge.c diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index 4308002bb82c..6f8f69213aae 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -26,3 +26,14 @@ config MEDIATEK_GE_SOC_PHY the MT7981 and MT7988 SoCs. These PHYs need calibration data present in the SoCs efuse and will dynamically calibrate VCM (common-mode voltage) during startup. + +config MEDIATEK_2P5GE_PHY + tristate "MediaTek 2.5Gb Ethernet PHYs" + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in 2.5Gb Ethernet PHYs. + + This will load necessary firmware and add appropriate time delay. + Accelerate this procedure through internal pbus instead of MDIO + bus. Certain link-up issues will also be fixed here. diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile index 814879d0abe5..c6db8abd2c9c 100644 --- a/drivers/net/phy/mediatek/Makefile +++ b/drivers/net/phy/mediatek/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o +obj-$(CONFIG_MEDIATEK_2P5GE_PHY) += mtk-2p5ge.o diff --git a/drivers/net/phy/mediatek/mtk-2p5ge.c b/drivers/net/phy/mediatek/mtk-2p5ge.c new file mode 100644 index 000000000000..9e5a0331e719 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-2p5ge.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk.h" + +#define MTK_2P5GPHY_ID_MT7988 (0x00339c11) + +#define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin" +#define MT7988_2P5GE_PMB_FW_SIZE (0x20000) +#define MD32_EN_CFG (0x18) +#define MD32_EN BIT(0) + +#define BASE100T_STATUS_EXTEND (0x10) +#define BASE1000T_STATUS_EXTEND (0x11) +#define EXTEND_CTRL_AND_STATUS (0x16) + +#define PHY_AUX_CTRL_STATUS (0x1d) +#define PHY_AUX_DPX_MASK GENMASK(5, 5) +#define PHY_AUX_SPEED_MASK GENMASK(4, 2) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_LPI_PCS_DSP_CTRL (0x121) +#define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8) + +#define MTK_PHY_HOST_CMD1 0x800e +#define MTK_PHY_HOST_CMD2 0x800f +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +#define AUTO_NP_10XEN BIT(6) + +struct mtk_i2p5ge_phy_priv { + bool fw_loaded; +}; + +enum { + PHY_AUX_SPD_10 = 0, + PHY_AUX_SPD_100, + PHY_AUX_SPD_1000, + PHY_AUX_SPD_2500, +}; + +static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev) +{ + struct mtk_i2p5ge_phy_priv *priv = phydev->priv; + void __iomem *mcu_csr_base, *pmb_addr; + struct device *dev = &phydev->mdio.dev; + const struct firmware *fw; + struct device_node *np; + int ret, i; + u32 reg; + + np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw"); + if (!np) + return -ENOENT; + + pmb_addr = of_iomap(np, 0); + if (!pmb_addr) + return -ENOMEM; + mcu_csr_base = of_iomap(np, 1); + if (!mcu_csr_base) { + ret = -ENOMEM; + goto free_pmb; + } + + ret = request_firmware(&fw, MT7988_2P5GE_PMB_FW, dev); + if (ret) { + dev_err(dev, "failed to load firmware: %s, ret: %d\n", + MT7988_2P5GE_PMB_FW, ret); + goto free; + } + + if (fw->size != MT7988_2P5GE_PMB_FW_SIZE) { + dev_err(dev, "Firmware size 0x%zx != 0x%x\n", + fw->size, MT7988_2P5GE_PMB_FW_SIZE); + ret = -EINVAL; + goto release_fw; + } + + reg = readw(mcu_csr_base + MD32_EN_CFG); + if (reg & MD32_EN) { + phy_set_bits(phydev, MII_BMCR, BMCR_RESET); + usleep_range(10000, 11000); + } + phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); + + /* Write magic number to safely stall MCU */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD1, 0x1100); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_HOST_CMD2, 0x00df); + + for (i = 0; i < MT7988_2P5GE_PMB_FW_SIZE - 1; i += 4) + writel(*((uint32_t *)(fw->data + i)), pmb_addr + i); + + if (!priv->fw_loaded) + dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n", + be16_to_cpu(*((__be16 *)(fw->data + + MT7988_2P5GE_PMB_FW_SIZE - 8))), + *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 6), + *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 5), + *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 2), + *(fw->data + MT7988_2P5GE_PMB_FW_SIZE - 1)); + + writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG); + writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG); + phy_set_bits(phydev, MII_BMCR, BMCR_RESET); + /* We need a delay here to stabilize initialization of MCU */ + usleep_range(7000, 8000); + + priv->fw_loaded = true; + +release_fw: + release_firmware(fw); +free: + iounmap(mcu_csr_base); +free_pmb: + iounmap(pmb_addr); + + return ret; +} + +static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev) +{ + struct pinctrl *pinctrl; + int ret; + + /* Check if PHY interface type is compatible */ + if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL) + return -ENODEV; + + ret = mt798x_2p5ge_phy_load_fw(phydev); + if (ret < 0) + return ret; + + /* Setup LED */ + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY | MTK_PHY_LED_ON_LINK10 | + MTK_PHY_LED_ON_LINK100 | MTK_PHY_LED_ON_LINK1000 | + MTK_PHY_LED_ON_LINK2500); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX); + + /* Switch pinctrl after setting polarity to avoid bogus blinking */ + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led"); + if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) + dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n"); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL, + MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0); + + /* Enable 16-bit next page exchange bit if 1000-BT isn't advertising */ + mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AUTO_NP_10XEN, + FIELD_PREP(AUTO_NP_10XEN, 0x1)); + + /* Enable HW auto downshift */ + phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, + MTK_PHY_AUX_CTRL_AND_STATUS, + 0, MTK_PHY_ENABLE_DOWNSHIFT); + + return 0; +} + +static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u32 adv; + int ret; + + ret = genphy_c45_an_config_aneg(phydev); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + /* Clause 45 doesn't define 1000BaseT support. Use Clause 22 instead in + * our design. + */ + adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); + ret = phy_modify_changed(phydev, MII_CTRL1000, ADVERTISE_1000FULL, adv); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + return __genphy_config_aneg(phydev, changed); +} + +static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + /* This phy can't handle collision, and neither can (XFI)MAC it's + * connected to. Although it can do HDX handshake, it doesn't support + * CSMA/CD that HDX requires. + */ + linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, + phydev->supported); + + return 0; +} + +static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev) +{ + int ret; + + /* When MDIO_STAT1_LSTATUS is raised genphy_c45_read_link(), this phy + * actually hasn't finished AN. So use CL22's link update function + * instead. + */ + ret = genphy_update_link(phydev); + if (ret) + return ret; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + /* We'll read link speed through vendor specific registers down below. + * So remove phy_resolve_aneg_linkmode (AN on) & genphy_c45_read_pma + * (AN off). + */ + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { + ret = genphy_c45_read_lpa(phydev); + if (ret < 0) + return ret; + + /* Clause 45 doesn't define 1000BaseT support. Read the link + * partner's 1G advertisement via Clause 22. + */ + ret = phy_read(phydev, MII_STAT1000); + if (ret < 0) + return ret; + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret); + } else if (phydev->autoneg == AUTONEG_DISABLE) { + linkmode_zero(phydev->lp_advertising); + } + + if (phydev->link) { + ret = phy_read(phydev, PHY_AUX_CTRL_STATUS); + if (ret < 0) + return ret; + + switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) { + case PHY_AUX_SPD_10: + phydev->speed = SPEED_10; + break; + case PHY_AUX_SPD_100: + phydev->speed = SPEED_100; + break; + case PHY_AUX_SPD_1000: + phydev->speed = SPEED_1000; + break; + case PHY_AUX_SPD_2500: + phydev->speed = SPEED_2500; + break; + } + + phydev->duplex = DUPLEX_FULL; + /* FIXME: + * The current firmware always enables rate adaptation mode. + */ + phydev->rate_matching = RATE_MATCH_PAUSE; + } + + return 0; +} + +static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev, + phy_interface_t iface) +{ + return RATE_MATCH_PAUSE; +} + +static int mt798x_2p5ge_phy_probe(struct phy_device *phydev) +{ + struct mtk_i2p5ge_phy_priv *priv; + + priv = devm_kzalloc(&phydev->mdio.dev, + sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + switch (phydev->drv->phy_id) { + case MTK_2P5GPHY_ID_MT7988: + /* The original hardware only sets MDIO_DEVS_PMAPMD */ + phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS | + MDIO_DEVS_AN | + MDIO_DEVS_VEND1 | + MDIO_DEVS_VEND2; + break; + default: + return -EINVAL; + } + + priv->fw_loaded = false; + phydev->priv = priv; + + return 0; +} + +static struct phy_driver mtk_2p5gephy_driver[] = { + { + PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988), + .name = "MediaTek MT7988 2.5GbE PHY", + .probe = mt798x_2p5ge_phy_probe, + .config_init = mt798x_2p5ge_phy_config_init, + .config_aneg = mt798x_2p5ge_phy_config_aneg, + .get_features = mt798x_2p5ge_phy_get_features, + .read_status = mt798x_2p5ge_phy_read_status, + .get_rate_matching = mt798x_2p5ge_phy_get_rate_matching, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, + }, +}; + +module_phy_driver(mtk_2p5gephy_driver); + +static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = { + { PHY_ID_MATCH_VENDOR(0x00339c00) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver"); +MODULE_AUTHOR("SkyLake Huang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl); +MODULE_FIRMWARE(MT7988_2P5GE_PMB_FW); -- 2.51.0 From a42eb788cf9cd31ab5c465f6a0843ff7530cb20d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 4 Sep 2020 18:42:42 +0200 Subject: [PATCH 490/517] pci: pcie-mediatek: add support for coherent DMA It improves performance by eliminating the need for a cache flush for DMA on attached devices Signed-off-by: Felix Fietkau --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 8 ++++++- drivers/pci/controller/pcie-mediatek.c | 27 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index ce802c3b22df..c4216828487e 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -832,6 +832,9 @@ pcie0: pcie@1a143000 { bus-range = <0x00 0xff>; ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>; status = "disabled"; + dma-coherent; + mediatek,hifsys = <&hifsys>; + mediatek,cci-control = <&cci_control2>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; @@ -876,6 +879,9 @@ pcie1: pcie@1a145000 { bus-range = <0x00 0xff>; ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>; status = "disabled"; + dma-coherent; + mediatek,hifsys = <&hifsys>; + mediatek,cci-control = <&cci_control2>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 7>; @@ -937,7 +943,7 @@ sata_port: sata-phy@1a243000 { }; hifsys: clock-controller@1af00000 { - compatible = "mediatek,mt7622-hifsys"; + compatible = "mediatek,mt7622-hifsys", "syscon"; reg = <0 0x1af00000 0 0x70>; #clock-cells = <1>; }; diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index b723cdfab3a0..daec88901679 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,11 @@ #define PCIE_LINK_STATUS_V2 0x804 #define PCIE_PORT_LINKUP_V2 BIT(10) +/* DMA channel mapping */ +#define HIFSYS_DMA_AG_MAP 0x008 +#define HIFSYS_DMA_AG_MAP_PCIE0 BIT(0) +#define HIFSYS_DMA_AG_MAP_PCIE1 BIT(1) + struct mtk_pcie_port; /** @@ -1052,6 +1058,27 @@ static int mtk_pcie_setup(struct mtk_pcie *pcie) struct mtk_pcie_port *port, *tmp; int err, slot; + if (of_dma_is_coherent(node)) { + struct regmap *con; + u32 mask; + + con = syscon_regmap_lookup_by_phandle(node, + "mediatek,cci-control"); + /* enable CPU/bus coherency */ + if (!IS_ERR(con)) + regmap_write(con, 0, 3); + + con = syscon_regmap_lookup_by_phandle(node, + "mediatek,hifsys"); + if (IS_ERR(con)) { + dev_err(dev, "missing hifsys node\n"); + return PTR_ERR(con); + } + + mask = HIFSYS_DMA_AG_MAP_PCIE0 | HIFSYS_DMA_AG_MAP_PCIE1; + regmap_update_bits(con, HIFSYS_DMA_AG_MAP, mask, mask); + } + slot = of_get_pci_domain_nr(dev->of_node); if (slot < 0) { for_each_available_child_of_node(node, child) { -- 2.51.0 From 1c08409b312633c3478c952996235c3de2976465 Mon Sep 17 00:00:00 2001 From: Jip de Beer Date: Sun, 9 Jan 2022 13:14:04 +0100 Subject: [PATCH 491/517] mediatek mt7622: fix 300mhz typo in dts The lowest frequency should be 300MHz, since that is the label assigned to the OPP in the mt7622.dtsi device tree, while there is one missing zero in the actual value. To be clear, the lowest frequency should be 300MHz instead of 30MHz. As mentioned @dangowrt on the OpenWrt forum there is no benefit in leaving 30MHz as the lowest frequency. Signed-off-by: Jip de Beer Signed-off-by: Fritz D. Ansel --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index c4216828487e..4ffc52a101f7 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -24,7 +24,7 @@ cpu_opp_table: opp-table { compatible = "operating-points-v2"; opp-shared; opp-300000000 { - opp-hz = /bits/ 64 <30000000>; + opp-hz = /bits/ 64 <300000000>; opp-microvolt = <950000>; }; -- 2.51.0 From a0cda045c7e0d8dc0a6164cd45c6ae3d84fadcbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:05 +0100 Subject: [PATCH 492/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/722-remove-300Hz-to-prevent-freeze.patch --- arch/arm64/boot/dts/mediatek/mt7622.dtsi | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi index 4ffc52a101f7..8ea9ae91c45c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi @@ -23,11 +23,17 @@ / { cpu_opp_table: opp-table { compatible = "operating-points-v2"; opp-shared; - opp-300000000 { - opp-hz = /bits/ 64 <300000000>; - opp-microvolt = <950000>; - }; - + /* Due to the bug described at the link below, remove the 300 MHz clock to avoid a low + * voltage condition that can cause a hang when rebooting the RT3200/E8450. + * + * https://forum.openwrt.org/t/belkin-rt3200-linksys-e8450-wifi-ax-discussion/94302/1490 + * + * opp-300000000 { + * opp-hz = /bits/ 64 <300000000>; + * opp-microvolt = <950000>; + * }; + * + */ opp-437500000 { opp-hz = /bits/ 64 <437500000>; opp-microvolt = <1000000>; -- 2.51.0 From 19f58b171d2812a5f40b48d4a61d7627996ac650 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 6 Apr 2023 23:36:50 +0100 Subject: [PATCH 493/517] net: phy: mxl-gpy: don't use SGMII AN if using phylink MAC drivers using phylink expect SGMII in-band-status to be switched off when attached to a PHY. Make sure this is the case also for mxl-gpy which keeps SGMII in-band-status in case of SGMII interface mode is used. Signed-off-by: Daniel Golle --- drivers/net/phy/mxl-gpy.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index e0bdbb66df5c..48fe9241cab3 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -380,8 +380,11 @@ static bool gpy_2500basex_chk(struct phy_device *phydev) phydev->speed = SPEED_2500; phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, - VSPEC1_SGMII_CTRL_ANEN, 0); + + if (!phydev->phylink) + phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, + VSPEC1_SGMII_CTRL_ANEN, 0); + return true; } @@ -432,6 +435,14 @@ static int gpy_config_aneg(struct phy_device *phydev) u32 adv; int ret; + /* Disable SGMII auto-negotiation if using phylink */ + if (phydev->phylink) { + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, + VSPEC1_SGMII_CTRL_ANEN, 0); + if (ret < 0) + return ret; + } + if (phydev->autoneg == AUTONEG_DISABLE) { /* Configure half duplex with genphy_setup_forced, * because genphy_c45_pma_setup_forced does not support. @@ -554,6 +565,8 @@ static int gpy_update_interface(struct phy_device *phydev) switch (phydev->speed) { case SPEED_2500: phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + if (phydev->phylink) + break; ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL, VSPEC1_SGMII_CTRL_ANEN, 0); if (ret < 0) { @@ -567,7 +580,7 @@ static int gpy_update_interface(struct phy_device *phydev) case SPEED_100: case SPEED_10: phydev->interface = PHY_INTERFACE_MODE_SGMII; - if (gpy_sgmii_aneg_en(phydev)) + if (phydev->phylink || gpy_sgmii_aneg_en(phydev)) break; /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed * if ANEG is disabled (in 2500-BaseX mode). -- 2.51.0 From 1afe6c2034b55a0e26d3e458c83c8d09b8da783b Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sat, 23 Mar 2024 20:21:14 +0100 Subject: [PATCH 494/517] net: phy: add Airoha EN8801SC PHY Airoha EN8801SC Gigabit PHY is used on Edgecore EAP111, so include a modified version of MTK SDK driver. Signed-off-by: Robert Marko --- drivers/net/phy/Kconfig | 5 +++++ drivers/net/phy/Makefile | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 2fcb9544a3b0..c627136d9ed0 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -165,6 +165,11 @@ config AS21XXX_PHY AS21210PB1 that all register with the PHY ID 0x7500 0x7500 before the firmware is loaded. +config AIROHA_EN8801SC_PHY + tristate "Airoha EN8801SC Gigabit PHY" + help + Currently supports the Airoha EN8801SC PHY. + config AIR_EN8811H_PHY tristate "Airoha EN8811H 2.5 Gigabit PHY" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index f869dd4a7ff4..845ee491e8d9 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -50,6 +50,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o +obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o -- 2.51.0 From e1f280932e8365d4a856f205554968ae9aea46c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:06 +0100 Subject: [PATCH 495/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/736-net-pcs-mtk_usxgmii-add-polarity-control.patch --- drivers/net/pcs/pcs-mtk-usxgmii.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/pcs/pcs-mtk-usxgmii.c b/drivers/net/pcs/pcs-mtk-usxgmii.c index 9691d9e73790..4ce212e366e9 100644 --- a/drivers/net/pcs/pcs-mtk-usxgmii.c +++ b/drivers/net/pcs/pcs-mtk-usxgmii.c @@ -52,6 +52,12 @@ #define USXGMII_LPA GENMASK(15, 0) #define USXGMII_LPA_LATCH BIT(31) +/* Register to control PCS polarity */ +#define RG_PHY_TOP_CTRL0 0x82C +#define USXGMII_PN_SWAP_MASK GENMASK(1, 0) +#define USXGMII_PN_SWAP_RX BIT(1) +#define USXGMII_PN_SWAP_TX BIT(0) + /* Register to read PCS link status */ #define RG_PCS_RX_STATUS0 0x904 #define RG_PCS_RX_STATUS_UPDATE BIT(16) @@ -74,6 +80,7 @@ struct mtk_usxgmii_pcs { struct clk *clk; struct reset_control *reset; phy_interface_t interface; + unsigned int polarity; unsigned int neg_mode; struct list_head node; }; @@ -155,6 +162,10 @@ static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode mtk_usxgmii_reset(mpcs); + /* Configure the interface polarity */ + mtk_m32(mpcs, RG_PHY_TOP_CTRL0, + USXGMII_PN_SWAP_MASK, mpcs->polarity); + /* Setup USXGMII AN ctrl */ mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE, @@ -332,6 +343,7 @@ static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = { static int mtk_usxgmii_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct mtk_usxgmii_pcs *mpcs; mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); @@ -342,6 +354,13 @@ static int mtk_usxgmii_probe(struct platform_device *pdev) if (IS_ERR(mpcs->base)) return PTR_ERR(mpcs->base); + if (of_property_read_bool(np->parent, "mediatek,pnswap")) + mpcs->polarity = USXGMII_PN_SWAP_TX | USXGMII_PN_SWAP_RX; + else if (of_property_read_bool(np, "mediatek,pnswap-tx")) + mpcs->polarity = USXGMII_PN_SWAP_TX; + else if (of_property_read_bool(np, "mediatek,pnswap-rx")) + mpcs->polarity = USXGMII_PN_SWAP_RX; + mpcs->dev = dev; mpcs->pcs.ops = &mtk_usxgmii_pcs_ops; mpcs->pcs.poll = true; -- 2.51.0 From 82fbdfafa6531553caab6cf3b09e8f969956ff1d Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 9 Dec 2024 14:44:17 +0100 Subject: [PATCH 496/517] net: dsa: Add Airoha AN8855 support This small series add the initial support for the Airoha AN8855 Switch. It's a 5 port Gigabit Switch with SGMII/HSGMII upstream port. This is starting to get in the wild and there are already some router having this switch chip. It's conceptually similar to mediatek switch but register and bits are different. And there is that massive Hell that is the PCS configuration. Saddly for that part we have absolutely NO documentation currently. There is this special thing where PHY needs to be calibrated with values from the switch efuse. (the thing have a whole cpu timer and MCU) Changes v11: - Address reviews from Christophe (spell mistake + dev_err_probe) - Fix kconfig dependency for MFD driver (depends on MDIO_DEVICE instead of MDIO) (indirectly fix link error for mdio APIs) - Fix copy-paste error for MFD driver of_table - Fix compilation error for PHY (move NVMEM to .config) - Drop unneeded NVMEM node from MDIO example schema (from Andrew) - Adapt MFD example schema to MDIO reg property restrictions Changes v10: - Entire rework to MFD + split to MDIO, EFUSE, SWITCH separate drivers - Drop EEE OPs (while Russell finish RFC for EEE changes) - Use new pcs_inpand OPs - Drop AN restart function and move to pcs_config - Enable assisted_learning and disable CPU learn (preparation for fdb_isolation) - Move EFUSE read in Internal PHY driver to .config to handle EPROBE_DEFER (needed now that NVMEM driver is register externally instead of internally to switch node) Changes v9: - Error out on using 5G speed as currently not supported - Add missing MAC_2500FD in phylink mac_capabilities - Add comment and improve if condition for an8855_phylink_mac_config Changes v8: - Add port Fast Age support - Add support for Port Isolation - Use correct register for Learning Disable - Add support for Ageing Time OP - Set default PVID to 0 by default - Add mdb OPs - Add port change MTU - Fix support for Upper VLAN Changes v7: - Fix devm_dsa_register_switch wrong export symbol Changes v6: - Drop standard MIB and handle with ethtool OPs (as requested by Jakub) - Cosmetic: use bool instead of 0 or 1 Changes v5: - Add devm_dsa_register_switch() patch - Add Reviewed-by tag for DT patch Changes v4: - Set regmap readable_table static (mute compilation warning) - Add support for port_bridge flags (LEARNING, FLOOD) - Reset fdb struct in fdb_dump - Drop support_asym_pause in port_enable - Add define for get_phy_flags - Fix bug for port not inititially part of a bridge (in an8855_setup the port matrix was always cleared but the CPU port was never initially added) - Disable learning and flood for user port by default - Set CPU port to flood and learning by default - Correctly AND force duplex and flow control in an8855_phylink_mac_link_up - Drop RGMII from pcs_config - Check ret in "Disable AN if not in autoneg" - Use devm_mutex_init - Fix typo for AN8855_PORT_CHECK_MODE - Better define AN8855_STP_LISTENING = AN8855_STP_BLOCKING - Fix typo in AN8855_PHY_EN_DOWN_SHIFT - Use paged helper for PHY - Skip calibration in config_init if priv not defined Changes v3: - Out of RFC - Switch PHY code to select_page API - Better describe masks and bits in PHY driver for ADC register - Drop raw values and use define for mii read/write - Switch to absolute PHY address - Replace raw values with mask and bits for pcs_config - Fix typo for ext-surge property name - Drop support for relocating Switch base PHY address on the bus Changes v2: - Drop mutex guard patch - Drop guard usage in DSA driver - Use __mdiobus_write/read - Check return condition and return errors for mii read/write - Fix wrong logic for EEE - Fix link_down (don't force link down with autoneg) - Fix forcing speed on sgmii autoneg - Better document link speed for sgmii reg - Use standard define for sgmii reg - Imlement nvmem support to expose switch EFUSE - Rework PHY calibration with the use of NVMEM producer/consumer - Update DT with new NVMEM property - Move aneg validation for 2500-basex in pcs_config - Move r50Ohm table and function to PHY driver Christian Marangi (9): dt-bindings: nvmem: Document support for Airoha AN8855 Switch EFUSE dt-bindings: net: Document support for Airoha AN8855 Switch Virtual MDIO dt-bindings: net: dsa: Document support for Airoha AN8855 DSA Switch dt-bindings: mfd: Document support for Airoha AN8855 Switch SoC mfd: an8855: Add support for Airoha AN8855 Switch MFD net: mdio: Add Airoha AN8855 Switch MDIO Passtrough nvmem: an8855: Add support for Airoha AN8855 Switch EFUSE net: dsa: Add Airoha AN8855 5-Port Gigabit DSA Switch driver net: phy: Add Airoha AN8855 Internal Switch Gigabit PHY .../bindings/mfd/airoha,an8855-mfd.yaml | 178 ++ .../bindings/net/airoha,an8855-mdio.yaml | 56 + .../net/dsa/airoha,an8855-switch.yaml | 105 + .../bindings/nvmem/airoha,an8855-efuse.yaml | 123 + MAINTAINERS | 17 + drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/airoha-an8855.c | 278 ++ drivers/net/dsa/Kconfig | 9 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/an8855.c | 2310 +++++++++++++++++ drivers/net/dsa/an8855.h | 783 ++++++ drivers/net/mdio/Kconfig | 9 + drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-an8855.c | 113 + drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + drivers/net/phy/air_an8855.c | 267 ++ drivers/nvmem/Kconfig | 11 + drivers/nvmem/Makefile | 2 + drivers/nvmem/an8855-efuse.c | 63 + include/linux/mfd/airoha-an8855-mfd.h | 41 + 22 files changed, 4384 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/airoha,an8855-mfd.yaml create mode 100644 Documentation/devicetree/bindings/net/airoha,an8855-mdio.yaml create mode 100644 Documentation/devicetree/bindings/net/dsa/airoha,an8855-switch.yaml create mode 100644 Documentation/devicetree/bindings/nvmem/airoha,an8855-efuse.yaml create mode 100644 drivers/mfd/airoha-an8855.c create mode 100644 drivers/net/dsa/an8855.c create mode 100644 drivers/net/dsa/an8855.h create mode 100644 drivers/net/mdio/mdio-an8855.c create mode 100644 drivers/net/phy/air_an8855.c create mode 100644 drivers/nvmem/an8855-efuse.c create mode 100644 include/linux/mfd/airoha-an8855-mfd.h --- drivers/mfd/Kconfig | 10 ++++++++++ drivers/mfd/Makefile | 1 + drivers/net/dsa/Kconfig | 9 +++++++++ drivers/net/dsa/Makefile | 1 + drivers/net/mdio/Kconfig | 9 +++++++++ drivers/net/mdio/Makefile | 1 + drivers/net/phy/Kconfig | 5 +++++ drivers/net/phy/Makefile | 1 + drivers/nvmem/Kconfig | 11 +++++++++++ drivers/nvmem/Makefile | 2 ++ 10 files changed, 50 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f9325bcce1b9..340d8a03558c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -53,6 +53,16 @@ config MFD_ALTERA_SYSMGR using regmap_mmio accesses for ARM32 parts and SMC calls to EL3 for ARM64 parts. +config MFD_AIROHA_AN8855 + tristate "Airoha AN8855 Switch MFD" + select MFD_CORE + select MDIO_DEVICE + depends on NETDEVICES && OF + help + Support for the Airoha AN8855 Switch MFD. This is a SoC Switch + that provides various peripherals. Currently it provides a + DSA switch and a NVMEM provider. + config MFD_ACT8945A tristate "Active-semi ACT8945A" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2a9f91e81af8..da210d16c7bb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_88PM886_PMIC) += 88pm886.o obj-$(CONFIG_MFD_ACT8945A) += act8945a.o +obj-$(CONFIG_MFD_AIROHA_AN8855) += airoha-an8855.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index b7b473e3fc02..37a4a0b7ae96 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -24,6 +24,15 @@ config NET_DSA_LOOP This enables support for a fake mock-up switch chip which exercises the DSA APIs. +config NET_DSA_AN8855 + tristate "Airoha AN8855 Ethernet switch support" + depends on MFD_AIROHA_AN8855 + depends on NET_DSA + select NET_DSA_TAG_MTK + help + This enables support for the Airoha AN8855 Ethernet switch + chip. + source "drivers/net/dsa/hirschmann/Kconfig" config NET_DSA_LANTIQ_GSWIP diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 23dbdf1a36a8..1e9d01ef7490 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -6,6 +6,7 @@ ifdef CONFIG_NET_DSA_LOOP obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdinfo.o endif obj-$(CONFIG_NET_DSA_KS8995) += ks8995.o +obj-$(CONFIG_NET_DSA_AN8855) += an8855.o obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index 4a7a303be2f7..3d417948e73a 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -61,6 +61,15 @@ config MDIO_XGENE This module provides a driver for the MDIO busses found in the APM X-Gene SoC's. +config MDIO_AN8855 + tristate "Airoha AN8855 Switch MDIO bus controller" + depends on MFD_AIROHA_AN8855 + depends on OF_MDIO + help + This module provides a driver for the Airoha AN8855 Switch + that requires a MDIO passtrough as switch address is shared + with the internal PHYs and requires additional page handling. + config MDIO_ASPEED tristate "ASPEED MDIO bus controller" depends on ARCH_ASPEED || COMPILE_TEST diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile index 1015f0db4531..546c4e55b475 100644 --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ACPI_MDIO) += acpi_mdio.o obj-$(CONFIG_FWNODE_MDIO) += fwnode_mdio.o obj-$(CONFIG_OF_MDIO) += of_mdio.o +obj-$(CONFIG_MDIO_AN8855) += mdio-an8855.o obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c627136d9ed0..2682c7ba2b14 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -170,6 +170,11 @@ config AIROHA_EN8801SC_PHY help Currently supports the Airoha EN8801SC PHY. +config AIR_AN8855_PHY + tristate "Airoha AN8855 Internal Gigabit PHY" + help + Currently supports the internal Airoha AN8855 Switch PHY. + config AIR_EN8811H_PHY tristate "Airoha EN8811H 2.5 Gigabit PHY" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 845ee491e8d9..d75b8fab63eb 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -51,6 +51,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o +obj-$(CONFIG_AIR_AN8855_PHY) += air_an8855.o obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 51257aa2cd3e..9b998a92189a 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -29,6 +29,17 @@ source "drivers/nvmem/layouts/Kconfig" # Devices +config NVMEM_AN8855_EFUSE + tristate "Airoha AN8855 eFuse support" + depends on MFD_AIROHA_AN8855 || COMPILE_TEST + help + Say y here to enable support for reading eFuses on Airoha AN8855 + Switch. These are e.g. used to store factory programmed + calibration data required for the PHY. + + This driver can also be built as a module. If so, the module will + be called nvmem-an8855-efuse. + config NVMEM_APPLE_EFUSES tristate "Apple eFuse support" depends on ARCH_APPLE || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 68fcf845f417..6c6a49cb9890 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -10,6 +10,8 @@ nvmem_layouts-y := layouts.o obj-y += layouts/ # Devices +obj-$(CONFIG_NVMEM_AN8855_EFUSE) += nvmem-an8855-efuse.o +nvmem-an8855-efuse-y := an8855-efuse.o obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o nvmem-apple-efuses-y := apple-efuses.o obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o -- 2.51.0 From 744a0be88f4d250f79d3ae4beaba2a4bcab033c4 Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 7 Sep 2023 10:54:37 +0800 Subject: [PATCH 497/517] arm64: dts: mt7986: add afe --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 9a8d7db31261..49b5839eb7e9 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -202,6 +202,29 @@ pio: pinctrl@1001f000 { #interrupt-cells = <2>; }; + afe: audio-controller@11210000 { + compatible = "mediatek,mt7986-afe"; + reg = <0 0x11210000 0 0x9000>; + #sound-dai-cells = <0>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_AUD_BUS_CK>, + <&infracfg CLK_INFRA_AUD_26M_CK>, + <&infracfg CLK_INFRA_AUD_L_CK>, + <&infracfg CLK_INFRA_AUD_AUD_CK>, + <&infracfg CLK_INFRA_AUD_EG2_CK>; + clock-names = "aud_bus_ck", + "aud_26m_ck", + "aud_l_ck", + "aud_aud_ck", + "aud_eg2_ck"; + assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>, + <&topckgen CLK_TOP_AUD_L_SEL>, + <&topckgen CLK_TOP_A_TUNER_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>, + <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL2_D4>; + }; + pwm: pwm@10048000 { compatible = "mediatek,mt7986-pwm"; reg = <0 0x10048000 0 0x1000>; -- 2.51.0 From 9576cb9f4d5b90fdbae13c30eaca52d4e77dfb50 Mon Sep 17 00:00:00 2001 From: Maso Huang Date: Thu, 7 Sep 2023 10:54:37 +0800 Subject: [PATCH 498/517] arm64: dts: mt7986: add sound wm8960 --- .../dts/mediatek/mt7986a-rfb-spim-nand.dts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts index 479a5ca2fc4d..85ec95de405f 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts +++ b/arch/arm64/boot/dts/mediatek/mt7986a-rfb-spim-nand.dts @@ -4,6 +4,36 @@ / { compatible = "mediatek,mt7986a-rfb-snand"; + + sound_wm8960 { + compatible = "mediatek,mt7986-wm8960-sound"; + audio-routing = "Headphone", "HP_L", + "Headphone", "HP_R", + "LINPUT1", "AMIC", + "RINPUT1", "AMIC"; + + status = "okay"; + + platform { + sound-dai = <&afe>; + }; + + codec { + sound-dai = <&wm8960>; + }; + }; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + status = "okay"; + + wm8960: wm8960@1a { + compatible = "wlf,wm8960"; + #sound-dai-cells = <0>; + reg = <0x1a>; + }; }; &spi0 { @@ -50,3 +80,13 @@ partition@580000 { &wifi { mediatek,mtd-eeprom = <&factory 0>; }; + +&pio { + i2c_pins: i2c-pins-3-4 { + mux { + function = "i2c"; + groups = "i2c"; + }; + }; +}; + -- 2.51.0 From 865785365dda36ad89ca2a72db9304f5c9cd7b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:07 +0100 Subject: [PATCH 499/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/864-arm64-dts-mt7986-add-sound-overlay-for-bpi-r3.patch --- arch/arm64/boot/dts/mediatek/Makefile | 1 + ...7986a-bananapi-bpi-r3-respeaker-2mics.dtso | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index 82f7332077c4..7d4c852cb124 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -18,6 +18,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-emmc.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nand.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-nor.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-sd.dtbo +dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-bananapi-bpi-r3-respeaker-2mics.dtbo dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986a-rfb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7986b-rfb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt7988a-bananapi-bpi-r4.dtb diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso new file mode 100644 index 000000000000..e583875154a3 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3-respeaker-2mics.dtso @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Maso Huang + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r3", "mediatek,mt7986a"; + + fragment@0 { + target-path = "/"; + __overlay__ { + sound_wm8960 { + compatible = "mediatek,mt7986-wm8960-sound"; + audio-routing = "Headphone", "HP_L", + "Headphone", "HP_R", + "LINPUT1", "AMIC", + "RINPUT1", "AMIC"; + + status = "okay"; + + platform { + sound-dai = <&afe>; + }; + + codec { + sound-dai = <&wm8960>; + }; + }; + }; + }; + + fragment@1 { + target = <&i2c0>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + clock-frequency = <400000>; + status = "okay"; + + wm8960: wm8960@1a { + compatible = "wlf,wm8960"; + #sound-dai-cells = <0>; + reg = <0x1a>; + }; + }; + }; + + fragment@2 { + target = <&pio>; + __overlay__ { + i2c_pins: i2c-pins-3-4 { + mux { + function = "i2c"; + groups = "i2c"; + }; + }; + }; + }; +}; -- 2.51.0 From 58396f54f6a0640436a55866eb4ff7567d54ec08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:08 +0100 Subject: [PATCH 500/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/900-dts-mt7622-bpi-r64-aliases-for-dtoverlay.patch --- .../mt7622-bananapi-bpi-r64-pcie1.dtso | 17 ++++++++++ .../mt7622-bananapi-bpi-r64-sata.dtso | 31 +++++++++++++++++++ .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso create mode 100644 arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso new file mode 100644 index 000000000000..6be1ea2a8a13 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-pcie1.dtso @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ + +#include + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r64", "mediatek,mt7622"; + + fragment@0 { + target = <&asmsel>; + __overlay__ { + gpios = <90 GPIO_ACTIVE_HIGH>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso new file mode 100644 index 000000000000..160423348b4c --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64-sata.dtso @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ + +#include + +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r64", "mediatek,mt7622"; + + fragment@0 { + target = <&asmsel>; + __overlay__ { + gpios = <90 GPIO_ACTIVE_LOW>; + }; + }; + + fragment@1 { + target = <&sata>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@2 { + target = <&sata_phy>; + __overlay__ { + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 77ecf5086c2c..b8cc6b9516e5 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -323,7 +323,7 @@ &pio { /* Attention: GPIO 90 is used to switch between PCIe@1,0 and * SATA functions. i.e. output-high: PCIe, output-low: SATA */ - asm_sel { + asmsel: asm_sel { gpio-hog; gpios = <90 GPIO_ACTIVE_HIGH>; output-high; -- 2.51.0 From 98b9ffa72c8692d6441504a508fdbeaa83418ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:08 +0100 Subject: [PATCH 501/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/901-arm-add-cmdline-override.patch --- arch/arm/Kconfig | 8 ++++++++ arch/arm64/Kconfig | 8 ++++++++ drivers/of/fdt.c | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d5bf16462bdb..bb39e14b7486 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1505,6 +1505,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND endchoice +config CMDLINE_OVERRIDE + bool "Use alternative cmdline from device tree" + help + Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can + be used, this is not a good option for kernels that are shared across + devices. This setting enables using "chosen/cmdline-override" as the + cmdline if it exists in the device tree. + config CMDLINE string "Default kernel command string" default "" diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 40ae4dd961b1..788c05232708 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2381,6 +2381,14 @@ config CMDLINE_FORCE endchoice +config CMDLINE_OVERRIDE + bool "Use alternative cmdline from device tree" + help + Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can + be used, this is not a good option for kernels that are shared across + devices. This setting enables using "chosen/cmdline-override" as the + cmdline if it exists in the device tree. + config EFI_STUB bool diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 500807cccee4..1ca6cb71a908 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -1053,6 +1053,17 @@ int __init early_init_dt_scan_chosen(char *cmdline) if (p != NULL && l > 0) strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); + /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different + * device tree option of chosen/bootargs-override. This is + * helpful on boards where u-boot sets bootargs, and is unable + * to be modified. + */ +#ifdef CONFIG_CMDLINE_OVERRIDE + p = of_get_flat_dt_prop(node, "bootargs-override", &l); + if (p != NULL && l > 0) + strscpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE)); +#endif + handle_cmdline: /* * CONFIG_CMDLINE is meant to be a default in case nothing else -- 2.51.0 From 9aafa16a5e03d1d3488357d03c769324d01d9546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:08 +0100 Subject: [PATCH 502/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/910-dts-mt7622-bpi-r64-wifi-eeprom.patch --- .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index b8cc6b9516e5..456d260b5edf 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -650,5 +650,28 @@ &watchdog { }; &wmac { + mediatek,eeprom-data = <0x22760500 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x44000020 0x0 0x10002000 + 0x4400 0x4000000 0x0 0x0 + 0x200000b3 0x40b6c3c3 0x26000000 0x41c42600 + 0x41c4 0x26000000 0xc0c52600 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0xc6c6 + 0xc3c3c2c1 0xc300c3 0x818181 0x83c1c182 + 0x83838382 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x84002e00 0x90000087 0x8a000000 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0xb000009 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x7707>; + status = "okay"; }; -- 2.51.0 From c4409ad0cbfc4b8700cf01d1670473352839322c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:09 +0100 Subject: [PATCH 503/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/911-dts-mt7622-bpi-r64-add-rootdisk.patch --- .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 78 +++++++++++++++++-- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index 456d260b5edf..bec66209492f 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -32,6 +32,9 @@ aliases { chosen { stdout-path = "serial0:115200n8"; bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; + rootdisk-emmc = <&emmc_rootfs>; + rootdisk-sd = <&sd_rootfs>; + rootdisk-snfi = <&ubi_rootfs>; }; cpus { @@ -245,6 +248,28 @@ &mmc0 { assigned-clocks = <&topckgen CLK_TOP_MSDC30_0_SEL>; assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; non-removable; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + block { + compatible = "block-device"; + partitions { + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env"; + }; + }; + emmc_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; + }; }; &mmc1 { @@ -260,6 +285,28 @@ &mmc1 { vqmmc-supply = <®_3p3v>; assigned-clocks = <&topckgen CLK_TOP_MSDC30_1_SEL>; assigned-clock-parents = <&topckgen CLK_TOP_UNIV48M>; + #address-cells = <1>; + #size-cells = <0>; + + card@0 { + compatible = "mmc-card"; + reg = <0>; + + block { + compatible = "block-device"; + partitions { + block-partition-env { + partname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env"; + }; + }; + sd_rootfs: block-partition-production { + partname = "production"; + }; + }; + }; + }; }; &nandc { @@ -293,15 +340,30 @@ partition@0 { read-only; }; - partition@80000 { - label = "fip"; - reg = <0x80000 0x200000>; - read-only; - }; - - ubi: partition@280000 { + ubi: partition@80000 { label = "ubi"; - reg = <0x280000 0x7d80000>; + reg = <0x80000 0x7f80000>; + compatible = "linux,ubi"; + + volumes { + ubi-volume-ubootenv { + volname = "ubootenv"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + ubi-volume-ubootenv2 { + volname = "ubootenv2"; + nvmem-layout { + compatible = "u-boot,env-redundant-bool"; + }; + }; + + ubi_rootfs: ubi-volume-fit { + volname = "fit"; + }; + }; }; }; }; -- 2.51.0 From 0f6cc451cecc15b12cf113f5046e9985bc23f7a7 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 9 May 2025 02:38:51 +0100 Subject: [PATCH 504/517] block: partitions: msdos: add OF node by partition number A hack for some legacy boards... Signed-off-by: Daniel Golle --- block/partitions/msdos.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 073be78ba0b0..857893fa5c39 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -27,6 +27,7 @@ */ #include #include +#include #include "check.h" #include "efi.h" @@ -116,6 +117,26 @@ static void set_info(struct parsed_partitions *state, int slot, state->parts[slot].has_info = true; } +static struct device_node *find_partno_of_node(struct device_node *partitions_np, + int partno) +{ + int np_partno; + + if (!partitions_np || + !of_device_is_compatible(partitions_np, "msdos-partitions")) + return NULL; + + for_each_available_child_of_node_scoped(partitions_np, np) { + if (!of_property_read_u32(np, "partno", &np_partno) && + partno != np_partno) + continue; + + return np; + } + + return NULL; +} + /* * Create devices for each logical partition in an extended partition. * The logical partitions form a linked list, with each entry being @@ -131,6 +152,8 @@ static void parse_extended(struct parsed_partitions *state, sector_t first_sector, sector_t first_size, u32 disksig) { + struct device *ddev = disk_to_dev(state->disk); + struct device_node *partitions_np = of_node_get(ddev->of_node); struct msdos_partition *p; Sector sect; unsigned char *data; @@ -190,7 +213,8 @@ static void parse_extended(struct parsed_partitions *state, continue; } - put_partition(state, state->next, next, size); + of_put_partition(state, state->next, next, size, + find_partno_of_node(partitions_np, state->next)); set_info(state, state->next, disksig); if (p->sys_ind == LINUX_RAID_PARTITION) state->parts[state->next].flags = ADDPART_FLAG_RAID; @@ -580,6 +604,8 @@ static struct { int msdos_partition(struct parsed_partitions *state) { + struct device *ddev = disk_to_dev(state->disk); + struct device_node *partitions_np = of_node_get(ddev->of_node); sector_t sector_size; Sector sect; unsigned char *data; @@ -676,14 +702,18 @@ int msdos_partition(struct parsed_partitions *state) sector_t n = 2; n = min(size, max(sector_size, n)); - put_partition(state, slot, start, n); + of_put_partition(state, slot, start, n, + find_partno_of_node(partitions_np, + slot)); strlcat(state->pp_buf, " <", PAGE_SIZE); parse_extended(state, start, size, disksig); strlcat(state->pp_buf, " >", PAGE_SIZE); continue; } - put_partition(state, slot, start, size); + of_put_partition(state, slot, start, size, + find_partno_of_node(partitions_np, + slot)); set_info(state, slot, disksig); if (p->sys_ind == LINUX_RAID_PARTITION) state->parts[slot].flags = ADDPART_FLAG_RAID; -- 2.51.0 From cad132ca9e315f20dca290a1b8f5b7c71e5796be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:10 +0100 Subject: [PATCH 505/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/930-spi-mt65xx-enable-sel-clk.patch --- drivers/spi/spi-mt65xx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 906e188987c8..4aed51720298 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1237,8 +1237,15 @@ static int mtk_spi_probe(struct platform_device *pdev) if (ret < 0) return dev_err_probe(dev, ret, "failed to enable hclk\n"); + ret = clk_prepare_enable(mdata->sel_clk); + if (ret < 0) { + clk_disable_unprepare(mdata->spi_hclk); + return dev_err_probe(dev, ret, "failed to enable sel_clk\n"); + } + ret = clk_prepare_enable(mdata->spi_clk); if (ret < 0) { + clk_disable_unprepare(mdata->sel_clk); clk_disable_unprepare(mdata->spi_hclk); return dev_err_probe(dev, ret, "failed to enable spi_clk\n"); } -- 2.51.0 From 23e8f05982b92a225fe2f9dc1475feefd6aedd52 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 12 Mar 2023 16:40:31 +0100 Subject: [PATCH 506/517] net: ethernet: mtk_wed: rename mtk_wed_get_memory_region in mtk_wed_get_reserved_memory_region This is a preliminary patch to move wed ilm/dlm and cpuboot properties in dedicated dts nodes. Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c index c06e5ad18b01..ed97ca29b4e5 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c @@ -234,8 +234,8 @@ int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, } static int -mtk_wed_get_memory_region(struct mtk_wed_hw *hw, int index, - struct mtk_wed_wo_memory_region *region) +mtk_wed_get_reserved_memory_region(struct mtk_wed_hw *hw, int index, + struct mtk_wed_wo_memory_region *region) { struct reserved_mem *rmem; struct device_node *np; @@ -325,7 +325,7 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) if (index < 0) continue; - ret = mtk_wed_get_memory_region(wo->hw, index, &mem_region[i]); + ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]); if (ret) return ret; } -- 2.51.0 From e8e2af046559ce38fcdb522f4cc1337ea0932a70 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 11 Mar 2023 16:32:41 +0100 Subject: [PATCH 507/517] arm64: dts: mt7986: move cpuboot in a dedicated node Signed-off-by: Lorenzo Bianconi --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 49b5839eb7e9..d7908645dbf8 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -121,12 +121,6 @@ wo_dlm1: wo-dlm@151f8000 { reg = <0 0x151f8000 0 0x2000>; no-map; }; - - wo_boot: wo-boot@15194000 { - reg = <0 0x15194000 0 0x1000>; - no-map; - }; - }; soc { @@ -533,10 +527,11 @@ wed0: wed@15010000 { interrupt-parent = <&gic>; interrupts = ; memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, - <&wo_data>, <&wo_boot>; + <&wo_data>; memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", - "wo-data", "wo-boot"; + "wo-data"; mediatek,wo-ccif = <&wo_ccif0>; + mediatek,wo-cpuboot = <&wo_cpuboot>; }; wed1: wed@15011000 { @@ -546,10 +541,11 @@ wed1: wed@15011000 { interrupt-parent = <&gic>; interrupts = ; memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>, - <&wo_data>, <&wo_boot>; + <&wo_data>; memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", - "wo-data", "wo-boot"; + "wo-data"; mediatek,wo-ccif = <&wo_ccif1>; + mediatek,wo-cpuboot = <&wo_cpuboot>; }; eth: ethernet@15100000 { @@ -607,6 +603,11 @@ wo_ccif1: syscon@151ad000 { interrupts = ; }; + wo_cpuboot: syscon@15194000 { + compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; + reg = <0 0x15194000 0 0x1000>; + }; + wifi: wifi@18000000 { compatible = "mediatek,mt7986-wmac"; reg = <0 0x18000000 0 0x1000000>, -- 2.51.0 From 4a24e54ea7cff129f0ad3a539c091b92228885d4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 11 Mar 2023 18:13:04 +0100 Subject: [PATCH 508/517] net: ethernet: mtk_wed: move cpuboot in a dedicated dts node Since the cpuboot memory region is not part of the RAM SoC, move cpuboot in a deidicated syscon node. This patch helps to keep backward-compatibility with older version of uboot codebase where we have a limit of 8 reserved-memory dts child nodes. Keep backward-compatibility with older dts version where cpuboot was defined as reserved-memory child node. Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 33 ++++++++++++++++----- drivers/net/ethernet/mediatek/mtk_wed_wo.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c index ed97ca29b4e5..87f8d0def161 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c @@ -32,14 +32,25 @@ static struct mtk_wed_wo_memory_region mem_region[] = { }, }; -static u32 wo_r32(u32 reg) +static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg) { - return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); + u32 val; + + if (!wo->boot_regmap) + return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); + + if (regmap_read(wo->boot_regmap, reg, &val)) + val = ~0; + + return val; } -static void wo_w32(u32 reg, u32 val) +static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val) { - writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); + if (wo->boot_regmap) + regmap_write(wo->boot_regmap, reg, val); + else + writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg); } static struct sk_buff * @@ -317,6 +328,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) u32 val, boot_cr; int ret, i; + wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node, + "mediatek,wo-cpuboot"); + /* load firmware region metadata */ for (i = 0; i < ARRAY_SIZE(mem_region); i++) { int index = of_property_match_string(wo->hw->node, @@ -325,6 +339,9 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) if (index < 0) continue; + if (index == MTK_WED_WO_REGION_BOOT && !IS_ERR(wo->boot_regmap)) + continue; + ret = mtk_wed_get_reserved_memory_region(wo->hw, index, &mem_region[i]); if (ret) return ret; @@ -373,13 +390,13 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR; else boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR; - wo_w32(boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16); + wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16); /* wo firmware reset */ - wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); + wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); - val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) | + val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) | MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK; - wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); + wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); out: release_firmware(fw); diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h index c01b1e8428f6..1b06f79662e3 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h +++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h @@ -231,6 +231,7 @@ struct mtk_wed_wo_queue { struct mtk_wed_wo { struct mtk_wed_hw *hw; + struct regmap *boot_regmap; struct mtk_wed_wo_queue q_tx; struct mtk_wed_wo_queue q_rx; -- 2.51.0 From d66901ae6cee48a1b0735d43f780d2b1372a734f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 12 Mar 2023 18:51:47 +0100 Subject: [PATCH 509/517] net: ethernet: mtk_wed: move ilm a dedicated dts node Since the ilm memory region is not part of the RAM SoC, move ilm in a deidicated syscon node. This patch helps to keep backward-compatibility with older version of uboot codebase where we have a limit of 8 reserved-memory dts child nodes. Keep backward-compatibility with older dts version where ilm was defined as reserved-memory child node. Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 45 +++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c index 87f8d0def161..81f77492e1ef 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c @@ -319,6 +319,39 @@ mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw) return 0; } +static int +mtk_wed_mcu_load_ilm(struct mtk_wed_wo *wo) +{ + struct mtk_wed_wo_memory_region *ilm_region; + struct resource res; + struct device_node *np; + int ret; + + np = of_parse_phandle(wo->hw->node, "mediatek,wo-ilm", 0); + if (!np) + return 0; + + ret = of_address_to_resource(np, 0, &res); + of_node_put(np); + + if (ret < 0) + return ret; + + ilm_region = &mem_region[MTK_WED_WO_REGION_ILM]; + ilm_region->phy_addr = res.start; + ilm_region->size = resource_size(&res); + ilm_region->addr = devm_ioremap(wo->hw->dev, res.start, + resource_size(&res)); + + if (!IS_ERR(ilm_region->addr)) + return 0; + + ret = PTR_ERR(ilm_region->addr); + ilm_region->addr = NULL; + + return ret; +} + static int mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) { @@ -328,14 +361,20 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) u32 val, boot_cr; int ret, i; + mtk_wed_mcu_load_ilm(wo); wo->boot_regmap = syscon_regmap_lookup_by_phandle(wo->hw->node, "mediatek,wo-cpuboot"); /* load firmware region metadata */ for (i = 0; i < ARRAY_SIZE(mem_region); i++) { - int index = of_property_match_string(wo->hw->node, - "memory-region-names", - mem_region[i].name); + int index; + + if (mem_region[i].addr) + continue; + + index = of_property_match_string(wo->hw->node, + "memory-region-names", + mem_region[i].name); if (index < 0) continue; -- 2.51.0 From 660d36d99016c57f240fd84219aed006f716de11 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Mar 2023 15:45:16 +0100 Subject: [PATCH 510/517] net: ethernet: mtk_wed: move dlm a dedicated dts node Since the dlm memory region is not part of the RAM SoC, move dlm in a deidicated syscon node. This patch helps to keep backward-compatibility with older version of uboot codebase where we have a limit of 8 reserved-memory dts child nodes. Keep backward-compatibility with older dts version where dlm was defined as reserved-memory child node. Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/mediatek/mtk_wed.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index 1e369a059edd..3c22aaefa267 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -1333,6 +1333,24 @@ mtk_wed_rro_alloc(struct mtk_wed_device *dev) struct device_node *np; int index; + np = of_parse_phandle(dev->hw->node, "mediatek,wo-dlm", 0); + if (np) { + struct resource res; + int ret; + + ret = of_address_to_resource(np, 0, &res); + of_node_put(np); + + if (ret < 0) + return ret; + + dev->rro.miod_phys = res.start; + goto out; + } + + /* For backward compatibility, we need to check if DLM + * node is defined through reserved memory property. + */ index = of_property_match_string(dev->hw->node, "memory-region-names", "wo-dlm"); if (index < 0) @@ -1349,6 +1367,7 @@ mtk_wed_rro_alloc(struct mtk_wed_device *dev) return -ENODEV; dev->rro.miod_phys = rmem->base; +out: dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys; return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring, -- 2.51.0 From ddab7743c6cc805854cde7032aa185f501007ae3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Mar 2023 15:10:56 +0100 Subject: [PATCH 511/517] arm64: dts: mt7986: move ilm in a dedicated node Since the ilm memory region is not part of the RAM SoC, move ilm in a deidicated syscon node. This patch helps to keep backward-compatibility with older version of uboot codebase where we have a limit of 8 reserved-memory dts child nodes. Signed-off-by: Lorenzo Bianconi --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 34 +++++++++++------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index d7908645dbf8..60e12fba069c 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -97,16 +97,6 @@ wo_emi1: wo-emi@4fd40000 { no-map; }; - wo_ilm0: wo-ilm@151e0000 { - reg = <0 0x151e0000 0 0x8000>; - no-map; - }; - - wo_ilm1: wo-ilm@151f0000 { - reg = <0 0x151f0000 0 0x8000>; - no-map; - }; - wo_data: wo-data@4fd80000 { reg = <0 0x4fd80000 0 0x240000>; no-map; @@ -526,11 +516,10 @@ wed0: wed@15010000 { reg = <0 0x15010000 0 0x1000>; interrupt-parent = <&gic>; interrupts = ; - memory-region = <&wo_emi0>, <&wo_ilm0>, <&wo_dlm0>, - <&wo_data>; - memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", - "wo-data"; + memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>; + memory-region-names = "wo-emi", "wo-dlm", "wo-data"; mediatek,wo-ccif = <&wo_ccif0>; + mediatek,wo-ilm = <&wo_ilm0>; mediatek,wo-cpuboot = <&wo_cpuboot>; }; @@ -540,11 +529,10 @@ wed1: wed@15011000 { reg = <0 0x15011000 0 0x1000>; interrupt-parent = <&gic>; interrupts = ; - memory-region = <&wo_emi1>, <&wo_ilm1>, <&wo_dlm1>, - <&wo_data>; - memory-region-names = "wo-emi", "wo-ilm", "wo-dlm", - "wo-data"; + memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>; + memory-region-names = "wo-emi", "wo-dlm", "wo-data"; mediatek,wo-ccif = <&wo_ccif1>; + mediatek,wo-ilm = <&wo_ilm1>; mediatek,wo-cpuboot = <&wo_cpuboot>; }; @@ -603,6 +591,16 @@ wo_ccif1: syscon@151ad000 { interrupts = ; }; + wo_ilm0: syscon@151e0000 { + compatible = "mediatek,mt7986-wo-ilm", "syscon"; + reg = <0 0x151e0000 0 0x8000>; + }; + + wo_ilm1: syscon@151f0000 { + compatible = "mediatek,mt7986-wo-ilm", "syscon"; + reg = <0 0x151f0000 0 0x8000>; + }; + wo_cpuboot: syscon@15194000 { compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; reg = <0 0x15194000 0 0x1000>; -- 2.51.0 From f8607a0f13c5a3138a6a6c20d8954f0abeb98cc5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Mar 2023 15:53:30 +0100 Subject: [PATCH 512/517] arm64: dts: mt7986: move dlm in a dedicated node Since the dlm memory region is not part of the RAM SoC, move dlm in a deidicated syscon node. This patch helps to keep backward-compatibility with older version of uboot codebase where we have a limit of 8 reserved-memory dts child nodes. Signed-off-by: Lorenzo Bianconi --- arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 30 ++++++++++++----------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi index 60e12fba069c..f8a99686e374 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi @@ -101,16 +101,6 @@ wo_data: wo-data@4fd80000 { reg = <0 0x4fd80000 0 0x240000>; no-map; }; - - wo_dlm0: wo-dlm@151e8000 { - reg = <0 0x151e8000 0 0x2000>; - no-map; - }; - - wo_dlm1: wo-dlm@151f8000 { - reg = <0 0x151f8000 0 0x2000>; - no-map; - }; }; soc { @@ -516,10 +506,11 @@ wed0: wed@15010000 { reg = <0 0x15010000 0 0x1000>; interrupt-parent = <&gic>; interrupts = ; - memory-region = <&wo_emi0>, <&wo_dlm0>, <&wo_data>; - memory-region-names = "wo-emi", "wo-dlm", "wo-data"; + memory-region = <&wo_emi0>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; mediatek,wo-ccif = <&wo_ccif0>; mediatek,wo-ilm = <&wo_ilm0>; + mediatek,wo-dlm = <&wo_dlm0>; mediatek,wo-cpuboot = <&wo_cpuboot>; }; @@ -529,10 +520,11 @@ wed1: wed@15011000 { reg = <0 0x15011000 0 0x1000>; interrupt-parent = <&gic>; interrupts = ; - memory-region = <&wo_emi1>, <&wo_dlm1>, <&wo_data>; - memory-region-names = "wo-emi", "wo-dlm", "wo-data"; + memory-region = <&wo_emi1>, <&wo_data>; + memory-region-names = "wo-emi", "wo-data"; mediatek,wo-ccif = <&wo_ccif1>; mediatek,wo-ilm = <&wo_ilm1>; + mediatek,wo-dlm = <&wo_dlm1>; mediatek,wo-cpuboot = <&wo_cpuboot>; }; @@ -601,6 +593,16 @@ wo_ilm1: syscon@151f0000 { reg = <0 0x151f0000 0 0x8000>; }; + wo_dlm0: syscon@151e8000 { + compatible = "mediatek,mt7986-wo-dlm", "syscon"; + reg = <0 0x151e8000 0 0x2000>; + }; + + wo_dlm1: syscon@151f8000 { + compatible = "mediatek,mt7986-wo-dlm", "syscon"; + reg = <0 0x151f8000 0 0x2000>; + }; + wo_cpuboot: syscon@15194000 { compatible = "mediatek,mt7986-wo-cpuboot", "syscon"; reg = <0 0x15194000 0 0x1000>; -- 2.51.0 From 74446121fe51ebdad4b00400a1b92340f0a61fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:12 +0100 Subject: [PATCH 513/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/950-smartrg-i2c-led-driver.patch --- drivers/leds/Kconfig | 10 ++++++++++ drivers/leds/Makefile | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c275963c498c..7dd68878d84b 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -977,6 +977,16 @@ source "drivers/leds/flash/Kconfig" comment "RGB LED drivers" source "drivers/leds/rgb/Kconfig" +config LEDS_SMARTRG_LED + tristate "LED support for Adtran SmartRG" + depends on LEDS_CLASS && I2C && OF + help + This option enables support for the Adtran SmartRG platform + system LED driver. + + To compile this driver as a module, choose M here: the module + will be called leds-smartrg-system. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 32241451b805..1eabbf823afe 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o obj-$(CONFIG_LEDS_PWM) += leds-pwm.o obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o +obj-$(CONFIG_LEDS_SMARTRG_LED) += leds-smartrg-system.o obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o -- 2.51.0 From ce803bc11bfcaf5bb6c01c942ecd8a1d3549164c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:12 +0100 Subject: [PATCH 514/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/955-dts-mt7968a-bpi-r3-add-label-to-gmac-for-sfp1-port.patch --- arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts index 5e0c2941928d..db8928987342 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts @@ -195,6 +195,7 @@ gmac1: mac@1 { phy-mode = "2500base-x"; sfp = <&sfp1>; managed = "in-band-status"; + openwrt,netdev-name = "sfp1"; }; mdio: mdio-bus { -- 2.51.0 From 4df705cab8dd3bb7be1c5f456cda96d665847a47 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 6 Feb 2025 05:07:20 +0000 Subject: [PATCH 515/517] mtd: spinand: add work-around to prevent bootloader wiping mtdparts ASUS makes use of U-Boot's fdt_fixup_mtdparts() function which applies the partitions defined in U-Boot's mtdparts and mtdids environment variables to the devicetree passed over to Linux. The undesired side-effect is that in this way also all additional properties and child nodes get wiped, preventing NVMEM cells to be defined for MTD partitions or UBI volumes. To work-around this issue, add an additional compatible string 'u-boot-dont-touch-spi-nand' which can be used instead of 'spi-nand' in case the replacement of the MTD partitions by U-Boot should be skipped alltogether. In practise this is mostly relevant for SPI-NAND which anyway comes only with two partitions nowadays: 'Bootloader' and 'UBI_DEV'. Hence this work-around is applicable for SPI-NAND only. Similar work-arounds for other MTD devices can be created as well should they actually be needed. Signed-off-by: Daniel Golle --- drivers/mtd/nand/spi/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index a74bda5c4965..1dcffc2bbd18 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1668,6 +1668,7 @@ static int spinand_remove(struct spi_mem *mem) static const struct spi_device_id spinand_ids[] = { { .name = "spi-nand" }, + { .name = "u-boot-dont-touch-spi-nand" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(spi, spinand_ids); @@ -1675,6 +1676,7 @@ MODULE_DEVICE_TABLE(spi, spinand_ids); #ifdef CONFIG_OF static const struct of_device_id spinand_of_ids[] = { { .compatible = "spi-nand" }, + { .compatible = "u-boot-dont-touch-spi-nand" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, spinand_of_ids); -- 2.51.0 From 3c06beabf11952531131a8c93d4a7e11267b2b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Mon, 3 Nov 2025 15:51:13 +0100 Subject: [PATCH 516/517] /home/cynerd/turris/upstream/openwrt/target/linux/mediatek/patches-6.12/965-dts-mt7988a-add-trng-support.patch --- arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index 5717729f563c..d907769259ca 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -1319,4 +1319,8 @@ timer { , ; }; + + trng { + compatible = "mediatek,mt7988-rng"; + }; }; -- 2.51.0 From 1e87e9227c60dd7f73de3aec9882ffd5423113ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Thu, 2 Oct 2025 11:54:23 +0200 Subject: [PATCH 517/517] Pull OpenWrt One device tree from OpenWrt master The commit used: 915a57ccd9086db88ee74cfa531ff13f8652a447 --- .../boot/dts/mediatek/mt7981b-openwrt-one.dts | 460 +++++++++++++++++- 1 file changed, 457 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts index 4f6cbb491287..5f54506b2cba 100644 --- a/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts +++ b/arch/arm64/boot/dts/mediatek/mt7981b-openwrt-one.dts @@ -1,15 +1,469 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT +// SPDX-License-Identifier: (GPL-2.0 OR MIT) /dts-v1/; - #include "mt7981b.dtsi" / { - compatible = "openwrt,one", "mediatek,mt7981b"; model = "OpenWrt One"; + compatible = "openwrt,one", "mediatek,mt7981"; + + aliases { + ethernet0 = &gmac1; + label-mac-device = &gmac0; + led-boot = &led_status_white; + led-failsafe = &led_status_red; + led-running = &led_status_green; + led-upgrade = &led_status_green; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + rootdisk = <&ubi_fit_volume>; + }; memory@40000000 { reg = <0 0x40000000 0 0x40000000>; device_type = "memory"; }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; + + gpio-keys { + compatible = "gpio-keys"; + + user { + label = "user"; + linux,code = ; + gpios = <&pio 0 GPIO_ACTIVE_LOW>; + }; + + reset { + label = "reset"; + linux,code = ; + gpios = <&pio 1 GPIO_ACTIVE_LOW>; + }; + }; + + pwm-leds { + compatible = "pwm-leds"; + + led_status_white: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + pwms = <&pwm 0 10000>; + linux,default-trigger = "pattern"; + led-pattern = <0 500 25 500>; + }; + + led_status_green: led-1 { + color = ; + function = LED_FUNCTION_STATUS; + pwms = <&pwm 1 10000>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led_status_red: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&pio 9 GPIO_ACTIVE_HIGH>; + }; + + led-1 { + function = LED_FUNCTION_LAN; + color = ; + gpios = <&pio 34 GPIO_ACTIVE_LOW>; + }; + + led-2 { + function = LED_FUNCTION_LAN; + color = ; + gpios = <&pio 35 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-export { + compatible = "gpio-export"; + + gpio-0 { + gpio-export,name = "mikrobus-reset"; + gpio-export,output = <1>; + gpios = <&pio 2 GPIO_ACTIVE_HIGH>; + }; + + gpio-1 { + gpio-export,name = "watchdog-enable"; + gpio-export,output = <1>; + gpios = <&pio 11 GPIO_ACTIVE_HIGH>; + }; + + gpio-2 { + gpio-export,name = "usb-enable"; + gpio-export,output = <1>; + gpios = <&pio 14 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio-watchdog { + compatible = "linux,wdt-gpio"; + gpios = <&pio 8 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + hw_margin_ms = <25000>; + always-running; + }; +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-handle = <&phy15>; + phy-mode = "2500base-x"; + nvmem-cell-names = "mac-address"; + nvmem-cells = <&macaddr_factory_24>; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "gmii"; + phy-handle = <&int_gbe_phy>; + }; +}; + +&mdio_bus { + phy15: phy@f { + reg = <0xf>; + + airoha,pnswap-rx; + + interrupt-parent = <&pio>; + interrupts = <38 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&pio 39 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + reset-deassert-us = <20000>; + + phy-mode = "2500base-x"; + full-duplex; + pause; + + leds { + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + function = LED_FUNCTION_WAN; + color = ; + }; + + led@1 { + reg = <1>; + function = LED_FUNCTION_WAN; + color = ; + }; + }; + }; +}; + +&crypto { + status = "okay"; +}; + +&pio { + spi0_flash_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + + conf-pu { + pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP"; + drive-strength = ; + bias-pull-up = ; + }; + + conf-pd { + pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO"; + drive-strength = ; + bias-pull-down = ; + }; + }; + + spi1_flash_pins: spi1-pins { + mux { + function = "spi"; + groups = "spi1_1"; + }; + + conf-pu { + pins = "SPI1_CS"; + drive-strength = ; + bias-pull-up = ; + }; + + conf-pd { + pins = "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO"; + drive-strength = ; + bias-pull-down = ; + }; + }; + + spi2_flash_pins: spi2-pins { + mux { + function = "spi"; + groups = "spi2"; + }; + + conf-pu { + pins = "SPI2_CS", "SPI2_WP"; + drive-strength = ; + bias-pull-up = ; + }; + + conf-pd { + pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; + drive-strength = ; + bias-pull-down = ; + }; + }; + + i2c_pins: i2c-pins { + mux { + function = "i2c"; + groups = "i2c0_0"; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2_0_tx_rx"; + }; + }; + + pwm_pins: pwm-pins { + mux { + function = "pwm"; + groups = "pwm0_0", "pwm1_1"; + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_pereset"; + }; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_pins>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + status = "okay"; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + cs-gpios = <0>, <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <52000000>; + + spi-cal-enable; + spi-cal-mode = "read-data"; + spi-cal-datalen = <7>; + spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>; + spi-cal-addrlen = <5>; + spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl2"; + reg = <0x0 0x100000>; + read-only; + }; + + partition@580000 { + label = "ubi"; + reg = <0x100000 0xFF00000>; + compatible = "linux,ubi"; + + volumes { + ubi_fit_volume: ubi-volume-fit { + volname = "fit"; + }; + }; + }; + }; + }; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_flash_pins>; + status = "okay"; +}; + +&spi2 { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_flash_pins>; + status = "okay"; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + + spi-max-frequency = <52000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl2-nor"; + reg = <0x00000 0x40000>; + }; + + partition@40000 { + label = "factory"; + reg = <0x40000 0xc0000>; + read-only; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + eeprom_factory_0: eeprom@0 { + reg = <0x0 0x1000>; + }; + + macaddr_factory_4: macaddr@4 { + reg = <0x4 0x6>; + compatible = "mac-base"; + #nvmem-cell-cells = <1>; + }; + + macaddr_factory_24: macaddr@24 { + reg = <0x24 0x6>; + compatible = "mac-base"; + }; + }; + }; + + partition@100000 { + label = "fip-nor"; + reg = <0x100000 0x80000>; + }; + + partition@180000 { + label = "recovery"; + reg = <0x180000 0xc80000>; + }; + }; + }; +}; + +&xhci { + phys = <&u2port0 PHY_TYPE_USB2>; + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + mediatek,u3p-dis-msk = <0x01>; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&wifi { + #address-cells = <1>; + #size-cells = <0>; + nvmem-cells = <&eeprom_factory_0>; + nvmem-cell-names = "eeprom"; + status = "okay"; + + band@0 { + reg = <0>; + nvmem-cells = <&macaddr_factory_4 0>; + nvmem-cell-names = "mac-address"; + }; + + band@1 { + reg = <1>; + nvmem-cells = <&macaddr_factory_4 7>; + nvmem-cell-names = "mac-address"; + }; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; + status = "okay"; +}; + +&sgmiisys0 { + /delete-node/ mediatek,pnswap; }; -- 2.51.0