| /* |
| * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. |
| * 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. |
| */ |
| /*qca808x_start*/ |
| #include "sw.h" |
| #include "ssdk_init.h" |
| #include "fal_init.h" |
| #include "fal.h" |
| #include "hsl.h" |
| #include "hsl_dev.h" |
| #include "ssdk_init.h" |
| /*qca808x_end*/ |
| #include "ssdk_dts.h" |
| #if (defined(HPPE) || defined(MP)) |
| #include "hppe_init.h" |
| #endif |
| #include <linux/kconfig.h> |
| /*qca808x_start*/ |
| #include <linux/version.h> |
| /*qca808x_end*/ |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/phy.h> |
| #include <linux/platform_device.h> |
| #include <linux/types.h> |
| //#include <asm/mach-types.h> |
| #include <generated/autoconf.h> |
| #include <linux/if_arp.h> |
| #include <linux/inetdevice.h> |
| #include <linux/netdevice.h> |
| #include <linux/phy.h> |
| #include <linux/clk.h> |
| #include <linux/delay.h> |
| #include <linux/string.h> |
| |
| #if defined(ISIS) ||defined(ISISC) ||defined(GARUDA) |
| #include <f1_phy.h> |
| #endif |
| #if defined(ATHENA) ||defined(SHIVA) ||defined(HORUS) |
| #include <f2_phy.h> |
| #endif |
| #ifdef IN_MALIBU_PHY |
| #include <malibu_phy.h> |
| #endif |
| /*qca808x_start*/ |
| #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)) |
| #include <linux/of.h> |
| #include <linux/of_mdio.h> |
| #include <linux/of_platform.h> |
| #elif defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) |
| #include <linux/of.h> |
| #include <linux/of_mdio.h> |
| #include <drivers/leds/leds-ipq40xx.h> |
| #include <linux/of_platform.h> |
| #include <linux/reset.h> |
| #else |
| #include <linux/ar8216_platform.h> |
| #include <drivers/net/phy/ar8216.h> |
| #include <drivers/net/ethernet/atheros/ag71xx/ag71xx.h> |
| #endif |
| #include "ssdk_plat.h" |
| /*qca808x_end*/ |
| #include "ssdk_clk.h" |
| #include "ref_vlan.h" |
| #include "ref_fdb.h" |
| #include "ref_mib.h" |
| #include "ref_port_ctrl.h" |
| #include "ref_misc.h" |
| #include "ref_uci.h" |
| #include "shell.h" |
| #ifdef BOARD_AR71XX |
| #include "ssdk_uci.h" |
| #endif |
| |
| #include "hsl_phy.h" |
| #ifdef IN_LINUX_STD_PTP |
| #include "qca808x_ptp.h" |
| #endif |
| |
| #ifdef IN_IP |
| #if defined (CONFIG_NF_FLOW_COOKIE) |
| #include "fal_flowcookie.h" |
| #ifdef IN_SFE |
| #include <shortcut-fe/sfe.h> |
| #endif |
| #endif |
| #endif |
| |
| #ifdef IN_RFS |
| #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
| #include <linux/if_vlan.h> |
| #endif |
| #include <qca-rfs/rfs_dev.h> |
| #ifdef IN_IP |
| #include "fal_rfs.h" |
| #endif |
| #endif |
| |
| #include "adpt.h" |
| /*qca808x_start*/ |
| |
| extern struct qca_phy_priv **qca_phy_priv_global; |
| extern ssdk_chip_type SSDK_CURRENT_CHIP_TYPE; |
| /*qca808x_end*/ |
| struct mutex switch_mdio_lock; |
| |
| #ifdef BOARD_IPQ806X |
| #define PLATFORM_MDIO_BUS_NAME "mdio-gpio" |
| #endif |
| |
| #ifdef BOARD_AR71XX |
| #define PLATFORM_MDIO_BUS_NAME "ag71xx-mdio" |
| #endif |
| /*qca808x_start*/ |
| #define MDIO_BUS_0 0 |
| #define MDIO_BUS_1 1 |
| /*qca808x_end*/ |
| #define PLATFORM_MDIO_BUS_NUM MDIO_BUS_0 |
| |
| #define ISIS_CHIP_ID 0x18 |
| #define ISIS_CHIP_REG 0 |
| #define SHIVA_CHIP_ID 0x1f |
| #define SHIVA_CHIP_REG 0x10 |
| #define HIGH_ADDR_DFLT 0x200 |
| |
| /* |
| * Using ISIS's address as default |
| */ |
| static int switch_chip_id = ISIS_CHIP_ID; |
| static int switch_chip_reg = ISIS_CHIP_REG; |
| |
| static int ssdk_dev_id = 0; |
| /*qca808x_start*/ |
| a_uint32_t ssdk_log_level = SSDK_LOG_LEVEL_DEFAULT; |
| /*qca808x_end*/ |
| |
| #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) |
| struct ag71xx_mdio { |
| struct mii_bus *mii_bus; |
| int mii_irq[PHY_MAX_ADDR]; |
| void __iomem *mdio_base; |
| }; |
| #endif |
| |
| #ifdef BOARD_AR71XX |
| static uint32_t switch_chip_id_adjuest(a_uint32_t dev_id) |
| { |
| uint32_t chip_version = 0; |
| chip_version = (qca_ar8216_mii_read(dev_id, 0)&0xff00)>>8; |
| if((chip_version !=0) && (chip_version !=0xff)) |
| return 0; |
| |
| switch_chip_id = SHIVA_CHIP_ID; |
| switch_chip_reg = SHIVA_CHIP_REG; |
| |
| chip_version = (qca_ar8216_mii_read(dev_id, 0)&0xff00)>>8; |
| printk("chip_version:0x%x\n", chip_version); |
| return 1; |
| } |
| #endif |
| |
| static inline void |
| split_addr(uint32_t regaddr, uint16_t *r1, uint16_t *r2, uint16_t *page) |
| { |
| regaddr >>= 1; |
| *r1 = regaddr & 0x1e; |
| |
| regaddr >>= 5; |
| *r2 = regaddr & 0x7; |
| |
| regaddr >>= 3; |
| *page = regaddr & 0x3ff; |
| } |
| |
| a_uint32_t |
| qca_ar8216_mii_read(a_uint32_t dev_id, a_uint32_t reg) |
| { |
| struct mii_bus *bus; |
| uint16_t r1, r2, page; |
| uint16_t lo, hi; |
| |
| bus = qca_phy_priv_global[dev_id]->miibus; |
| |
| split_addr((uint32_t) reg, &r1, &r2, &page); |
| mutex_lock(&switch_mdio_lock); |
| mdiobus_write(bus, switch_chip_id, switch_chip_reg, page); |
| udelay(100); |
| lo = mdiobus_read(bus, 0x10 | r2, r1); |
| hi = mdiobus_read(bus, 0x10 | r2, r1 + 1); |
| mdiobus_write(bus, switch_chip_id, switch_chip_reg, HIGH_ADDR_DFLT); |
| mutex_unlock(&switch_mdio_lock); |
| return (hi << 16) | lo; |
| } |
| |
| void |
| qca_ar8216_mii_write(a_uint32_t dev_id, a_uint32_t reg, a_uint32_t val) |
| { |
| struct mii_bus *bus; |
| uint16_t r1, r2, r3; |
| uint16_t lo, hi; |
| |
| bus = qca_phy_priv_global[dev_id]->miibus; |
| |
| split_addr((a_uint32_t) reg, &r1, &r2, &r3); |
| lo = val & 0xffff; |
| hi = (a_uint16_t) (val >> 16); |
| |
| mutex_lock(&switch_mdio_lock); |
| mdiobus_write(bus, switch_chip_id, switch_chip_reg, r3); |
| udelay(100); |
| if(SSDK_CURRENT_CHIP_TYPE != CHIP_SHIVA) { |
| mdiobus_write(bus, 0x10 | r2, r1, lo); |
| mdiobus_write(bus, 0x10 | r2, r1 + 1, hi); |
| } else { |
| mdiobus_write(bus, 0x10 | r2, r1 + 1, hi); |
| mdiobus_write(bus, 0x10 | r2, r1, lo); |
| } |
| mdiobus_write(bus, switch_chip_id, switch_chip_reg, HIGH_ADDR_DFLT); |
| mutex_unlock(&switch_mdio_lock); |
| } |
| |
| /*qca808x_start*/ |
| a_bool_t |
| phy_addr_validation_check(a_uint32_t phy_addr) |
| { |
| |
| if ((phy_addr > SSDK_PHY_BCAST_ID) || (phy_addr < SSDK_PHY_MIN_ID)) |
| return A_FALSE; |
| else |
| return A_TRUE; |
| } |
| |
| static struct mii_bus * |
| ssdk_phy_miibus_get(a_uint32_t dev_id, a_uint32_t phy_addr) |
| { |
| struct mii_bus *bus = NULL; |
| /*qca808x_end*/ |
| #ifndef BOARD_AR71XX |
| #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) |
| bus = ssdk_dts_miibus_get(dev_id, phy_addr); |
| #endif |
| #endif |
| /*qca808x_start*/ |
| if (!bus) |
| bus = qca_phy_priv_global[dev_id]->miibus; |
| |
| return bus; |
| } |
| |
| sw_error_t |
| qca_ar8327_phy_read(a_uint32_t dev_id, a_uint32_t phy_addr, |
| a_uint32_t reg, a_uint16_t* data) |
| { |
| struct mii_bus *bus = NULL; |
| |
| if (A_TRUE != phy_addr_validation_check (phy_addr)) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| bus = ssdk_phy_miibus_get(dev_id, phy_addr); |
| if (!bus) |
| return SW_NOT_SUPPORTED; |
| |
| *data = mdiobus_read(bus, phy_addr, reg); |
| return 0; |
| } |
| |
| sw_error_t |
| qca_ar8327_phy_write(a_uint32_t dev_id, a_uint32_t phy_addr, |
| a_uint32_t reg, a_uint16_t data) |
| { |
| struct mii_bus *bus = NULL; |
| |
| if (A_TRUE != phy_addr_validation_check (phy_addr)) |
| { |
| return SW_BAD_PARAM; |
| } |
| |
| bus = ssdk_phy_miibus_get(dev_id, phy_addr); |
| if (!bus) |
| return SW_NOT_SUPPORTED; |
| |
| mdiobus_write(bus, phy_addr, reg, data); |
| return 0; |
| } |
| |
| void |
| qca_ar8327_phy_dbg_write(a_uint32_t dev_id, a_uint32_t phy_addr, |
| a_uint16_t dbg_addr, a_uint16_t dbg_data) |
| { |
| struct mii_bus *bus = NULL; |
| |
| if (A_TRUE != phy_addr_validation_check (phy_addr)) |
| { |
| return; |
| } |
| |
| bus = ssdk_phy_miibus_get(dev_id, phy_addr); |
| if (!bus) |
| return; |
| |
| mdiobus_write(bus, phy_addr, QCA_MII_DBG_ADDR, dbg_addr); |
| mdiobus_write(bus, phy_addr, QCA_MII_DBG_DATA, dbg_data); |
| } |
| |
| void |
| qca_ar8327_phy_dbg_read(a_uint32_t dev_id, a_uint32_t phy_addr, |
| a_uint16_t dbg_addr, a_uint16_t *dbg_data) |
| { |
| struct mii_bus *bus = NULL; |
| |
| if (A_TRUE != phy_addr_validation_check (phy_addr)) |
| { |
| return; |
| } |
| |
| bus = ssdk_phy_miibus_get(dev_id, phy_addr); |
| if (!bus) |
| return; |
| |
| mdiobus_write(bus, phy_addr, QCA_MII_DBG_ADDR, dbg_addr); |
| *dbg_data = mdiobus_read(bus, phy_addr, QCA_MII_DBG_DATA); |
| } |
| |
| |
| void |
| qca_ar8327_mmd_write(a_uint32_t dev_id, a_uint32_t phy_addr, |
| a_uint16_t addr, a_uint16_t data) |
| { |
| struct mii_bus *bus = NULL; |
| |
| if (A_TRUE != phy_addr_validation_check (phy_addr)) |
| { |
| return; |
| } |
| |
| bus = ssdk_phy_miibus_get(dev_id, phy_addr); |
| if (!bus) |
| return; |
| |
| mdiobus_write(bus, phy_addr, QCA_MII_MMD_ADDR, addr); |
| mdiobus_write(bus, phy_addr, QCA_MII_MMD_DATA, data); |
| } |
| |
| void qca_phy_mmd_write(u32 dev_id, u32 phy_id, |
| u16 mmd_num, u16 reg_id, u16 reg_val) |
| { |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_ADDR, mmd_num); |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_DATA, reg_id); |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_ADDR, |
| 0x4000 | mmd_num); |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_DATA, reg_val); |
| } |
| |
| u16 qca_phy_mmd_read(u32 dev_id, u32 phy_id, |
| u16 mmd_num, u16 reg_id) |
| { |
| u16 value = 0; |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_ADDR, mmd_num); |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_DATA, reg_id); |
| qca_ar8327_phy_write(dev_id, phy_id, |
| QCA_MII_MMD_ADDR, |
| 0x4000 | mmd_num); |
| qca_ar8327_phy_read(dev_id, phy_id, |
| QCA_MII_MMD_DATA, &value); |
| return value; |
| } |
| /*qca808x_end*/ |
| sw_error_t |
| qca_switch_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| uint32_t reg_val = 0; |
| |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if ((reg_addr%4)!= 0) |
| return SW_BAD_PARAM; |
| |
| reg_val = readl(qca_phy_priv_global[dev_id]->hw_addr + reg_addr); |
| |
| aos_mem_copy(reg_data, ®_val, sizeof (a_uint32_t)); |
| return 0; |
| } |
| |
| sw_error_t |
| qca_switch_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| uint32_t reg_val = 0; |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if ((reg_addr%4)!= 0) |
| return SW_BAD_PARAM; |
| |
| aos_mem_copy(®_val, reg_data, sizeof (a_uint32_t)); |
| writel(reg_val, qca_phy_priv_global[dev_id]->hw_addr + reg_addr); |
| return 0; |
| } |
| |
| sw_error_t |
| qca_psgmii_reg_read(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| #ifdef DESS |
| uint32_t reg_val = 0; |
| |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if((reg_addr%4)!=0) |
| return SW_BAD_PARAM; |
| |
| if (qca_phy_priv_global[dev_id]->psgmii_hw_addr == NULL) |
| return SW_NOT_SUPPORTED; |
| |
| reg_val = readl(qca_phy_priv_global[dev_id]->psgmii_hw_addr + reg_addr); |
| |
| aos_mem_copy(reg_data, ®_val, sizeof (a_uint32_t)); |
| #endif |
| return 0; |
| } |
| |
| sw_error_t |
| qca_psgmii_reg_write(a_uint32_t dev_id, a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| #ifdef DESS |
| uint32_t reg_val = 0; |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if((reg_addr%4)!=0) |
| return SW_BAD_PARAM; |
| |
| if (qca_phy_priv_global[dev_id]->psgmii_hw_addr == NULL) |
| return SW_NOT_SUPPORTED; |
| |
| aos_mem_copy(®_val, reg_data, sizeof (a_uint32_t)); |
| writel(reg_val, qca_phy_priv_global[dev_id]->psgmii_hw_addr + reg_addr); |
| #endif |
| return 0; |
| } |
| |
| sw_error_t |
| qca_uniphy_reg_read(a_uint32_t dev_id, a_uint32_t uniphy_index, |
| a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| #if (defined(HPPE) || defined(MP)) |
| uint32_t reg_val = 0; |
| void __iomem *hppe_uniphy_base = NULL; |
| a_uint32_t reg_addr1, reg_addr2; |
| |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if (SSDK_UNIPHY_INSTANCE0 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr; |
| else if (SSDK_UNIPHY_INSTANCE1 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr + HPPE_UNIPHY_BASE1; |
| |
| else if (SSDK_UNIPHY_INSTANCE2 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr + HPPE_UNIPHY_BASE2; |
| else |
| return SW_BAD_PARAM; |
| |
| if ( reg_addr > HPPE_UNIPHY_MAX_DIRECT_ACCESS_REG) |
| { |
| // uniphy reg indireclty access |
| reg_addr1 = (reg_addr & 0xffffff) >> 8; |
| writel(reg_addr1, hppe_uniphy_base + HPPE_UNIPHY_INDIRECT_REG_ADDR); |
| |
| reg_addr2 = reg_addr & HPPE_UNIPHY_INDIRECT_LOW_ADDR; |
| reg_addr = (HPPE_UNIPHY_INDIRECT_DATA << 10) | (reg_addr2 << 2); |
| |
| reg_val = readl(hppe_uniphy_base + reg_addr); |
| aos_mem_copy(reg_data, ®_val, sizeof (a_uint32_t)); |
| } |
| else |
| { // uniphy reg directly access |
| reg_val = readl(hppe_uniphy_base + reg_addr); |
| aos_mem_copy(reg_data, ®_val, sizeof (a_uint32_t)); |
| } |
| #endif |
| return 0; |
| } |
| |
| sw_error_t |
| qca_uniphy_reg_write(a_uint32_t dev_id, a_uint32_t uniphy_index, |
| a_uint32_t reg_addr, a_uint8_t * reg_data, a_uint32_t len) |
| { |
| #if (defined(HPPE) || defined(MP)) |
| void __iomem *hppe_uniphy_base = NULL; |
| a_uint32_t reg_addr1, reg_addr2; |
| uint32_t reg_val = 0; |
| |
| if (len != sizeof (a_uint32_t)) |
| return SW_BAD_LEN; |
| |
| if (SSDK_UNIPHY_INSTANCE0 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr; |
| else if (SSDK_UNIPHY_INSTANCE1 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr + HPPE_UNIPHY_BASE1; |
| |
| else if (SSDK_UNIPHY_INSTANCE2 == uniphy_index) |
| hppe_uniphy_base = qca_phy_priv_global[dev_id]->uniphy_hw_addr + HPPE_UNIPHY_BASE2; |
| else |
| return SW_BAD_PARAM; |
| |
| if ( reg_addr > HPPE_UNIPHY_MAX_DIRECT_ACCESS_REG) |
| { |
| // uniphy reg indireclty access |
| reg_addr1 = (reg_addr & 0xffffff) >> 8; |
| writel(reg_addr1, hppe_uniphy_base + HPPE_UNIPHY_INDIRECT_REG_ADDR); |
| |
| reg_addr2 = reg_addr & HPPE_UNIPHY_INDIRECT_LOW_ADDR; |
| reg_addr = (HPPE_UNIPHY_INDIRECT_DATA << 10) | (reg_addr2 << 2); |
| aos_mem_copy(®_val, reg_data, sizeof (a_uint32_t)); |
| writel(reg_val, hppe_uniphy_base + reg_addr); |
| } |
| else |
| { // uniphy reg directly access |
| aos_mem_copy(®_val, reg_data, sizeof (a_uint32_t)); |
| writel(reg_val, hppe_uniphy_base + reg_addr); |
| } |
| #endif |
| return 0; |
| } |
| #ifndef BOARD_AR71XX |
| /*qca808x_start*/ |
| static int miibus_get(a_uint32_t dev_id) |
| { |
| /*qca808x_end*/ |
| #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) |
| /*qca808x_start*/ |
| struct device_node *mdio_node = NULL; |
| struct device_node *switch_node = NULL; |
| struct platform_device *mdio_plat = NULL; |
| struct ipq40xx_mdio_data *mdio_data = NULL; |
| struct qca_phy_priv *priv; |
| hsl_reg_mode reg_mode = HSL_REG_LOCAL_BUS; |
| priv = qca_phy_priv_global[dev_id]; |
| switch_node = qca_phy_priv_global[dev_id]->of_node; |
| if (switch_node) { |
| mdio_node = of_parse_phandle(switch_node, "mdio-bus", 0); |
| if (mdio_node) { |
| priv->miibus = of_mdio_find_bus(mdio_node); |
| return 0; |
| } |
| } |
| /*qca808x_end*/ |
| reg_mode=ssdk_switch_reg_access_mode_get(dev_id); |
| /*qca808x_start*/ |
| if(reg_mode == HSL_REG_LOCAL_BUS) |
| mdio_node = of_find_compatible_node(NULL, NULL, "qcom,ipq40xx-mdio"); |
| else |
| mdio_node = of_find_compatible_node(NULL, NULL, "virtual,mdio-gpio"); |
| |
| if (!mdio_node) { |
| SSDK_ERROR("No MDIO node found in DTS!\n"); |
| return 1; |
| } |
| |
| mdio_plat = of_find_device_by_node(mdio_node); |
| if (!mdio_plat) { |
| SSDK_ERROR("cannot find platform device from mdio node\n"); |
| return 1; |
| } |
| |
| if(reg_mode == HSL_REG_LOCAL_BUS) |
| { |
| mdio_data = dev_get_drvdata(&mdio_plat->dev); |
| if (!mdio_data) { |
| SSDK_ERROR("cannot get mdio_data reference from device data\n"); |
| return 1; |
| } |
| priv->miibus = mdio_data->mii_bus; |
| } |
| else |
| priv->miibus = dev_get_drvdata(&mdio_plat->dev); |
| |
| if (!priv->miibus) { |
| SSDK_ERROR("cannot get mii bus reference from device data\n"); |
| return 1; |
| } |
| /*qca808x_end*/ |
| #else |
| struct device *miidev; |
| char busid[MII_BUS_ID_SIZE]; |
| struct qca_phy_priv *priv; |
| |
| priv = qca_phy_priv_global[dev_id]; |
| snprintf(busid, MII_BUS_ID_SIZE, "%s.%d", |
| PLATFORM_MDIO_BUS_NAME, PLATFORM_MDIO_BUS_NUM); |
| |
| miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid); |
| if (!miidev) { |
| SSDK_ERROR("Failed to get miidev\n"); |
| return 1; |
| } |
| |
| priv->miibus = dev_get_drvdata(miidev); |
| |
| if(!priv->miibus){ |
| SSDK_ERROR("mdio bus '%s' get FAIL\n", busid); |
| return 1; |
| } |
| #endif |
| /*qca808x_start*/ |
| return 0; |
| } |
| /*qca808x_end*/ |
| #else |
| static int miibus_get(a_uint32_t dev_id) |
| { |
| struct ag71xx_mdio *am; |
| struct qca_phy_priv *priv = qca_phy_priv_global[dev_id]; |
| #if defined(CONFIG_OF) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) |
| struct device_node *mdio_node = NULL; |
| struct platform_device *mdio_plat = NULL; |
| |
| mdio_node = of_find_compatible_node(NULL, NULL, "qca,ag71xx-mdio"); |
| if (!mdio_node) { |
| SSDK_ERROR("No MDIO node found in DTS!\n"); |
| return 1; |
| } |
| mdio_plat = of_find_device_by_node(mdio_node); |
| if (!mdio_plat) { |
| SSDK_ERROR("cannot find platform device from mdio node\n"); |
| return 1; |
| } |
| am = dev_get_drvdata(&mdio_plat->dev); |
| if (!am) { |
| SSDK_ERROR("cannot get mdio_data reference from device data\n"); |
| return 1; |
| } |
| priv->miibus = am->mii_bus; |
| |
| switch_chip_id_adjuest(dev_id); |
| #else |
| struct device *miidev; |
| char busid[MII_BUS_ID_SIZE]; |
| |
| snprintf(busid, MII_BUS_ID_SIZE, "%s.%d", |
| PLATFORM_MDIO_BUS_NAME, PLATFORM_MDIO_BUS_NUM); |
| |
| miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid); |
| if (!miidev) { |
| SSDK_ERROR("Failed to get miidev!\n"); |
| return 1; |
| } |
| am = dev_get_drvdata(miidev); |
| priv->miibus = am->mii_bus; |
| |
| if(switch_chip_id_adjuest(dev_id)) { |
| snprintf(busid, MII_BUS_ID_SIZE, "%s.%d", |
| PLATFORM_MDIO_BUS_NAME, MDIO_BUS_1); |
| |
| miidev = bus_find_device_by_name(&platform_bus_type, NULL, busid); |
| if (!miidev) { |
| SSDK_ERROR("Failed get mii bus\n"); |
| return 1; |
| } |
| |
| am = dev_get_drvdata(miidev); |
| priv->miibus = am->mii_bus; |
| SSDK_INFO("chip_version:0x%x\n", (qca_ar8216_mii_read(dev_id, 0)&0xff00)>>8); |
| } |
| |
| if(!miidev){ |
| SSDK_ERROR("mdio bus '%s' get FAIL\n", busid); |
| return 1; |
| } |
| #endif |
| |
| return 0; |
| } |
| #endif |
| |
| struct mii_bus *ssdk_miibus_get_by_device(a_uint32_t dev_id) |
| { |
| return qca_phy_priv_global[dev_id]->miibus; |
| } |
| |
| static ssize_t ssdk_dev_id_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| a_uint32_t num; |
| |
| num = (a_uint32_t)ssdk_dev_id; |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "%u", num); |
| return count; |
| } |
| |
| static ssize_t ssdk_dev_id_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char num_buf[12]; |
| a_uint32_t num; |
| |
| if (count >= sizeof(num_buf)) return 0; |
| memcpy(num_buf, buf, count); |
| num_buf[count] = '\0'; |
| sscanf(num_buf, "%u", &num); |
| |
| ssdk_dev_id = num; |
| |
| return count; |
| } |
| |
| static ssize_t ssdk_log_level_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| a_uint32_t num; |
| |
| num = ssdk_log_level; |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "%u", num); |
| return count; |
| } |
| |
| static ssize_t ssdk_log_level_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char num_buf[12]; |
| a_uint32_t num; |
| |
| if (count >= sizeof(num_buf)) |
| return 0; |
| memcpy(num_buf, buf, count); |
| num_buf[count] = '\0'; |
| sscanf(num_buf, "%u", &num); |
| |
| ssdk_log_level = (a_uint32_t)num; |
| |
| return count; |
| } |
| |
| static ssize_t ssdk_packet_counter_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| adpt_api_t *p_api; |
| |
| p_api = adpt_api_ptr_get(ssdk_dev_id); |
| if (p_api == NULL || p_api->adpt_debug_counter_get == NULL) |
| { |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "Unsupported\n"); |
| return count; |
| } |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "\n"); |
| |
| p_api->adpt_debug_counter_get(A_FALSE); |
| |
| return count; |
| } |
| |
| static ssize_t ssdk_packet_counter_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char num_buf[12]; |
| adpt_api_t *p_api; |
| |
| p_api = adpt_api_ptr_get(ssdk_dev_id); |
| if (p_api == NULL || p_api->adpt_debug_counter_set == NULL) { |
| SSDK_WARN("Unsupported\n"); |
| return count; |
| } |
| |
| p_api->adpt_debug_counter_set(); |
| |
| if (count >= sizeof(num_buf)) |
| return 0; |
| memcpy(num_buf, buf, count); |
| num_buf[count] = '\0'; |
| |
| |
| return count; |
| } |
| |
| static ssize_t ssdk_byte_counter_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| adpt_api_t *p_api; |
| |
| p_api = adpt_api_ptr_get(ssdk_dev_id); |
| if (p_api == NULL || p_api->adpt_debug_counter_get == NULL) |
| { |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "Unsupported\n"); |
| return count; |
| } |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "\n"); |
| |
| p_api->adpt_debug_counter_get(A_TRUE); |
| |
| return count; |
| } |
| |
| static ssize_t ssdk_byte_counter_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char num_buf[12]; |
| adpt_api_t *p_api; |
| |
| p_api = adpt_api_ptr_get(ssdk_dev_id); |
| if (p_api == NULL || p_api->adpt_debug_counter_set == NULL) { |
| SSDK_WARN("Unsupported\n"); |
| return count; |
| } |
| |
| p_api->adpt_debug_counter_set(); |
| |
| if (count >= sizeof(num_buf)) |
| return 0; |
| memcpy(num_buf, buf, count); |
| num_buf[count] = '\0'; |
| |
| |
| return count; |
| } |
| |
| #ifdef HPPE |
| #ifdef IN_QOS |
| void ssdk_dts_port_scheduler_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t i; |
| ssdk_dt_portscheduler_cfg *portscheduler_cfg; |
| ssdk_dt_scheduler_cfg *scheduler_cfg; |
| a_uint8_t srcmsg[7][16]; |
| |
| scheduler_cfg = ssdk_bootup_shceduler_cfg_get(dev_id); |
| |
| printk("===============================port_scheduler_resource===========================\n"); |
| printk("portid ucastq mcastq 10sp 10cdrr 10edrr 11cdrr 11edrr\n"); |
| for (i = 0; i < SSDK_MAX_PORT_NUM; i++) |
| { |
| portscheduler_cfg = &scheduler_cfg->pool[i]; |
| snprintf(srcmsg[0], sizeof(srcmsg[0]), "<%d %d>", portscheduler_cfg->ucastq_start, |
| portscheduler_cfg->ucastq_end); |
| snprintf(srcmsg[1], sizeof(srcmsg[1]), "<%d %d>", portscheduler_cfg->mcastq_start, |
| portscheduler_cfg->mcastq_end); |
| snprintf(srcmsg[2], sizeof(srcmsg[2]), "<%d %d>", portscheduler_cfg->l0sp_start, |
| portscheduler_cfg->l0sp_end); |
| snprintf(srcmsg[3], sizeof(srcmsg[3]), "<%d %d>", portscheduler_cfg->l0cdrr_start, |
| portscheduler_cfg->l0cdrr_end); |
| snprintf(srcmsg[4], sizeof(srcmsg[4]), "<%d %d>", portscheduler_cfg->l0edrr_start, |
| portscheduler_cfg->l0edrr_end); |
| snprintf(srcmsg[5], sizeof(srcmsg[5]), "<%d %d>", portscheduler_cfg->l1cdrr_start, |
| portscheduler_cfg->l1cdrr_end); |
| snprintf(srcmsg[6], sizeof(srcmsg[6]), "<%d %d>", portscheduler_cfg->l1edrr_start, |
| portscheduler_cfg->l1edrr_end); |
| printk("%6d%11s%11s%9s%11s%11s%11s%11s\n", i, srcmsg[0], srcmsg[1], srcmsg[2], srcmsg[3], |
| srcmsg[4], srcmsg[5], srcmsg[6]); |
| } |
| } |
| |
| void ssdk_dts_l0scheduler_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t i; |
| ssdk_dt_l0scheduler_cfg *scheduler_cfg; |
| ssdk_dt_scheduler_cfg *cfg; |
| |
| cfg = ssdk_bootup_shceduler_cfg_get(dev_id); |
| printk("==========================l0scheduler_cfg===========================\n"); |
| printk("queue portid cpri cdrr_id epri edrr_id sp_id\n"); |
| for (i = 0; i < SSDK_L0SCHEDULER_CFG_MAX; i++) |
| { |
| scheduler_cfg = &cfg->l0cfg[i]; |
| if (scheduler_cfg->valid == 1) |
| printk("%5d%11d%9d%12d%9d%12d%10d\n", i, scheduler_cfg->port_id, |
| scheduler_cfg->cpri, scheduler_cfg->cdrr_id, scheduler_cfg->epri, |
| scheduler_cfg->edrr_id, scheduler_cfg->sp_id); |
| } |
| } |
| |
| void ssdk_dts_l1scheduler_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t i; |
| ssdk_dt_l1scheduler_cfg *scheduler_cfg; |
| ssdk_dt_scheduler_cfg *cfg; |
| |
| cfg = ssdk_bootup_shceduler_cfg_get(dev_id); |
| |
| printk("=====================l1scheduler_cfg=====================\n"); |
| printk("flow portid cpri cdrr_id epri edrr_id\n"); |
| for (i = 0; i < SSDK_L1SCHEDULER_CFG_MAX; i++) |
| { |
| scheduler_cfg = &cfg->l1cfg[i]; |
| if (scheduler_cfg->valid == 1) |
| printk("%4d%11d%9d%12d%9d%12d\n", i, scheduler_cfg->port_id, |
| scheduler_cfg->cpri, scheduler_cfg->cdrr_id, |
| scheduler_cfg->epri, scheduler_cfg->edrr_id); |
| } |
| } |
| #endif |
| #endif |
| static const a_int8_t *qca_phy_feature_str[QCA_PHY_FEATURE_MAX] = { |
| "PHY_CLAUSE45", |
| "PHY_COMBO", |
| "PHY_QGMAC", |
| "PHY_XGMAC", |
| "PHY_I2C", |
| "PHY_INIT", |
| "PHY_FORCE" |
| }; |
| |
| void ssdk_dts_phyinfo_dump(a_uint32_t dev_id) |
| { |
| a_uint32_t i, j; |
| ssdk_port_phyinfo *port_phyinfo; |
| |
| printk("=====================port phyinfo========================\n"); |
| printk("portid phy_addr features\n"); |
| |
| for (i = 0; i <= SSDK_MAX_PORT_NUM; i++) { |
| port_phyinfo = ssdk_port_phyinfo_get(dev_id, i); |
| if (port_phyinfo) { |
| printk("%6d%13d%*s", port_phyinfo->port_id, |
| port_phyinfo->phy_addr, 5, ""); |
| for (j = 0; j < QCA_PHY_FEATURE_MAX; j++) { |
| if (port_phyinfo->phy_features & BIT(j) && BIT(j) != PHY_F_INIT) { |
| printk(KERN_CONT "%s ", qca_phy_feature_str[j]); |
| if (BIT(j) == PHY_F_FORCE) { |
| printk(KERN_CONT "(speed: %d, duplex: %s) ", |
| port_phyinfo->port_speed, |
| port_phyinfo->port_duplex > 0 ? |
| "full" : "half"); |
| } |
| } |
| } |
| printk(KERN_CONT "\n"); |
| } |
| } |
| } |
| |
| static ssize_t ssdk_dts_dump(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| a_uint32_t dev_id, dev_num; |
| ssdk_reg_map_info map; |
| hsl_reg_mode mode; |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "\n"); |
| |
| dev_num = ssdk_switch_device_num_get(); |
| for (dev_id = 0; dev_id < dev_num; dev_id ++) |
| { |
| ssdk_switch_reg_map_info_get(dev_id, &map); |
| mode = ssdk_switch_reg_access_mode_get(dev_id); |
| printk("=======================================================\n"); |
| printk("ess-switch\n"); |
| printk(" reg = <0x%x 0x%x>\n", map.base_addr, map.size); |
| if (mode == HSL_REG_LOCAL_BUS) |
| printk(" switch_access_mode = <local bus>\n"); |
| else if (mode == HSL_REG_MDIO) |
| printk(" switch_access_mode = <mdio bus>\n"); |
| else |
| printk(" switch_access_mode = <(null)>\n"); |
| printk(" switch_cpu_bmp = <0x%x>\n", ssdk_cpu_bmp_get(dev_id)); |
| printk(" switch_lan_bmp = <0x%x>\n", ssdk_lan_bmp_get(dev_id)); |
| printk(" switch_wan_bmp = <0x%x>\n", ssdk_wan_bmp_get(dev_id)); |
| printk(" switch_inner_bmp = <0x%x>\n", ssdk_inner_bmp_get(dev_id)); |
| printk(" switch_mac_mode = <0x%x>\n", ssdk_dt_global_get_mac_mode(dev_id, 0)); |
| printk(" switch_mac_mode1 = <0x%x>\n", ssdk_dt_global_get_mac_mode(dev_id, 1)); |
| printk(" switch_mac_mode2 = <0x%x>\n", ssdk_dt_global_get_mac_mode(dev_id, 2)); |
| #ifdef IN_BM |
| printk(" bm_tick_mode = <0x%x>\n", ssdk_bm_tick_mode_get(dev_id)); |
| #endif |
| #ifdef HPPE |
| #ifdef IN_QOS |
| printk(" tm_tick_mode = <0x%x>\n", ssdk_tm_tick_mode_get(dev_id)); |
| #endif |
| #endif |
| #ifdef DESS |
| printk("ess-psgmii\n"); |
| ssdk_psgmii_reg_map_info_get(dev_id, &map); |
| mode = ssdk_psgmii_reg_access_mode_get(dev_id); |
| printk(" reg = <0x%x 0x%x>\n", map.base_addr, map.size); |
| if (mode == HSL_REG_LOCAL_BUS) |
| printk(" psgmii_access_mode = <local bus>\n"); |
| else if (mode == HSL_REG_MDIO) |
| printk(" psgmii_access_mode = <mdio bus>\n"); |
| else |
| printk(" psgmii_access_mode = <(null)>\n"); |
| #endif |
| #ifdef IN_UNIPHY |
| printk("ess-uniphy\n"); |
| ssdk_uniphy_reg_map_info_get(dev_id, &map); |
| mode = ssdk_uniphy_reg_access_mode_get(dev_id); |
| printk(" reg = <0x%x 0x%x>\n", map.base_addr, map.size); |
| if (mode == HSL_REG_LOCAL_BUS) |
| printk(" uniphy_access_mode = <local bus>\n"); |
| else if (mode == HSL_REG_MDIO) |
| printk(" uniphy_access_mode = <mdio bus>\n"); |
| else |
| printk(" uniphy_access_mode = <(null)>\n"); |
| #endif |
| #ifdef HPPE |
| #ifdef IN_QOS |
| printk("\n"); |
| ssdk_dts_port_scheduler_dump(dev_id); |
| printk("\n"); |
| ssdk_dts_l0scheduler_dump(dev_id); |
| printk("\n"); |
| ssdk_dts_l1scheduler_dump(dev_id); |
| #endif |
| #endif |
| printk("\n"); |
| ssdk_dts_phyinfo_dump(dev_id); |
| } |
| |
| return count; |
| } |
| |
| static a_uint16_t phy_reg_val = 0; |
| static ssize_t ssdk_phy_write_reg_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char phy_buf[32]; |
| char *this_opt; |
| char *options = phy_buf; |
| unsigned int phy_addr, reg_addr, reg_value; |
| |
| if (count >= sizeof(phy_buf)) |
| return 0; |
| memcpy(phy_buf, buf, count); |
| phy_buf[count] = '\0'; |
| |
| this_opt = strsep(&options, " "); |
| if (!this_opt) |
| goto fail; |
| |
| kstrtouint(this_opt, 0, &phy_addr); |
| if ((options - phy_buf) >= (count - 1)) |
| goto fail; |
| |
| this_opt = strsep(&options, " "); |
| if (!this_opt) |
| goto fail; |
| |
| kstrtouint(this_opt, 0, ®_addr); |
| if ((options - phy_buf) >= (count - 1)) |
| goto fail; |
| |
| this_opt = strsep(&options, " "); |
| if (!this_opt) |
| goto fail; |
| |
| kstrtouint(this_opt, 0, ®_value); |
| |
| qca_ar8327_phy_write(0, phy_addr, reg_addr, reg_value); |
| |
| return count; |
| |
| fail: |
| printk("Format: phy_addr reg_addr reg_value\n"); |
| return -EINVAL; |
| } |
| |
| static ssize_t ssdk_phy_read_reg_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "reg_val = 0x%x\n", phy_reg_val); |
| return count; |
| } |
| |
| static ssize_t ssdk_phy_read_reg_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| char phy_buf[32]; |
| char *this_opt; |
| char *options = phy_buf; |
| unsigned int phy_addr, reg_addr; |
| |
| if (count >= sizeof(phy_buf)) |
| return 0; |
| memcpy(phy_buf, buf, count); |
| phy_buf[count] = '\0'; |
| |
| this_opt = strsep(&options, " "); |
| if (!this_opt) |
| goto fail; |
| |
| kstrtouint(this_opt, 0, &phy_addr); |
| if ((options - phy_buf) >= (count - 1)) |
| goto fail; |
| |
| this_opt = strsep(&options, " "); |
| if (!this_opt) |
| goto fail; |
| |
| kstrtouint(this_opt, 0, ®_addr); |
| |
| qca_ar8327_phy_read(0, phy_addr, reg_addr, &phy_reg_val); |
| |
| return count; |
| |
| fail: |
| printk("Format: phy_addr reg_addr\n"); |
| return -EINVAL; |
| } |
| |
| #ifdef IN_LINUX_STD_PTP |
| static ssize_t ssdk_ptp_counter_get(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| ssize_t count; |
| |
| count = snprintf(buf, (ssize_t)PAGE_SIZE, "\n"); |
| qca808x_ptp_stat_get(); |
| return count; |
| } |
| |
| static ssize_t ssdk_ptp_counter_set(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| qca808x_ptp_stat_set(); |
| return count; |
| } |
| #endif |
| |
| static const struct device_attribute ssdk_dev_id_attr = |
| __ATTR(dev_id, 0660, ssdk_dev_id_get, ssdk_dev_id_set); |
| static const struct device_attribute ssdk_log_level_attr = |
| __ATTR(log_level, 0660, ssdk_log_level_get, ssdk_log_level_set); |
| static const struct device_attribute ssdk_packet_counter_attr = |
| __ATTR(packet_counter, 0660, ssdk_packet_counter_get, ssdk_packet_counter_set); |
| static const struct device_attribute ssdk_byte_counter_attr = |
| __ATTR(byte_counter, 0660, ssdk_byte_counter_get, ssdk_byte_counter_set); |
| static const struct device_attribute ssdk_dts_dump_attr = |
| __ATTR(dts_dump, 0660, ssdk_dts_dump, NULL); |
| static const struct device_attribute ssdk_phy_write_reg_attr = |
| __ATTR(phy_write_reg, 0660, NULL, ssdk_phy_write_reg_set); |
| static const struct device_attribute ssdk_phy_read_reg_attr = |
| __ATTR(phy_read_reg, 0660, ssdk_phy_read_reg_get, ssdk_phy_read_reg_set); |
| #ifdef IN_LINUX_STD_PTP |
| static const struct device_attribute ssdk_ptp_counter_attr = |
| __ATTR(ptp_packet_counter, 0660, ssdk_ptp_counter_get, ssdk_ptp_counter_set); |
| #endif |
| struct kobject *ssdk_sys = NULL; |
| |
| int ssdk_sysfs_init (void) |
| { |
| int ret = 0; |
| |
| /* create /sys/ssdk/ dir */ |
| ssdk_sys = kobject_create_and_add("ssdk", NULL); |
| if (!ssdk_sys) { |
| printk("Failed to register SSDK sysfs\n"); |
| return ret; |
| } |
| |
| /* create /sys/ssdk/dev_id file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_dev_id_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK dev id SysFS file\n"); |
| goto CLEANUP_1; |
| } |
| |
| /* create /sys/ssdk/log_level file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_log_level_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK log level SysFS file\n"); |
| goto CLEANUP_2; |
| } |
| |
| /* create /sys/ssdk/packet_counter file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_packet_counter_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK switch counter SysFS file\n"); |
| goto CLEANUP_3; |
| } |
| |
| /* create /sys/ssdk/byte_counter file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_byte_counter_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK switch counter bytes SysFS file\n"); |
| goto CLEANUP_4; |
| } |
| |
| /* create /sys/ssdk/dts_dump file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_dts_dump_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK switch show dts SysFS file\n"); |
| goto CLEANUP_5; |
| } |
| |
| /* create /sys/ssdk/phy_write_reg file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_phy_write_reg_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK phy write reg file\n"); |
| goto CLEANUP_6; |
| } |
| |
| /* create /sys/ssdk/phy_read_reg file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_phy_read_reg_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK phy read reg file\n"); |
| goto CLEANUP_7; |
| } |
| |
| #ifdef IN_LINUX_STD_PTP |
| /* create /sys/ssdk/ptp_packet_counter file */ |
| ret = sysfs_create_file(ssdk_sys, &ssdk_ptp_counter_attr.attr); |
| if (ret) { |
| printk("Failed to register SSDK ptp counter file\n"); |
| goto CLEANUP_8; |
| } |
| #endif |
| |
| return 0; |
| |
| #ifdef IN_LINUX_STD_PTP |
| CLEANUP_8: |
| sysfs_remove_file(ssdk_sys, &ssdk_phy_read_reg_attr.attr); |
| #endif |
| CLEANUP_7: |
| sysfs_remove_file(ssdk_sys, &ssdk_phy_write_reg_attr.attr); |
| CLEANUP_6: |
| sysfs_remove_file(ssdk_sys, &ssdk_dts_dump_attr.attr); |
| CLEANUP_5: |
| sysfs_remove_file(ssdk_sys, &ssdk_byte_counter_attr.attr); |
| CLEANUP_4: |
| sysfs_remove_file(ssdk_sys, &ssdk_packet_counter_attr.attr); |
| CLEANUP_3: |
| sysfs_remove_file(ssdk_sys, &ssdk_log_level_attr.attr); |
| CLEANUP_2: |
| sysfs_remove_file(ssdk_sys, &ssdk_dev_id_attr.attr); |
| CLEANUP_1: |
| kobject_put(ssdk_sys); |
| |
| return ret; |
| } |
| |
| void ssdk_sysfs_exit (void) |
| { |
| #ifdef IN_LINUX_STD_PTP |
| sysfs_remove_file(ssdk_sys, &ssdk_ptp_counter_attr.attr); |
| #endif |
| sysfs_remove_file(ssdk_sys, &ssdk_phy_read_reg_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_phy_write_reg_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_dts_dump_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_byte_counter_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_packet_counter_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_log_level_attr.attr); |
| sysfs_remove_file(ssdk_sys, &ssdk_dev_id_attr.attr); |
| kobject_put(ssdk_sys); |
| } |
| |
| /*qca808x_start*/ |
| int |
| ssdk_plat_init(ssdk_init_cfg *cfg, a_uint32_t dev_id) |
| { |
| /*qca808x_end*/ |
| hsl_reg_mode reg_mode; |
| ssdk_reg_map_info map; |
| struct clk * ess_clk; |
| struct clk * cmn_clk; |
| #ifdef BOARD_AR71XX |
| int rv = 0; |
| #endif |
| /*qca808x_start*/ |
| printk("ssdk_plat_init start\n"); |
| /*qca808x_end*/ |
| mutex_init(&switch_mdio_lock); |
| |
| if(!ssdk_is_emulation(dev_id)){ |
| /*qca808x_start*/ |
| if(miibus_get(dev_id)) |
| return -ENODEV; |
| /*qca808x_end*/ |
| } |
| #ifdef IN_UNIPHY |
| reg_mode = ssdk_uniphy_reg_access_mode_get(dev_id); |
| if(reg_mode == HSL_REG_LOCAL_BUS) { |
| ssdk_uniphy_reg_map_info_get(dev_id, &map); |
| qca_phy_priv_global[dev_id]->uniphy_hw_addr = ioremap_nocache(map.base_addr, |
| map.size); |
| if (!qca_phy_priv_global[dev_id]->uniphy_hw_addr) { |
| SSDK_ERROR("%s ioremap fail.", __func__); |
| cfg->reg_func.uniphy_reg_set = NULL; |
| cfg->reg_func.uniphy_reg_get = NULL; |
| return -1; |
| } |
| cfg->reg_func.uniphy_reg_set = qca_uniphy_reg_write; |
| cfg->reg_func.uniphy_reg_get = qca_uniphy_reg_read; |
| } |
| #endif |
| reg_mode = ssdk_switch_reg_access_mode_get(dev_id); |
| if(reg_mode == HSL_REG_LOCAL_BUS) { |
| ssdk_switch_reg_map_info_get(dev_id, &map); |
| qca_phy_priv_global[dev_id]->hw_addr = ioremap_nocache(map.base_addr, |
| map.size); |
| if (!qca_phy_priv_global[dev_id]->hw_addr) { |
| SSDK_ERROR("%s ioremap fail.", __func__); |
| return -1; |
| } |
| ess_clk = ssdk_dts_essclk_get(dev_id); |
| cmn_clk = ssdk_dts_cmnclk_get(dev_id); |
| if (!IS_ERR(ess_clk)) { |
| /* Enable ess clock here */ |
| SSDK_INFO("Enable ess clk\n"); |
| clk_prepare_enable(ess_clk); |
| } else if (!IS_ERR(cmn_clk)) { |
| #if defined(HPPE) || defined(MP) |
| ssdk_gcc_clock_init(); |
| #endif |
| return 0; |
| } |
| |
| cfg->reg_mode = HSL_HEADER; |
| } |
| #ifdef DESS |
| reg_mode = ssdk_psgmii_reg_access_mode_get(dev_id); |
| if(reg_mode == HSL_REG_LOCAL_BUS) { |
| ssdk_psgmii_reg_map_info_get(dev_id, &map); |
| if (!request_mem_region(map.base_addr, |
| map.size, "psgmii_mem")) { |
| SSDK_ERROR("%s Unable to request psgmii resource.", __func__); |
| return -1; |
| } |
| |
| qca_phy_priv_global[dev_id]->psgmii_hw_addr = ioremap_nocache(map.base_addr, |
| map.size); |
| if (!qca_phy_priv_global[dev_id]->psgmii_hw_addr) { |
| SSDK_ERROR("%s ioremap fail.", __func__); |
| cfg->reg_func.psgmii_reg_set = NULL; |
| cfg->reg_func.psgmii_reg_get = NULL; |
| return -1; |
| } |
| |
| cfg->reg_func.psgmii_reg_set = qca_psgmii_reg_write; |
| cfg->reg_func.psgmii_reg_get = qca_psgmii_reg_read; |
| } |
| #endif |
| reg_mode = ssdk_switch_reg_access_mode_get(dev_id); |
| if(reg_mode == HSL_REG_MDIO) { |
| cfg->reg_mode = HSL_MDIO; |
| } else |
| return 0; |
| /*qca808x_start*/ |
| |
| return 0; |
| } |
| |
| void |
| ssdk_plat_exit(a_uint32_t dev_id) |
| { |
| /*qca808x_end*/ |
| hsl_reg_mode reg_mode; |
| #ifdef DESS |
| ssdk_reg_map_info map; |
| #endif |
| /*qca808x_start*/ |
| printk("ssdk_plat_exit\n"); |
| /*qca808x_end*/ |
| reg_mode = ssdk_switch_reg_access_mode_get(dev_id); |
| if (reg_mode == HSL_REG_LOCAL_BUS) { |
| iounmap(qca_phy_priv_global[dev_id]->hw_addr); |
| } |
| #ifdef DESS |
| reg_mode = ssdk_psgmii_reg_access_mode_get(dev_id); |
| if (reg_mode == HSL_REG_LOCAL_BUS) { |
| ssdk_psgmii_reg_map_info_get(dev_id, &map); |
| iounmap(qca_phy_priv_global[dev_id]->psgmii_hw_addr); |
| release_mem_region(map.base_addr, |
| map.size); |
| } |
| #endif |
| #ifdef IN_UNIPHY |
| reg_mode = ssdk_uniphy_reg_access_mode_get(dev_id); |
| if (reg_mode == HSL_REG_LOCAL_BUS) { |
| iounmap(qca_phy_priv_global[dev_id]->uniphy_hw_addr); |
| } |
| #endif |
| /*qca808x_start*/ |
| } |
| /*qca808x_end*/ |
| |