sm8750: init kernel modules repo

This commit is contained in:
2025-08-11 12:21:01 +02:00
parent 2681143b87
commit facad83b01
8851 changed files with 6894561 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
SMEM_MAILBOX_DLKM_BOARD_PLATFORMS_LIST := sun
ifneq (,$(call is-board-platform-in-list2,$(SMEM_MAILBOX_DLKM_BOARD_PLATFORMS_LIST)))
BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/smem-mailbox.ko
endif

View File

@@ -0,0 +1,3 @@
ifeq ($(TARGET_BOARD_PLATFORM), sun)
PRODUCT_PACKAGES += smem-mailbox.ko
endif

View File

@@ -0,0 +1 @@
include $(call all-subdir-makefiles)

View File

@@ -0,0 +1,37 @@
#This makefile is only to compile EMAC for AUTO platform
ifeq ($(TARGET_BOARD_AUTO),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# This makefile is only for DLKM
ifneq ($(findstring vendor,$(LOCAL_PATH)),)
ifneq ($(findstring opensource,$(LOCAL_PATH)),)
EMAC_BLD_DIR := ../../vendor/qcom/opensource/data-kernel/drivers/emac-dwc-eqos
endif # opensource
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
DLKM_DIR := ./device/qcom/common/dlkm
KBUILD_OPTIONS := $(EMAC_BLD_DIR)
KBUILD_OPTIONS += DCONFIG_PTPSUPPORT_OBJ=1
KBUILD_OPTIONS += DCONFIG_DEBUGFS_OBJ=1
#KBUILD_OPTIONS += DDWC_ETH_QOS_TEST=1
LOCAL_MODULE := emac_dwc_eqos.ko
LOCAL_MODULE_TAGS := optional
include $(DLKM_DIR)/Build_external_kernelmodule.mk
include $(CLEAR_VARS)
LOCAL_MODULE := emac_perf_settings.sh
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/emac
LOCAL_SRC_FILES := emac_perf_settings.sh
include $(BUILD_PREBUILT)
endif
endif

View File

@@ -0,0 +1,50 @@
/* Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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 <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <linux/inet.h>
#include <asm/uaccess.h>
#define EMAC_DRV_NAME "qcom-emac-dwc-eqos"
static int __init DWC_ETH_QOS_app_init (void)
{
struct net_device *dev;
rtnl_lock();
for_each_netdev(&init_net, dev) {
if(strncmp (EMAC_DRV_NAME, netdev_drivername(dev), strlen(EMAC_DRV_NAME)) == 0)
if (dev_change_flags(dev, dev->flags | IFF_UP) < 0)
pr_err("EMAC_DRV_NAME:DWC_ETH_QOS_app_init: Failed to open %s\n", dev->name);
}
rtnl_unlock();
pr_info("Call DWC_ETH_QOS_open function for test purpose\r\n");
return 0;
}
static void __exit DWC_ETH_QOS_app_cleanup (void)
{
return;
}
module_init(DWC_ETH_QOS_app_init);
module_exit(DWC_ETH_QOS_app_cleanup);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* =========================================================================
*/
#ifndef __DWC_ETH_QOS_DESC_H__
#define __DWC_ETH_QOS_DESC_H__
static INT allocate_buffer_and_desc(struct DWC_ETH_QOS_prv_data *);
static void DWC_ETH_QOS_wrapper_tx_descriptor_init(struct DWC_ETH_QOS_prv_data
*pdata);
static void DWC_ETH_QOS_wrapper_tx_descriptor_init_single_q(
struct DWC_ETH_QOS_prv_data *pdata, UINT);
static void DWC_ETH_QOS_wrapper_rx_descriptor_init(struct DWC_ETH_QOS_prv_data
*pdata);
static void DWC_ETH_QOS_wrapper_rx_descriptor_init_single_q(
struct DWC_ETH_QOS_prv_data *pdata, UINT);
#ifdef DWC_INET_LRO
static int DWC_ETH_QOS_get_skb_hdr(struct sk_buff *skb, void **iphdr,
void **tcph, u64 *hdr_flags, void *priv);
#endif
static void DWC_ETH_QOS_tx_free_mem(struct DWC_ETH_QOS_prv_data *);
static void DWC_ETH_QOS_rx_free_mem(struct DWC_ETH_QOS_prv_data *);
static unsigned int DWC_ETH_QOS_map_skb(struct net_device *, struct sk_buff *);
static void DWC_ETH_QOS_unmap_tx_skb(struct DWC_ETH_QOS_prv_data *,
struct DWC_ETH_QOS_tx_buffer *);
static void DWC_ETH_QOS_unmap_rx_skb(struct DWC_ETH_QOS_prv_data *,
struct DWC_ETH_QOS_rx_buffer *);
static void DWC_ETH_QOS_re_alloc_skb(
struct DWC_ETH_QOS_prv_data *pdata, UINT);
static void DWC_ETH_QOS_tx_desc_free_mem(struct DWC_ETH_QOS_prv_data *pdata,
UINT tx_q_cnt);
static void DWC_ETH_QOS_tx_buf_free_mem(struct DWC_ETH_QOS_prv_data *pdata,
UINT tx_q_cnt);
static void DWC_ETH_QOS_rx_desc_free_mem(struct DWC_ETH_QOS_prv_data *pdata,
UINT rx_q_cnt);
static void DWC_ETH_QOS_rx_buf_free_mem(struct DWC_ETH_QOS_prv_data *pdata,
UINT rx_q_cnt);
static void DWC_ETH_QOS_rx_skb_free_mem(
struct DWC_ETH_QOS_prv_data *pdata, UINT);
static void DWC_ETH_QOS_tx_skb_free_mem(struct DWC_ETH_QOS_prv_data *pdata,
UINT);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* =========================================================================
*/
#ifndef __DWC_ETH_QOS_DRV_H__
#define __DWC_ETH_QOS_DRV_H__
static int DWC_ETH_QOS_open(struct net_device *);
static int DWC_ETH_QOS_close(struct net_device *);
static void DWC_ETH_QOS_set_rx_mode(struct net_device *);
static int DWC_ETH_QOS_start_xmit(struct sk_buff *, struct net_device *);
static void DWC_ETH_QOS_tx_interrupt(struct net_device *,
struct DWC_ETH_QOS_prv_data *, UINT);
static struct net_device_stats *DWC_ETH_QOS_get_stats(struct net_device *);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void DWC_ETH_QOS_poll_controller(struct net_device *);
#endif /*end of CONFIG_NET_POLL_CONTROLLER */
static int DWC_ETH_QOS_set_features(
struct net_device *dev, netdev_features_t features);
static netdev_features_t DWC_ETH_QOS_fix_features(
struct net_device *dev, netdev_features_t features);
INT DWC_ETH_QOS_configure_remotewakeup(struct net_device *dev,
struct ifr_data_struct *req);
static void DWC_ETH_QOS_program_dcb_algorithm(
struct DWC_ETH_QOS_prv_data *pdata, struct ifr_data_struct *req);
static void DWC_ETH_QOS_program_avb_algorithm(
struct DWC_ETH_QOS_prv_data *pdata, struct ifr_data_struct *req);
static void DWC_ETH_QOS_config_tx_pbl(struct DWC_ETH_QOS_prv_data *pdata,
UINT tx_pbl, UINT ch_no);
static void DWC_ETH_QOS_config_rx_pbl(struct DWC_ETH_QOS_prv_data *pdata,
UINT rx_pbl, UINT ch_no);
static int DWC_ETH_QOS_handle_prv_ioctl(struct DWC_ETH_QOS_prv_data *pdata,
struct ifr_data_struct *req);
static int DWC_ETH_QOS_handle_prv_ioctl_ipa(struct DWC_ETH_QOS_prv_data *pdata,
struct ifreq *ifr);
static int DWC_ETH_QOS_ioctl(struct net_device *, struct ifreq *, int);
static INT DWC_ETH_QOS_change_mtu(struct net_device *dev, INT new_mtu);
static int DWC_ETH_QOS_clean_split_hdr_rx_irq(
struct DWC_ETH_QOS_prv_data *pdata, int quota, UINT);
static int DWC_ETH_QOS_clean_jumbo_rx_irq(struct DWC_ETH_QOS_prv_data *pdata,
int quota, UINT);
static int DWC_ETH_QOS_clean_rx_irq(struct DWC_ETH_QOS_prv_data *pdata,
int quota, UINT);
static void DWC_ETH_QOS_consume_page(struct DWC_ETH_QOS_rx_buffer *buffer,
struct sk_buff *skb,
u16 length, u16 buf2_len);
static void DWC_ETH_QOS_receive_skb(struct DWC_ETH_QOS_prv_data *pdata,
struct net_device *dev,
struct sk_buff *skb,
UINT);
static void DWC_ETH_QOS_configure_rx_fun_ptr(struct DWC_ETH_QOS_prv_data
*pdata);
static int DWC_ETH_QOS_alloc_split_hdr_rx_buf(
struct DWC_ETH_QOS_prv_data *pdata,
struct DWC_ETH_QOS_rx_buffer *buffer,
UINT qinx, gfp_t gfp);
static int DWC_ETH_QOS_alloc_jumbo_rx_buf(struct DWC_ETH_QOS_prv_data *pdata,
struct DWC_ETH_QOS_rx_buffer *buffer, UINT qinx,
gfp_t gfp);
static int DWC_ETH_QOS_alloc_rx_buf(struct DWC_ETH_QOS_prv_data *pdata,
struct DWC_ETH_QOS_rx_buffer *buffer, UINT qinx,
gfp_t gfp);
static void DWC_ETH_QOS_default_common_confs(struct DWC_ETH_QOS_prv_data
*pdata);
static void DWC_ETH_QOS_default_tx_confs(struct DWC_ETH_QOS_prv_data *pdata);
static void DWC_ETH_QOS_default_tx_confs_single_q(struct DWC_ETH_QOS_prv_data
*pdata, UINT);
static void DWC_ETH_QOS_default_rx_confs(struct DWC_ETH_QOS_prv_data *pdata);
static void DWC_ETH_QOS_default_rx_confs_single_q(struct DWC_ETH_QOS_prv_data
*pdata, UINT);
int DWC_ETH_QOS_poll(struct DWC_ETH_QOS_prv_data *pdata, int budget, int qinx);
static void DWC_ETH_QOS_mmc_setup(struct DWC_ETH_QOS_prv_data *pdata);
inline unsigned int DWC_ETH_QOS_reg_read(volatile ULONG * ptr);
#ifdef DWC_ETH_QOS_QUEUE_SELECT_ALGO
u16 DWC_ETH_QOS_select_queue(struct net_device *dev, struct sk_buff *skb,
void *accel_priv, select_queue_fallback_t fallback);
#endif
static int DWC_ETH_QOS_vlan_rx_add_vid(
struct net_device *dev, __be16 proto, u16 vid);
static int DWC_ETH_QOS_vlan_rx_kill_vid(struct net_device *dev,
__be16 proto, u16 vid);
#endif

View File

@@ -0,0 +1,555 @@
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* =========================================================================
*/
/*!@file: DWC_ETH_QOS_eee.c
* @brief: Driver functions.
*/
#include "DWC_ETH_QOS_yheader.h"
/* Clause 22 registers to access clause 45 register set */
#define MMD_CTRL_REG 0x0D /* MMD Access Control Register */
#define MMD_ADDR_DATA_REG 0x0E /* MMD Access Address Data Register */
/* MMD Access Control register fields */
#define MMD_CTRL_FUNC_ADDR 0x0000 /* address */
#define MMD_CTRL_FUNC_DATA_NOINCR 0x4000 /* data, no post increment */
/* data, post increment on reads & writes */
#define MMD_CTRL_FUNC_DATA_INCR_ON_RDWT 0x8000
/* data, post increment on writes only */
#define MMD_CTRL_FUNC_DATA_INCR_ON_WT 0xC000
/* Clause 45 expansion register */
#define CL45_PCS_EEE_ABLE 0x14 /* EEE Capability register */
#define CL45_ADV_EEE_REG 0x3C /* EEE advertisement */
#define CL45_AN_EEE_LPABLE_REG 0x3D /* EEE Link Partner ability reg */
#define CL45_CLK_STOP_EN_REG 0x0 /* Clock Stop enable reg */
/* Clause 45 expansion registers fields */
/* LP EEE capabilities status */
#define CL45_LP_ADV_EEE_STATS_1000BASE_T 0x0004
#define CL45_CLK_STOP_EN 0x400 /* Enable xMII Clock Stop */
#define AR8035_SMART_EEE_CTRL_3 0x805D
#define AR8035_SMART_EEE_EN (1<<8)
#define PHY_RX_CLOCK_STOPPABLE_EN 1
#define PHY_RX_CLOCK_STOPPABLE_DIS 0
void DWC_ETH_QOS_enable_eee_mode(struct DWC_ETH_QOS_prv_data *pdata)
{
struct DWC_ETH_QOS_tx_wrapper_descriptor *tx_desc_data = NULL;
struct hw_if_struct *hw_if = &pdata->hw_if;
int tx_idle = 0, QINX;
DBGPR_EEE("-->DWC_ETH_QOS_enable_eee_mode\n");
for (QINX = 0; pdata->tx_queue_cnt > QINX ; QINX++) {
tx_desc_data = GET_TX_WRAPPER_DESC(QINX);
if ((tx_desc_data->dirty_tx == tx_desc_data->cur_tx) &&
(!pdata->tx_path_in_lpi_mode)) {
tx_idle = 1;
} else {
tx_idle = 0;
break;
}
}
if (tx_idle)
hw_if->set_eee_mode();
DBGPR_EEE("<--DWC_ETH_QOS_enable_eee_mode\n");
}
void DWC_ETH_QOS_disable_eee_mode(struct DWC_ETH_QOS_prv_data *pdata)
{
struct hw_if_struct *hw_if = &pdata->hw_if;
DBGPR_EEE("-->DWC_ETH_QOS_disable_eee_mode\n");
hw_if->reset_eee_mode();
del_timer_sync(&pdata->eee_ctrl_timer);
pdata->tx_path_in_lpi_mode = false;
pdata->eee_active = 0;
DBGPR_EEE("-->DWC_ETH_QOS_disable_eee_mode\n");
}
/*!
* \brief API to control EEE mode.
*
* \details This function will move the MAC transmitter in LPI mode
* if there is no data transfer and MAC is not already in LPI state.
*
* \param[in] data - data hook
*
* \return void
*/
static void DWC_ETH_QOS_eee_ctrl_timer(unsigned long data)
{
struct DWC_ETH_QOS_prv_data *pdata =
(struct DWC_ETH_QOS_prv_data *)data;
DBGPR_EEE("-->DWC_ETH_QOS_eee_ctrl_timer\n");
DWC_ETH_QOS_enable_eee_mode(pdata);
DBGPR_EEE("<--DWC_ETH_QOS_eee_ctrl_timer\n");
}
static void DWC_ETH_QOS_mmd_phy_indirect(struct mii_bus *bus,
int REGADDR,
int DEVADDR,
int PHYADDR)
{
/* Write the desired MMD devAddr */
bus->write(bus, PHYADDR, MMD_CTRL_REG, DEVADDR);
/* Write the desired MMD regAddr */
bus->write(bus, PHYADDR, MMD_ADDR_DATA_REG, REGADDR);
/* Select the Function : DATA with no post increment */
bus->write(bus, PHYADDR, MMD_CTRL_REG,
(DEVADDR | MMD_CTRL_FUNC_DATA_NOINCR));
}
/*!
* \brief API to read data from the MMD registers.
*
* \details This function will read data from the MMD(clause 45) registers
* using clause 22 registers. The procedure to read MMD registers is,
* 1. Write the desired MMD device addr into reg 13
* 2. Write the desired MMD reg addr into reg 14
* 3. Select the desired Function - MMD data command by writing in reg 13
* 4. Read the content of the MMD's selected reg through reg 14
*
* \param[in] bus - the target MII bus
* \param[in] regAddr - desired MMD reg addr to be read
* \param[in] devAddr - desired MMD address
* \param[in] phyAddr - PHY addr/id on the MII bus
*
* \return integer
*/
static int DWC_ETH_QOS_phy_read_mmd_indirect(struct mii_bus *bus,
int REGADDR,
int DEVADDR,
int PHYADDR)
{
u32 ret;
DBGPR_EEE("-->DWC_ETH_QOS_phy_read_mmd_indirect\n");
DWC_ETH_QOS_mmd_phy_indirect(bus, REGADDR, DEVADDR, PHYADDR);
/* read the content of the MMD's selected register */
ret = bus->read(bus, PHYADDR, MMD_ADDR_DATA_REG);
DBGPR_EEE("<--DWC_ETH_QOS_phy_read_mmd_indirect\n");
return ret;
}
/*!
* \brief API to write data into the MMD registers.
*
* \details This function will write data into MMD(clause 45) registers
* using clause 22 registers. The procedure to write MMD registers is,
* 1. Write the desired MMD device addr into reg 13
* 2. Write the desired MMD reg addr into reg 14
* 3. Select the desired Function - MMD data command by writing in reg 13
* 4. Write the data into MMD's selected reg through reg 14
*
* \param[in] bus - the target MII bus
* \param[in] regAddr - desired MMD reg addr to be written
* \param[in] devAddr - desired MMD address
* \param[in] phyAddr - PHY addr/id on the MII bus
* \param[in] data - data to write into the MMD register
*
* \return void
*/
static void DWC_ETH_QOS_phy_write_mmd_indirect(struct mii_bus *bus,
int REGADDR,
int DEVADDR,
int PHYADDR,
u32 data)
{
DBGPR_EEE("-->DWC_ETH_QOS_phy_write_mmd_indirect\n");
DWC_ETH_QOS_mmd_phy_indirect(bus, REGADDR, DEVADDR, PHYADDR);
/* Write the data into MMD's selected register */
bus->write(bus, PHYADDR, MMD_ADDR_DATA_REG, data);
DBGPR_EEE("<--DWC_ETH_QOS_phy_write_mmd_indirect\n");
}
#if 0
#define MDIO_EEE_100TX 0x0002 /* EEE is supported for 100BASE-TX */
#define MDIO_EEE_1000T 0x0004 /* EEE is supported for 1000BASE-T */
#define MDIO_EEE_10GT 0x0008 /* EEE is supported for 10GBASE-T */
#define MDIO_EEE_1000KX 0x0010 /* EEE is supported for 1000BASE-KX */
#define MDIO_EEE_10GKX4 0x0020 /* EEE is supported for 10GBASE-KX4 */
#define MDIO_EEE_10GKR 0x0040 /* EEE is supported for 10GBASE KR */
/* A small helper function that translates MMD EEE Capability (3.20) bits
* to ethtool supported settings.
*/
static u32 DWC_ETH_QOS_mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap)
{
u32 supported = 0;
if (eee_cap & MDIO_EEE_100TX)
supported |= SUPPORTED_100baseT_Full;
if (eee_cap & MDIO_EEE_1000T)
supported |= SUPPORTED_1000baseT_Full;
if (eee_cap & MDIO_EEE_10GT)
supported |= SUPPORTED_10000baseT_Full;
if (eee_cap & MDIO_EEE_1000KX)
supported |= SUPPORTED_1000baseKX_Full;
if (eee_cap & MDIO_EEE_10GKX4)
supported |= SUPPORTED_10000baseKX4_Full;
if (eee_cap & MDIO_EEE_10GKR)
supported |= SUPPORTED_10000baseKR_Full;
return supported;
}
/* A small helper function that translates the MMD EEE Advertisment (7.60)
* and MMD EEE Link Partner Ability (7.61) bits to ethtool advertisement
* settings.
*/
static inline u32 DWC_ETH_QOS_mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv)
{
u32 adv = 0;
if (eee_adv & MDIO_EEE_100TX)
adv |= ADVERTISED_100baseT_Full;
if (eee_adv & MDIO_EEE_1000T)
adv |= ADVERTISED_1000baseT_Full;
if (eee_adv & MDIO_EEE_10GT)
adv |= ADVERTISED_10000baseT_Full;
if (eee_adv & MDIO_EEE_1000KX)
adv |= ADVERTISED_1000baseKX_Full;
if (eee_adv & MDIO_EEE_10GKX4)
adv |= ADVERTISED_10000baseKX4_Full;
if (eee_adv & MDIO_EEE_10GKR)
adv |= ADVERTISED_10000baseKR_Full;
return adv;
}
#endif
/*!
* \brief API to disable EEE mode.
*
* \details This function disable smart EEE
* \param[in] phydev - pointer to target phy_device structure
*/
static void DWC_ETH_QOS_disable_smart_eee(struct phy_device *phydev)
{
u32 smart_eee;
smart_eee = DWC_ETH_QOS_phy_read_mmd_indirect(
phydev->mdio.bus, AR8035_SMART_EEE_CTRL_3,
MDIO_MMD_PCS, phydev->mdio.addr);
smart_eee &= ~AR8035_SMART_EEE_EN;
DWC_ETH_QOS_phy_write_mmd_indirect(
phydev->mdio.bus, AR8035_SMART_EEE_CTRL_3,
MDIO_MMD_PCS,phydev->mdio.addr, smart_eee);
}
/*!
* \brief API to initialize and check EEE mode.
*
* \details This function checks if the EEE is supported by
* looking at the MMD registers and it also programs the MMD
* register 3.0 setting the "Clock stop enable" bit if required.
*
* \param[in] phydev - pointer to target phy_device structure
* \param[in] clk_stop_enable - PHY may stop the clock during LPI
*
* \return integer
*
* \retval zero if EEE is supported else return -ve number.
*/
static int DWC_ETH_QOS_phy_init_eee(struct phy_device *phydev,
bool clk_stop_enable)
{
int ret = -EPROTONOSUPPORT;
DBGPR_EEE("-->DWC_ETH_QOS_phy_init_eee\n");
/* According to 802.3az,the EEE is supported only in full duplex-mode.
* Also EEE feature is active when core is operating with MII, GMII,
* SGMII or RGMII.
*/
if ((phydev->duplex == DUPLEX_FULL) &&
((phydev->interface == PHY_INTERFACE_MODE_MII) ||
(phydev->interface == PHY_INTERFACE_MODE_GMII) ||
(phydev->interface == PHY_INTERFACE_MODE_SGMII) ||
(phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
int eee_lp, eee_cap, eee_adv;
/*u32 cap,lp , adv;*/
int status;/*, idx;*/
/* Read phy status to properly get the right settings */
status = phy_read_status(phydev);
if (status)
return status;
/* First check if the EEE ability is supported */
eee_cap = DWC_ETH_QOS_phy_read_mmd_indirect(
phydev->mdio.bus,
CL45_PCS_EEE_ABLE, MDIO_MMD_PCS,phydev->mdio.addr);
if (eee_cap < 0)
return eee_cap;
if (eee_cap == 0)
return -1;
/* cap = DWC_ETH_QOS_mmd_eee_cap_to_ethtool_sup_t(eee_cap);
* if (!cap)
* goto eee_exit;
*/
/* check whether link Partner support EEE or not */
eee_lp = DWC_ETH_QOS_phy_read_mmd_indirect(
phydev->mdio.bus,
CL45_AN_EEE_LPABLE_REG, MDIO_MMD_AN,phydev->mdio.addr);
if (eee_lp < 0)
return eee_lp;
if (eee_lp == 0)
return -1;
eee_adv = DWC_ETH_QOS_phy_read_mmd_indirect(
phydev->mdio.bus,
CL45_ADV_EEE_REG, MDIO_MMD_AN,phydev->mdio.addr);
if (eee_adv < 0)
return eee_adv;
if (eee_adv == 0)
return -1;
/* TODO:check this
* adv = DWC_ETH_QOS_mmd_eee_adv_to_ethtool_adv_t(eee_adv);
* lp = DWC_ETH_QOS_mmd_eee_adv_to_ethtool_adv_t(eee_lp);
* idx = phy_find_setting(phydev->speed, phydev->duplex);
* if ((lp & adv & settings[idx].setting))
goto eee_exit;
*/
if (clk_stop_enable) {
/* Configure the PHY to stop receiving xMII
* clock while it is signaling LPI.
*/
int val = DWC_ETH_QOS_phy_read_mmd_indirect(phydev->mdio.bus,
CL45_CLK_STOP_EN_REG, MDIO_MMD_PCS,
phydev->mdio.addr);
if (val < 0)
return val;
val |= CL45_CLK_STOP_EN;
DWC_ETH_QOS_phy_write_mmd_indirect(
phydev->mdio.bus, CL45_CLK_STOP_EN_REG, MDIO_MMD_PCS,
phydev->mdio.addr, val);
}
/* Disable smart EEE feature in AR8035*/
if (phydev->phy_id == ATH8035_PHY_ID || phydev->phy_id == ATH8030_PHY_ID) {
DWC_ETH_QOS_disable_smart_eee(phydev);
}
ret = 0; /* EEE supported */
}
DBGPR_EEE("<--DWC_ETH_QOS_phy_init_eee\n");
/*eee_exit:*/
return ret;
}
/*!
* \brief API to initialize EEE mode.
*
* \details This function enables the LPI state and start the timer
* to verify whether the tx path can enter in LPI state if
* a. GMAC supports EEE mode &
* b. phy can also manage EEE.
*
* \param[in] pdata - pointer to private data structure
*
* \return bool
*
* \retval true on success & false on failure.
*/
bool DWC_ETH_QOS_eee_init(struct DWC_ETH_QOS_prv_data *pdata)
{
struct hw_if_struct *hw_if;
bool ret = false;
EMACDBG("Enter\n");
hw_if = &pdata->hw_if;
/* Disable smart EEE & EEE for ATH8030*/
if ((pdata->emac_hw_version_type == EMAC_HW_v2_3_1)
&& (pdata->io_macro_phy_intf == RMII_MODE) &&
pdata->phydev->phy_id == ATH8030_PHY_ID) {
//disable smart EEE
DWC_ETH_QOS_disable_smart_eee(pdata->phydev);
EMACDBG("disable smart EEE for 8030\n");
}
/* For RMII mode EEE is not supported */
if (pdata->io_macro_phy_intf == RMII_MODE)
goto phy_eee_failed;
/* HW supports the EEE feature */
if (pdata->hw_feat.eee_sel) {
#ifndef DWC_ETH_QOS_CUSTOMIZED_EEE_TEST
/* check if the PHY supports EEE */
if (!pdata->phydev || !pdata->phydev->link
|| DWC_ETH_QOS_phy_init_eee(pdata->phydev, PHY_RX_CLOCK_STOPPABLE_DIS))
goto phy_eee_failed;
#endif /* DWC_ETH_QOS_CUSTOMIZED_EEE_TEST */
if (!pdata->eee_active) {
pdata->eee_active = 1;
if (pdata->use_lpi_auto_entry_timer) {
pdata->hw_if.set_lpi_us_tic_counter(CLOCK_AHB_MHZ);
hw_if->set_lpi_tx_auto_entry_timer(DWC_ETH_QOS_DEFAULT_LPI_LPIET_TIMER);
hw_if->set_eee_timer(DWC_ETH_QOS_DEFAULT_LPI_LS_TIMER,
DWC_ETH_QOS_DEFAULT_LPI_TWT_TIMER);
hw_if->set_lpi_tx_automate();
hw_if->set_lpi_tx_auto_entry_timer_en();
hw_if->set_eee_mode();
hw_if->set_eee_pls(pdata->phydev->link);
} else {
init_timer(&pdata->eee_ctrl_timer);
pdata->eee_ctrl_timer.function =
DWC_ETH_QOS_eee_ctrl_timer;
pdata->eee_ctrl_timer.data = (unsigned long)pdata;
pdata->eee_ctrl_timer.expires =
DWC_ETH_QOS_LPI_TIMER(
DWC_ETH_QOS_DEFAULT_LPI_TIMER);
add_timer(&pdata->eee_ctrl_timer);
hw_if->set_eee_timer(DWC_ETH_QOS_DEFAULT_LPI_LS_TIMER,
DWC_ETH_QOS_DEFAULT_LPI_TWT_TIMER);
if (pdata->use_lpi_tx_automate)
hw_if->set_lpi_tx_automate();
}
} else {
/* When EEE has been already initialized we have to
* modify the PLS bit in MAC_LPI_Control_Status reg
* according to PHY link status.
*/
hw_if->set_eee_pls(pdata->phydev->link);
}
DBGPR_EEE("EEE initialized\n");
ret = true;
}
return ret;
#ifndef DWC_ETH_QOS_CUSTOMIZED_EEE_TEST
phy_eee_failed:
/* In case of failure, reset the PHY link status in MAC_LPI_Control_Status reg */
hw_if->set_eee_pls(0);
/* Disable EEE mode */
if (pdata->eee_active) {
hw_if->reset_eee_mode();
pdata->eee_active = 0;
}
#endif
EMACDBG("Exit\n");
return ret;
}
#define MAC_LPS_TLPIEN 0x00000001
#define MAC_LPS_TLPIEX 0x00000002
#define MAC_LPS_RLPIEN 0x00000004
#define MAC_LPS_RLPIEX 0x00000008
void DWC_ETH_QOS_handle_eee_interrupt(struct DWC_ETH_QOS_prv_data *pdata)
{
struct hw_if_struct *hw_if = &pdata->hw_if;
u32 lpi_status;
DBGPR_EEE("-->DWC_ETH_QOS_handle_eee_interrupt\n");
lpi_status = hw_if->get_lpi_status();
DBGPR_EEE("MAC_LPI_Control_Status = %#x\n", lpi_status);
if (lpi_status & MAC_LPS_TLPIEN) {
pdata->tx_path_in_lpi_mode = 1;
pdata->xstats.tx_path_in_lpi_mode_irq_n++;
DBGPR_EEE("MAC Transmitter has entered the LPI state\n");
}
if (lpi_status & MAC_LPS_TLPIEX) {
pdata->tx_path_in_lpi_mode = 0;
pdata->xstats.tx_path_exit_lpi_mode_irq_n++;
DBGPR_EEE("MAC Transmitter has exited the LPI state\n");
}
if (lpi_status & MAC_LPS_RLPIEN) {
pdata->xstats.rx_path_in_lpi_mode_irq_n++;
DBGPR_EEE("MAC Receiver has entered the LPI state\n");
}
if (lpi_status & MAC_LPS_RLPIEX) {
pdata->xstats.rx_path_exit_lpi_mode_irq_n++;
DBGPR_EEE("MAC Receiver has exited the LPI state\n");
}
DBGPR_EEE("<--DWC_ETH_QOS_handle_eee_interrupt\n");
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* =========================================================================
*/
#ifndef __DWC_ETH_QOS_ETHTOOL_H__
#define __DWC_ETH_QOS_ETHTOOL_H__
static void DWC_ETH_QOS_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause);
static int DWC_ETH_QOS_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause);
static int DWC_ETH_QOS_getsettings(struct net_device *dev,
struct ethtool_cmd *cmd);
static int DWC_ETH_QOS_setsettings(struct net_device *dev,
struct ethtool_cmd *cmd);
static void DWC_ETH_QOS_get_wol(struct net_device *dev,
struct ethtool_wolinfo *wol);
static int DWC_ETH_QOS_set_wol(struct net_device *dev,
struct ethtool_wolinfo *wol);
static int DWC_ETH_QOS_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec);
static int DWC_ETH_QOS_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *ec);
static int DWC_ETH_QOS_get_sset_count(struct net_device *dev, int sset);
static void DWC_ETH_QOS_get_strings(struct net_device *dev, u32 stringset,
u8 *data);
static void DWC_ETH_QOS_get_ethtool_stats(
struct net_device *dev,
struct ethtool_stats *dummy, u64 *data);
#ifdef DWC_ETH_QOS_CONFIG_PTP
static int DWC_ETH_QOS_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info);
#endif /* end of DWC_ETH_QOS_CONFIG_PTP */
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/
#ifndef __DWC_ETH_QOS_IPA_H__
#define __DWC_ETH_QOS_IPA_H__
#include <linux/ipa.h>
#include <linux/ipa_uc_offload.h>
#include <asm/io.h>
#include <linux/debugfs.h>
#include <linux/in.h>
#include <linux/ip.h>
#include "DWC_ETH_QOS_yheader.h"
#include "DWC_ETH_QOS_yregacc.h"
#include "DWC_ETH_QOS_yrgmii_io_macro_regacc.h"
typedef enum {
EV_INVALID = 0,
EV_DEV_OPEN,
EV_DEV_CLOSE,
EV_IPA_READY,
EV_IPA_UC_READY,
EV_PHY_LINK_UP,
EV_PHY_LINK_DOWN,
EV_DPM_SUSPEND,
EV_DPM_RESUME,
EV_USR_SUSPEND,
EV_USR_RESUME,
EV_IPA_OFFLOAD_MAX,
} IPA_OFFLOAD_EVENT;
#ifdef DWC_ETH_QOS_ENABLE_IPA
#define EMAC_IPA_CAPABLE 1
void DWC_ETH_QOS_ipa_offload_event_handler(
struct DWC_ETH_QOS_prv_data *pdata, IPA_OFFLOAD_EVENT ev);
int DWC_ETH_QOS_disable_enable_ipa_offload(struct DWC_ETH_QOS_prv_data *pdata,int chInx_tx_ipa,
int chInx_rx_ipa);
void DWC_ETH_QOS_ipa_stats_read(struct DWC_ETH_QOS_prv_data *pdata);
#else /* DWC_ETH_QOS_ENABLE_IPA */
#define EMAC_IPA_CAPABLE 0
static inline void DWC_ETH_QOS_ipa_offload_event_handler(
struct DWC_ETH_QOS_prv_data *pdata, IPA_OFFLOAD_EVENT ev)
{
return;
}
static inline int DWC_ETH_QOS_disable_enable_ipa_offload(struct DWC_ETH_QOS_prv_data *pdata,
int chInx_tx_ipa, int chInx_rx_ipa)
{
return -EPERM;
}
static inline void DWC_ETH_QOS_ipa_stats_read(struct DWC_ETH_QOS_prv_data *pdata)
{
return;
}
#endif /* DWC_ETH_QOS_ENABLE_IPA */
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
/*Copyright (c) 2019, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
/*!@file: DWC_ETH_QOS_poll_support.c
*/
#include "DWC_ETH_QOS_yheader.h"
#define AVB_CLASS_A_CHANNEL_NUM 2
#define AVB_CLASS_B_CHANNEL_NUM 3
extern struct DWC_ETH_QOS_prv_data *gDWC_ETH_QOS_prv_data;
struct pps_info {
int channel_no;
};
bool avb_class_a_msg_wq_flag;
bool avb_class_b_msg_wq_flag;
DECLARE_WAIT_QUEUE_HEAD(avb_class_a_msg_wq);
DECLARE_WAIT_QUEUE_HEAD(avb_class_b_msg_wq);
static ssize_t pps_fops_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
unsigned int len = 0, buf_len = 5000;
char* temp_buf;
ssize_t ret_cnt = 0;
struct pps_info *info;
info = filp->private_data;
if (info->channel_no == AVB_CLASS_A_CHANNEL_NUM ) {
temp_buf = kzalloc(buf_len, GFP_KERNEL);
if (!temp_buf)
return -ENOMEM;
if (gDWC_ETH_QOS_prv_data)
len = scnprintf(temp_buf, buf_len ,
"%ld\n", gDWC_ETH_QOS_prv_data->avb_class_a_intr_cnt);
else
len = scnprintf(temp_buf, buf_len , "0\n");
ret_cnt = simple_read_from_buffer(buf, count, f_pos, temp_buf, len);
kfree(temp_buf);
if (gDWC_ETH_QOS_prv_data)
EMACERR("poll pps2intr info=%d sent by kernel\n", gDWC_ETH_QOS_prv_data->avb_class_a_intr_cnt);
} else if (info->channel_no == AVB_CLASS_B_CHANNEL_NUM ) {
temp_buf = kzalloc(buf_len, GFP_KERNEL);
if (!temp_buf)
return -ENOMEM;
if (gDWC_ETH_QOS_prv_data)
len = scnprintf(temp_buf, buf_len ,
"%ld\n", gDWC_ETH_QOS_prv_data->avb_class_b_intr_cnt);
else
len = scnprintf(temp_buf, buf_len , "0\n");
ret_cnt = simple_read_from_buffer(buf, count, f_pos, temp_buf, len);
kfree(temp_buf);
} else {
EMACERR("invalid channel %d\n",info->channel_no);
}
return ret_cnt;
}
static unsigned int pps_fops_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
struct pps_info *info;
info = file->private_data;
if (info->channel_no == AVB_CLASS_A_CHANNEL_NUM ){
EMACDBG("avb_class_a_fops_poll wait\n");
poll_wait(file, &avb_class_a_msg_wq, wait);
EMACDBG("avb_class_a_fops_poll exit\n");
if (avb_class_a_msg_wq_flag == 1) {
//Sending read mask
mask |= POLLIN | POLLRDNORM;
avb_class_a_msg_wq_flag = 0;
}
} else if (info->channel_no == AVB_CLASS_B_CHANNEL_NUM) {
EMACDBG("avb_class_b_fops_poll wait\n");
poll_wait(file, &avb_class_b_msg_wq, wait);
EMACDBG("avb_class_b_fops_poll exit\n");
if (avb_class_b_msg_wq_flag == 1) {
//Sending read mask
mask |= POLLIN | POLLRDNORM;
avb_class_b_msg_wq_flag = 0;
}
} else {
EMACERR("invalid channel %d\n",info->channel_no);
}
return mask;
}
int pps_open(struct inode *inode, struct file *file)
{
struct pps_info *info;
EMACDBG("pps_open enter\n");
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
if (!strncmp(file->f_path.dentry->d_iname, AVB_CLASS_A_POLL_DEV_NODE_NAME , strlen (AVB_CLASS_A_POLL_DEV_NODE_NAME))) {
EMACDBG("pps_open file name =%s \n",file->f_path.dentry->d_iname);
info->channel_no = AVB_CLASS_A_CHANNEL_NUM;
} else if (!strncmp(file->f_path.dentry->d_iname, AVB_CLASS_B_POLL_DEV_NODE_NAME , strlen (AVB_CLASS_B_POLL_DEV_NODE_NAME))) {
EMACDBG("pps_open file name =%s \n",file->f_path.dentry->d_iname);
info->channel_no = AVB_CLASS_B_CHANNEL_NUM;
} else {
EMACDBG("stsrncmp failed for %s\n",file->f_path.dentry->d_iname);
}
file->private_data = info;
return 0;
}
int pps_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static const struct file_operations pps_fops = {
.owner = THIS_MODULE,
.open = pps_open,
.release = pps_release,
.read = pps_fops_read,
.poll = pps_fops_poll,
};
int create_pps_interrupt_info_device_node(dev_t *pps_dev_t, struct cdev** pps_cdev,
struct class** pps_class, char *pps_dev_node_name)
{
int ret;
EMACDBG("create_pps_interrupt_info_device_node enter \n");
ret = alloc_chrdev_region(pps_dev_t, 0, 1,
pps_dev_node_name);
if (ret) {
EMACERR("alloc_chrdev_region error for node %s \n", pps_dev_node_name);
goto alloc_chrdev1_region_fail;
}
*pps_cdev = cdev_alloc();
if(!*pps_cdev) {
ret = -ENOMEM;
EMACERR("failed to alloc cdev\n");
goto fail_alloc_cdev;
}
cdev_init(*pps_cdev, &pps_fops);
ret = cdev_add(*pps_cdev, *pps_dev_t, 1);
if (ret < 0) {
EMACERR(":cdev_add err=%d\n", -ret);
goto cdev1_add_fail;
}
*pps_class = class_create(THIS_MODULE, pps_dev_node_name);
if(!*pps_class) {
ret = -ENODEV;
EMACERR("failed to create class\n");
goto fail_create_class;
}
if (!device_create(*pps_class, NULL,
*pps_dev_t, NULL, pps_dev_node_name)) {
ret = -EINVAL;
EMACERR("failed to create device_create\n");
goto fail_create_device;
}
EMACDBG("create_pps_interrupt_info_device_node exit successfuly \n");
return 0;
fail_create_device:
class_destroy(*pps_class);
fail_create_class:
cdev_del(*pps_cdev);
cdev1_add_fail:
fail_alloc_cdev:
unregister_chrdev_region(*pps_dev_t, 1);
alloc_chrdev1_region_fail:
return ret;
}
int remove_pps_interrupt_info_device_node(struct DWC_ETH_QOS_prv_data *pdata)
{
cdev_del(pdata->avb_class_a_cdev);
device_destroy(pdata->avb_class_a_class, pdata->avb_class_a_dev_t);
class_destroy(pdata->avb_class_a_class);
unregister_chrdev_region(pdata->avb_class_a_dev_t, 1);
pdata->avb_class_a_cdev = NULL;
pdata->avb_class_a_class = NULL;
cdev_del(pdata->avb_class_b_cdev);
device_destroy(pdata->avb_class_b_class, pdata->avb_class_b_dev_t);
class_destroy(pdata->avb_class_b_class);
unregister_chrdev_region(pdata->avb_class_b_dev_t, 1);
pdata->avb_class_b_cdev = NULL;
pdata->avb_class_b_class = NULL;
return 0;
}

View File

@@ -0,0 +1,381 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* =========================================================================
*/
/*!@file: DWC_ETH_QOS_ptp.c
* @brief: Driver functions.
*/
#include "DWC_ETH_QOS_yheader.h"
#include "DWC_ETH_QOS_yapphdr.h"
#ifdef CONFIG_PPS_OUTPUT
extern int ETH_PPSOUT_Config(struct DWC_ETH_QOS_prv_data *pdata, struct ifr_data_struct* req);
extern void DWC_ETH_QOS_pps_timer_init(struct ifr_data_struct* req);
#endif
/*!
* \brief API to adjust the frequency of hardware clock.
*
* \details This function is used to adjust the frequency of the
* hardware clock.
*
* \param[in] ptp pointer to ptp_clock_info structure.
* \param[in] delta desired period change in parts per billion.
*
* \return int
*
* \retval 0 on success and -ve number on failure.
*/
static int DWC_ETH_QOS_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
{
struct DWC_ETH_QOS_prv_data *pdata =
container_of(ptp, struct DWC_ETH_QOS_prv_data, ptp_clock_ops);
struct hw_if_struct *hw_if = &pdata->hw_if;
unsigned long flags;
u64 adj;
u32 diff, addend;
int neg_adj = 0;
DBGPR_PTP("-->DWC_ETH_QOS_adjust_freq: %d\n", ppb);
if (ppb < 0) {
neg_adj = 1;
ppb = -ppb;
}
addend = pdata->default_addend;
adj = addend;
adj *= ppb;
/* div_u64 will divided the "adj" by "1000000000ULL"
* and return the quotient.
*/
diff = div_u64(adj, 1000000000ULL);
addend = neg_adj ? (addend - diff) : (addend + diff);
spin_lock_irqsave(&pdata->ptp_lock, flags);
hw_if->config_addend(addend);
spin_unlock_irqrestore(&pdata->ptp_lock, flags);
DBGPR_PTP("<--DWC_ETH_QOS_adjust_freq\n");
return 0;
}
/*!
* \brief API to adjust the hardware time.
*
* \details This function is used to shift/adjust the time of the
* hardware clock.
*
* \param[in] ptp pointer to ptp_clock_info structure.
* \param[in] delta desired change in nanoseconds.
*
* \return int
*
* \retval 0 on success and -ve number on failure.
*/
static int DWC_ETH_QOS_adjust_time(struct ptp_clock_info *ptp, s64 delta)
{
struct DWC_ETH_QOS_prv_data *pdata =
container_of(ptp, struct DWC_ETH_QOS_prv_data, ptp_clock_ops);
struct hw_if_struct *hw_if = &pdata->hw_if;
unsigned long flags;
u32 sec, nsec;
u32 quotient, reminder;
int neg_adj = 0;
DBGPR_PTP("-->DWC_ETH_QOS_adjust_time: delta = %lld\n", delta);
if (delta < 0) {
neg_adj = 1;
delta = -delta;
}
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
sec = quotient;
nsec = reminder;
spin_lock_irqsave(&pdata->ptp_lock, flags);
hw_if->adjust_systime(sec, nsec, neg_adj, pdata->one_nsec_accuracy);
spin_unlock_irqrestore(&pdata->ptp_lock, flags);
DBGPR_PTP("<--DWC_ETH_QOS_adjust_time\n");
return 0;
}
/*!
* \brief API to get the current time.
*
* \details This function is used to read the current time from the
* hardware clock.
*
* \param[in] ptp pointer to ptp_clock_info structure.
* \param[in] ts pointer to hold the time/result.
*
* \return int
*
* \retval 0 on success and -ve number on failure.
*/
static int DWC_ETH_QOS_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct DWC_ETH_QOS_prv_data *pdata =
container_of(ptp, struct DWC_ETH_QOS_prv_data, ptp_clock_ops);
struct hw_if_struct *hw_if = &pdata->hw_if;
u64 ns;
u32 reminder;
unsigned long flags;
DBGPR_PTP("-->DWC_ETH_QOS_get_time\n");
spin_lock_irqsave(&pdata->ptp_lock, flags);
ns = hw_if->get_systime();
spin_unlock_irqrestore(&pdata->ptp_lock, flags);
ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &reminder);
ts->tv_nsec = reminder;
DBGPR_PTP("<--DWC_ETH_QOS_get_time: ts->tv_sec = %ld,", ts->tv_sec);
DBGPR_PTP("ts->tv_nsec = %ld\n", ts->tv_nsec);
return 0;
}
/*!
* \brief API to set the current time.
*
* \details This function is used to set the current time on the
* hardware clock.
*
* \param[in] ptp pointer to ptp_clock_info structure.
* \param[in] ts time value to set.
*
* \return int
*
* \retval 0 on success and -ve number on failure.
*/
static int DWC_ETH_QOS_set_time(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct DWC_ETH_QOS_prv_data *pdata =
container_of(ptp, struct DWC_ETH_QOS_prv_data, ptp_clock_ops);
struct hw_if_struct *hw_if = &pdata->hw_if;
unsigned long flags;
DBGPR_PTP("-->DWC_ETH_QOS_set_time: ts->tv_sec = %ld,", ts->tv_sec);
DBGPR_PTP("ts->tv_nsec = %ld\n", ts->tv_nsec);
spin_lock_irqsave(&pdata->ptp_lock, flags);
hw_if->init_systime(ts->tv_sec, ts->tv_nsec);
spin_unlock_irqrestore(&pdata->ptp_lock, flags);
DBGPR_PTP("<--DWC_ETH_QOS_set_time\n");
return 0;
}
/*!
* \brief API to enable/disable an ancillary feature.
*
* \details This function is used to enable or disable an ancillary
* device feature like PPS, PEROUT and EXTTS.
*
* \param[in] ptp pointer to ptp_clock_info structure.
* \param[in] rq desired resource to enable or disable.
* \param[in] on caller passes one to enable or zero to disable.
*
* \return int
*
* \retval 0 on success and -ve(EINVAL or EOPNOTSUPP) number on failure.
*/
static int DWC_ETH_QOS_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
/* structure describing a PTP hardware clock.
*/
static struct ptp_clock_info DWC_ETH_QOS_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "DWC_ETH_QOS_clk",
.max_adj = DWC_ETH_QOS_SYSCLOCK,
/* the max possible frequency adjustment, in parts per billion */
.n_alarm = 0, /* the number of programmable alarms */
.n_ext_ts = 0, /* the number of externel time stamp channels */
.n_per_out = 0, /* the number of programmable periodic signals */
.pps = 0, /* indicates whether the clk supports a PPS callback */
.adjfreq = DWC_ETH_QOS_adjust_freq,
.adjtime = DWC_ETH_QOS_adjust_time,
.gettime64 = DWC_ETH_QOS_get_time,
.settime64 = DWC_ETH_QOS_set_time,
.enable = DWC_ETH_QOS_enable,
};
/*!
* \brief API to register ptp clock driver.
*
* \details This function is used to register the ptp clock
* driver to kernel. It also does some housekeeping work.
*
* \param[in] pdata pointer to private data structure.
*
* \return int
*
* \retval 0 on success and -ve number on failure.
*/
int DWC_ETH_QOS_ptp_init(struct DWC_ETH_QOS_prv_data *pdata)
{
int ret = 0;
#ifdef CONFIG_PPS_OUTPUT
struct ifr_data_struct req = {0};
struct ETH_PPS_Config eth_pps_cfg = {0};
#endif
DBGPR_PTP("-->DWC_ETH_QOS_ptp_init\n");
if (!pdata->hw_feat.tsstssel) {
ret = -1;
pdata->ptp_clock = NULL;
pr_alert("No PTP supports in HW\n"
"Aborting PTP clock driver registration\n");
goto no_hw_ptp;
}
DWC_ETH_QOS_enable_ptp_clk(&pdata->pdev->dev);
spin_lock_init(&pdata->ptp_lock);
pdata->ptp_clock_ops = DWC_ETH_QOS_ptp_clock_ops;
pdata->ptp_clock = ptp_clock_register(&pdata->ptp_clock_ops,
&pdata->pdev->dev);
if (IS_ERR(pdata->ptp_clock)) {
pdata->ptp_clock = NULL;
pr_alert("ptp_clock_register() failed\n");
} else {
pr_alert("Added PTP HW clock successfully\n");
}
#ifdef CONFIG_PPS_OUTPUT
if (pdata->res_data->pps_lpass_conn_en) {
/*Configuring PPS0 PPS output frequency to defualt 19.2 Mhz*/
eth_pps_cfg.ppsout_ch = 0;
eth_pps_cfg.ptpclk_freq = DWC_ETH_QOS_DEFAULT_PTP_CLOCK;
eth_pps_cfg.ppsout_freq = DWC_ETH_QOS_DEFAULT_LPASS_PPS_FREQUENCY;
eth_pps_cfg.ppsout_start = 1;
eth_pps_cfg.ppsout_duty = 50;
req.ptr = (void*)&eth_pps_cfg;
DWC_ETH_QOS_pps_timer_init(&req);
ret = ETH_PPSOUT_Config(pdata, &req);
}
#endif
DBGPR_PTP("<--DWC_ETH_QOS_ptp_init\n");
return ret;
no_hw_ptp:
return ret;
}
/*!
* \brief API to unregister ptp clock driver.
*
* \details This function is used to remove/unregister the ptp
* clock driver from the kernel.
*
* \param[in] pdata pointer to private data structure.
*
* \return void
*/
void DWC_ETH_QOS_ptp_remove(struct DWC_ETH_QOS_prv_data *pdata)
{
DBGPR_PTP("-->DWC_ETH_QOS_ptp_remove\n");
if (pdata->ptp_clock) {
ptp_clock_unregister(pdata->ptp_clock);
pr_alert("Removed PTP HW clock successfully\n");
}
DWC_ETH_QOS_disable_ptp_clk(&pdata->pdev->dev);
DBGPR_PTP("<--DWC_ETH_QOS_ptp_remove\n");
}
/*!
* \brief API to find the PHC index.
*
* \details This function is used to find the PHC index from Linux subsystem
*
* \param[in] pdata ??? pointer to private data structure.
*
* \return void
*/
int DWC_ETH_QOS_phc_index(struct DWC_ETH_QOS_prv_data *pdata)
{
DBGPR_PTP("Fetching PHC index \n");
if (pdata->ptp_clock)
return ptp_clock_index(pdata->ptp_clock);
else
return -1;
}

View File

@@ -0,0 +1,680 @@
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
/*!@file: DWC_ETH_QOS_rgmii_io_macro.c
* @brief: RGMII IO MACRO functions.
*/
#include "DWC_ETH_QOS_yheader.h"
#include "DWC_ETH_QOS_yrgmii_io_macro_regacc.h"
/* RGMII IO MACRO power on reset values */
#define RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX 0
#define SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX 1
#define SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX 2
#define SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX 3
#define SDCC_USR_CTL_POR_ARR_INDEX 4
#define RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX 5
#define RGMII_IO_MACRO_DLL_POR_NUM_OF_REGS 6
#define RGMII_IO_MACRO_DLL_POR_REG_OFFSET_INDEX 0
#define RGMII_IO_MACRO_DLL_POR_REG_DATA_INDEX 1
ULONG rgmii_io_macro_dll_por_values
[EMAC_HW_vMAX][RGMII_IO_MACRO_DLL_POR_NUM_OF_REGS][2] = {
[EMAC_HW_None] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x0 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x0 },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x0 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x0 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x0 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x0 },
},
[EMAC_HW_v2_0_0] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00000000 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_1_0] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00010800 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_1_1] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00000000 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_1_2] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00000000 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_2_0] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x00C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x6004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00010800 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_3_0] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x00C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00010800 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_3_1] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00000000 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
[EMAC_HW_v2_3_2] = {
[RGMII_IO_MACRO_CONFIG_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET, 0x40C01343 },
[SDCC_HC_REG_DLL_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET, 0x2004642C },
[SDCC_HC_REG_DDR_CONFIG_POR_ARR_INDEX] = { SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET, 0x00000000 },
[SDCC_HC_REG_DLL_CONFIG_2_POR_ARR_INDEX] = { SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET, 0x00200000 },
[SDCC_USR_CTL_POR_ARR_INDEX] = { SDCC_USR_CTL_RGOFFADDR_OFFSET, 0x00000000 },
[RGMII_IO_MACRO_CONFIG_2_POR_ARR_INDEX] = { RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET, 0x00002060 },
},
};
/* SDCDC DLL initialization */
/*!
* \brief Initialize the SDCDC
*
* \details This function will write to the various fields in
* SDCC_HC_REG_DLL_CONFIG register for the DLL
* initialization
*\return Y_SUCCESS
*/
int DWC_ETH_QOS_rgmii_io_macro_sdcdc_init(struct DWC_ETH_QOS_prv_data *pdata)
{
int reg_val = 0;
ULONG RETRYCOUNT = 1000;
ULONG current_cnt = 0;
volatile ULONG VARDLL_LOCK;
EMACDBG("Enter\n");
/* Write 1 to DLL_RST bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_DLL_RST_UDFWR(0x1);
/* Write 1 to PDN bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_PDN_UDFWR(0x1);
/* Write 0 to DLL_RST bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_DLL_RST_UDFWR(0x0);
/* Write 0 to PDN bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_PDN_UDFWR(0x0);
/* DLL RST=0 and PDN=0 are sufficient for RGMII_ID 10/100 Mbps mode */
if (pdata->speed == SPEED_100 || pdata->speed == SPEED_10) {
EMACDBG("Bail out\n");
return Y_SUCCESS;
}
/* Write 1 to DLL_EN */
SDCC_HC_DLL_EN_UDFWR(0x1);
/* Write 1 to CK_OUT_EN */
SDCC_HC_CK_OUT_EN_UDFWR(0x1);
SDCC_USR_CTL_RGRD(reg_val);
reg_val &= ~(0x7UL<<24);
reg_val |= (0x4UL<<24);
SDCC_USR_CTL_RGWR(reg_val);
/* Wait until DLL_LOCK bit of SDC4_STATUS register is 1 */
while (1) {
if (current_cnt > RETRYCOUNT)
return -Y_FAILURE;
SDC4_STATUS_DLL_LOCK_STS_UDFRD(VARDLL_LOCK);
if (VARDLL_LOCK == 1) {
EMACDBG("DLL lock status bit set. DLL init successful\n");
break;
}
current_cnt++;
mdelay(1);
}
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* SDCDC low power mode */
/*!
* \brief Put SDCDC in the lowest power consumption mode
*
* \details This function will write to the PDN field in
* SDCC_HC_REG_DLL_CONFIG register to enable low power mode
*
*\return 0 on success and -ve on failure.
*/
int DWC_ETH_QOS_rgmii_io_macro_sdcdc_enable_lp_mode(void)
{
EMACDBG("Enter\n");
/* Write 1 to PDN bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_PDN_UDFWR(0x1);
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* SDCDC DLL configuration */
/*!
* \brief Configure SDCDC DLL config
*
* \details This function will write to the various fields in
* SDCC_HC_REG_DLL_CONFIG and SDCC_HC_REG_DLL_CONFIG_2
* registers for DLL configuration
*
*\return 0 on success and -1 on failure.
*/
int DWC_ETH_QOS_rgmii_io_macro_sdcdc_config(struct DWC_ETH_QOS_prv_data *pdata)
{
ULONG RETRYCOUNT = 1000;
ULONG current_cnt = 0;
volatile ULONG VARCK_OUT_EN;
EMACDBG("Enter\n");
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0) {
/* Set CDR_EN bit to 1 */
SDCC_HC_CDR_EN_UDFWR(0x1);
} else {
/* Set CDR_EN bit to 0 */
SDCC_HC_CDR_EN_UDFWR(0x0);
}
/* Set CDR_EXT_EN bit to 1 */
SDCC_HC_CDR_EXT_EN_UDFWR(0x1);
/* Set CK_OUT_EN bit to 0 */
SDCC_HC_CK_OUT_EN_UDFWR(0x0);
/* Set DLL_EN bit to 1 */
SDCC_HC_DLL_EN_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0) {
/* Set MCLK_GATING_ENABLE bit to 0 */
SDCC_HC_MCLK_GATING_ENABLE_UDFWR(0x0);
/* Set CDR_FINE_PHASE bit to 0 */
SDCC_HC_CDR_FINE_PHASE_UDFWR(0x0);
}
/* Wait until CK_OUT_EN bit of SDCC_HC_REG_DLL_CONFIG register
* is 0
*/
while (1) {
if (current_cnt > RETRYCOUNT)
return -Y_FAILURE;
SDCC_HC_CK_OUT_EN_UDFRD(VARCK_OUT_EN);
if (VARCK_OUT_EN == 0)
break;
current_cnt++;
mdelay(1);
}
/* Set CK_OUT_EN bit to 1 */
SDCC_HC_CK_OUT_EN_UDFWR(0x1);
/* Wait until CK_OUT_EN bit of SDCC_HC_REG_DLL_CONFIG register
* is 1
*/
current_cnt = 0;
while (1) {
if (current_cnt > RETRYCOUNT)
return -Y_FAILURE;
SDCC_HC_CK_OUT_EN_UDFRD(VARCK_OUT_EN);
if (VARCK_OUT_EN == 1)
break;
current_cnt++;
mdelay(1);
}
/* Write 1 to DDR_CAL_EN bit of SDCC_HC_REG_DLL_CONFIG_2
* register
*/
SDCC_HC_CFG_2_DDR_CAL_EN_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0) {
/* Set DLL_CLOCK_DISABLE bit to 0 */
SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_UDFWR(0x0);
/* Set MCLK_FREQ_CALC bit to 26 */
SDCC_HC_CFG_2_MCLK_FREQ_CALC_UDFWR(0x1A);
/* Set DDR_TRAFFIC_INIT_SEL bit to 0 */
SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_UDFWR(0x1);
/* Set DDR_TRAFFIC_INIT_SW bit to 0 */
SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_UDFWR(0x1);
}
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* SDCC DLL Bypass mode programming */
/*!
* \brief Enable SDCC DLL Bypass mode programming
*
* \details This function will write to the PDN field in
* SDCC_HC_REG_DLL_CONFIG register and bypass bit in
* SDCC_DLL_TEST_CTL register
*
*\return 0 on success
*/
int DWC_ETH_QOS_sdcc_set_bypass_mode(void)
{
EMACDBG("Enter\n");
/* Write 1 to PDN bit of SDCC_HC_REG_DLL_CONFIG register */
SDCC_HC_PDN_UDFWR(0x1);
/* Write 1 to bypass bit of SDCC_USR_CTL register */
SDCC_USR_CTL_BYPASS_MODE_UDFWR(0x1);
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* Programming rgmii_io_macro register for loopback mode */
/*!
* \brief Initialize the rgmii io macro block
*
* \details This function will write to the loopback
* fields in RGMII_IO_MACRO_CONFIG RGMII_IO_MACRO_CONFIG_2
* registers to set the RGMII loopback mode
*
*\return 0 on success
*/
static int DWC_ETH_QOS_set_rgmii_loopback_mode(UINT lb_mode)
{
EMACDBG("Enter\n");
RGMII_CONFIG_2_TX_TO_RX_LOOPBACK_EN_UDFWR(lb_mode);
EMACDBG("RGMII loopback mode set to = %d\n", lb_mode);
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* Programming rgmii_io_macro register for func_clk_en */
/*!
* \brief Initialize the rgmii io macro block
*
* \details This function will write to the func_clk_en
* fields in RGMII_IO_MACRO_CONFIG
*
*\return 0 on success
*/
int DWC_ETH_QOS_set_rgmii_func_clk_en(void)
{
EMACDBG("Enter\n");
RGMII_FUNC_CLK_EN_UDFWR(1);
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* Programming rgmii_io_macro register initialization */
/*!
* \brief Initialize the rgmii io macro block
*
* \details This function will write to the various
* fields in RGMII_IO_MACRO_CONFIG register to set the RGMII mode
*
*\return 0 on success
*/
int DWC_ETH_QOS_rgmii_io_macro_init(struct DWC_ETH_QOS_prv_data *pdata)
{
uint loopback_mode = 0;
uint loopback_mode_en = 0;
uint rgmii_data_divide_clk;
ULONG data;
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0 || (pdata->emac_hw_version_type == EMAC_HW_v2_3_1)
|| (pdata->emac_hw_version_type == EMAC_HW_v2_1_1)) {
if(pdata->io_macro_phy_intf == RGMII_MODE)
loopback_mode_en = 0x1;
rgmii_data_divide_clk = 0x0;
} else {
loopback_mode_en = 0x0;
rgmii_data_divide_clk = 0x1;
}
EMACDBG("Enter\n");
/* Loopback is disabled */
DWC_ETH_QOS_set_rgmii_loopback_mode(loopback_mode);
switch (pdata->io_macro_phy_intf) {
case RGMII_MODE:
/* Select RGMII interface */
RGMII_INTF_SEL_UDFWR(0x0);
switch (pdata->speed) {
case SPEED_1000:
EMACDBG("Set RGMII registers for speed = %d\n", pdata->speed);
if (pdata->io_macro_tx_mode_non_id){
EMACDBG(
"Set registers for Bypass mode = %d\n",
pdata->io_macro_tx_mode_non_id);
/* Enable DDR mode*/
RGMII_DDR_MODE_UDFWR(0x1);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x0);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x0);
/* Rx Path */
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_0 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
(pdata->emac_hw_version_type == EMAC_HW_v2_3_1) ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
} else {
/* Enable DDR mode*/
RGMII_DDR_MODE_UDFWR(0x1);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x0);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x1);
/* RGMII_TX_POS and RGMII_TX_NEG input pins are swapped
* based on the programmable swap control bit
*/
RGMII_PROG_SWAP_UDFWR(0x1);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x0);
/* If data arrives at positive edge or if data is
* delayed by 1.5ns/ 2ns then write 1 to RX_PROG_SWAP
* bit of register EMAC_RGMII_IO_MACRO_CONFIG_2
*/
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
/* Program PRG_RCLK_DLY to 52 ns for a required delay of 2 ns on HANA AU */
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_0 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_2)
SDCC_HC_PRG_RCLK_DLY_UDFWR(52);
else if (pdata->emac_hw_version_type == EMAC_HW_v2_3_1)
SDCC_HC_PRG_RCLK_DLY_UDFWR(104);
else if (pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
SDCC_HC_PRG_RCLK_DLY_UDFWR(130);
else { /* Program PRG_RCLK_DLY to 57 for a required delay of 1.8 ns */
SDCC_HC_PRG_RCLK_DLY_UDFWR(57);
}
SDCC_HC_REG_DDR_CONFIG_RGRD(data);
data |= (1 << 31);
SDCC_HC_REG_DDR_CONFIG_RGWR(data);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
}
break;
case SPEED_100:
EMACDBG("Set RGMII registers for speed = %d\n", pdata->speed);
if (pdata->io_macro_tx_mode_non_id) {
EMACDBG("Set registers for Bypass mode = %d\n",
pdata->io_macro_tx_mode_non_id);
RGMII_DDR_MODE_UDFWR(0x0);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x0);
RGMII_MAX_SPD_PRG_2_UDFWR(0x1);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x1);
/* Rx Path */
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x0);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_0 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
(pdata->emac_hw_version_type == EMAC_HW_v2_3_1) ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
} else{
RGMII_DDR_MODE_UDFWR(0x1);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
RGMII_MAX_SPD_PRG_2_UDFWR(0x1);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x0);
/* Rx Path */
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0)
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x0);
else
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
SDCC_HC_EXT_PRG_RCLK_DLY_CODE_UDFWR(0x5);
SDCC_HC_EXT_PRG_RCLK_DLY_UDFWR(0x3f);
SDCC_HC_EXT_PRG_RCLK_DLY_EN_UDFWR(0x1);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
}
break;
case SPEED_10:
EMACDBG("Set RGMII registers for speed = %d\n", pdata->speed);
if (pdata->io_macro_tx_mode_non_id) {
EMACDBG("Set registers for Bypass mode = %d\n",
pdata->io_macro_tx_mode_non_id);
RGMII_DDR_MODE_UDFWR(0x0);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x0);
RGMII_MAX_SPD_PRG_9_UDFWR(0x13);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x1);
/* Rx Path */
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_1)
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x0);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_0 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
(pdata->emac_hw_version_type == EMAC_HW_v2_3_1) ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
} else{
RGMII_DDR_MODE_UDFWR(0x1);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(rgmii_data_divide_clk);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
RGMII_MAX_SPD_PRG_9_UDFWR(0x13);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x0);
/* Rx Path */
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0)
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x0);
else
RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(0x1);
SDCC_HC_EXT_PRG_RCLK_DLY_CODE_UDFWR(0x5);
SDCC_HC_EXT_PRG_RCLK_DLY_UDFWR(0x3f);
SDCC_HC_EXT_PRG_RCLK_DLY_EN_UDFWR(0x1);
RGMII_LOOPBACK_EN_UDFWR(loopback_mode_en);
}
break;
default:
EMACDBG(
"No RGMII register settings for link speed = %d\n",
pdata->speed);
break;
}
break;
case RMII_MODE:
EMACDBG("Set registers for RMII mode and speed = %d\n", pdata->speed);
RGMII_INTF_SEL_UDFWR(0x01);
RGMII_DDR_MODE_UDFWR(0x0);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x1);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(0x1);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x0);
RGMII_CONFIG_2_CLK_DIVIDE_SEL_UDFWR(0x1);
RGMII_MAX_SPD_PRG_2_UDFWR(0x1);
RGMII_MAX_SPD_PRG_9_UDFWR(0x13);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x0);
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_0 || (pdata->emac_hw_version_type == EMAC_HW_v2_3_1))
RGMII_LOOPBACK_EN_UDFWR(0x0);
else
RGMII_LOOPBACK_EN_UDFWR(0x1);
break;
case MII_MODE:
EMACDBG("Set registers for MII mode and speed = %d\n", pdata->speed);
RGMII_INTF_SEL_UDFWR(0x2);
RGMII_DDR_MODE_UDFWR(0x0);
RGMII_BYPASS_TX_ID_EN_UDFWR(0x1);
RGMII_POS_NEG_DATA_SEL_UDFWR(0x0);
RGMII_PROG_SWAP_UDFWR(0x0);
RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(0x1);
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x0);
RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_1_2 ||
pdata->emac_hw_version_type == EMAC_HW_v2_1_1)
RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(0x1);
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_1)
RGMII_LOOPBACK_EN_UDFWR(0x1);
break;
}
EMACDBG("Exit\n");
return Y_SUCCESS;
}
/* Programming IO macro and DLL registers with POR values */
/*!
* \brief Reset the IO MACRO and DLL blocks
*
* \details This function will write POR values to RGMII and
* DLL registers.
*
*\return Y_SUCCESS
*/
int DWC_ETH_QOS_rgmii_io_macro_dll_reset(struct DWC_ETH_QOS_prv_data *pdata)
{
int index_of_reg;
ULONG data, address;
EMACDBG("Enter\n");
for (index_of_reg = 0 ; index_of_reg < RGMII_IO_MACRO_DLL_POR_NUM_OF_REGS; index_of_reg++) {
address = RGMII_IO_BASE_ADDRESS
+ rgmii_io_macro_dll_por_values
[pdata->emac_hw_version_type]
[index_of_reg]
[RGMII_IO_MACRO_DLL_POR_REG_OFFSET_INDEX];
data = rgmii_io_macro_dll_por_values
[pdata->emac_hw_version_type]
[index_of_reg]
[RGMII_IO_MACRO_DLL_POR_REG_DATA_INDEX];
iowrite32(data, (void *)address);
}
DWC_ETH_QOS_set_rgmii_func_clk_en();
EMACDBG("Exit\n");
return Y_SUCCESS;
}
void dump_rgmii_io_macro_registers(void)
{
int reg_val;
pr_alert(
"\n************* RGMII IO Macro Reg dump *************************\n");
RGMII_IO_MACRO_CONFIG_RGRD(reg_val);
pr_alert(
"RGMII_IO_MACRO_CONFIG (0x%p) = %#x\n",
RGMII_IO_MACRO_CONFIG_RGOFFADDR, reg_val);
SDCC_HC_REG_DLL_CONFIG_RGRD(reg_val);
pr_alert(
"SDCC_HC_REG_DLL_CONFIG (0x%p) = %#x\n",
SDCC_HC_REG_DLL_CONFIG_RGOFFADDR, reg_val);
SDCC_HC_REG_DDR_CONFIG_RGRD(reg_val);
pr_alert(
"SDCC_HC_REG_DDR_CONFIG (0x%p) = %#x\n",
SDCC_HC_REG_DDR_CONFIG_RGOFFADDR, reg_val);
SDCC_HC_REG_DLL_CONFIG_2_RGRD(reg_val);
pr_alert(
"SDCC_HC_REG_DLL_CONFIG_2 (0x%p) = %#x\n",
SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR, reg_val);
RGMII_IO_MACRO_CONFIG_2_RGRD(reg_val);
pr_alert(
"RGMII_IO_MACRO_CONFIG_2 (0x%p) = %#x\n",
RGMII_IO_MACRO_CONFIG_2_RGOFFADDR, reg_val);
RGMII_IO_MACRO_DEBUG_1_RGRD(reg_val);
pr_alert(
"RGMII_IO_MACRO_DEBUG_1 (0x%p) = %#x\n",
RGMII_IO_MACRO_DEBUG_1_RGOFFADDR, reg_val);
SDC4_STATUS_RGRD(reg_val);
pr_alert(
"SDC4_STATUS_RGRD (0x%p) = %#x\n",
SDC4_STATUS_RGOFFADDR, reg_val);
SDCC_USR_CTL_RGRD(reg_val);
pr_alert(
"SDCC_USR_CTL_RGRD (0x%p) = %#x\n",
SDCC_USR_CTL_RGOFFADDR, reg_val);
EMAC_SYSTEM_LOW_POWER_DEBUG_RGRD(reg_val);
pr_alert(
"EMAC_SYSTEM_LOW_POWER_DEBUG_RGRD (0x%p) = %#x\n",
EMAC_SYSTEM_LOW_POWER_DEBUG_RGOFFADDR, reg_val);
pr_alert("\n****************************************************\n");
}

View File

@@ -0,0 +1,617 @@
/* Copyright (c) 2017,2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*
* This file contain content copied from Synopsis driver,
* provided under the license below
*/
/* =========================================================================
* The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
* "Software") is an unsupported proprietary work of Synopsys, Inc. unless
* otherwise expressly agreed to in writing between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product under
* any End User Software License Agreement or Agreement for Licensed Product
* with Synopsys or any supplement thereto. Permission is hereby granted,
* free of charge, to any person obtaining a copy of this software annotated
* with this license and the Software, to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject
* to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
* ========================================================================= */
#ifndef __DWC_ETH_QOS_YAPPHDR_H__
#define __DWC_ETH_QOS_YAPPHDR_H__
#define DWC_ETH_QOS_MAX_TX_QUEUE_CNT 8
#define DWC_ETH_QOS_MAX_RX_QUEUE_CNT 8
#define CONFIG_PPS_OUTPUT // for PPS Output
/* Private IOCTL for handling device specific task */
#define DWC_ETH_QOS_PRV_IOCTL SIOCDEVPRIVATE
#define DWC_ETH_QOS_PRV_IOCTL_IPA SIOCDEVPRIVATE+1
/* IOCTL cmd to eMAC to register the RX/TX properties with VLAN hdr*/
enum{
DWC_ETH_QOS_IPA_VLAN_DISABLE_CMD= 0,
DWC_ETH_QOS_IPA_VLAN_ENABLE_CMD=1,
};
#define DWC_ETH_QOS_POWERUP_MAGIC_CMD 1
#define DWC_ETH_QOS_POWERDOWN_MAGIC_CMD 2
#define DWC_ETH_QOS_POWERUP_REMOTE_WAKEUP_CMD 3
#define DWC_ETH_QOS_POWERDOWN_REMOTE_WAKEUP_CMD 4
/* for TX and RX threshold configures */
#define DWC_ETH_QOS_RX_THRESHOLD_CMD 5
#define DWC_ETH_QOS_TX_THRESHOLD_CMD 6
/* for TX and RX Store and Forward mode configures */
#define DWC_ETH_QOS_RSF_CMD 7
#define DWC_ETH_QOS_TSF_CMD 8
/* for TX DMA Operate on Second Frame mode configures */
#define DWC_ETH_QOS_OSF_CMD 9
/* for TX and RX PBL configures */
#define DWC_ETH_QOS_TX_PBL_CMD 10
#define DWC_ETH_QOS_RX_PBL_CMD 11
/* INCR and INCRX mode */
#define DWC_ETH_QOS_INCR_INCRX_CMD 12
/* for MAC Double VLAN Processing config */
#define DWC_ETH_QOS_DVLAN_TX_PROCESSING_CMD 13
#define DWC_ETH_QOS_DVLAN_RX_PROCESSING_CMD 14
#define DWC_ETH_QOS_SVLAN_CMD 15
/* Manju: Remove the below defines */
/* RX/TX VLAN */
/* #define DWC_ETH_QOS_RX_OUTER_VLAN_STRIPPING_CMD 13 */
/* #define DWC_ETH_QOS_RX_INNER_VLAN_STRIPPING_CMD 14 */
/* #define DWC_ETH_QOS_TX_VLAN_DESC_CMD 15 */
/* #define DWC_ETH_QOS_TX_VLAN_REG_CMD 16 */
/* SA on TX */
#define DWC_ETH_QOS_SA0_DESC_CMD 17
#define DWC_ETH_QOS_SA1_DESC_CMD 18
#define DWC_ETH_QOS_SA0_REG_CMD 19
#define DWC_ETH_QOS_SA1_REG_CMD 20
/* CONTEX desc setup control */
#define DWC_ETH_QOS_SETUP_CONTEXT_DESCRIPTOR 21
/* Packet generation */
#define DWC_ETH_QOS_PG_TEST 22
/* TX/RX channel/queue count */
#define DWC_ETH_QOS_GET_TX_QCNT 23
#define DWC_ETH_QOS_GET_RX_QCNT 24
/* Line speed */
#define DWC_ETH_QOS_GET_CONNECTED_SPEED 25
/* DCB/AVB algorithm */
#define DWC_ETH_QOS_DCB_ALGORITHM 26
#define DWC_ETH_QOS_AVB_ALGORITHM 27
/* RX split header */
#define DWC_ETH_QOS_RX_SPLIT_HDR_CMD 28
/* L3/L4 filter */
#define DWC_ETH_QOS_L3_L4_FILTER_CMD 29
/* IPv4/6 and TCP/UDP filtering */
#define DWC_ETH_QOS_IPV4_FILTERING_CMD 30
#define DWC_ETH_QOS_IPV6_FILTERING_CMD 31
#define DWC_ETH_QOS_UDP_FILTERING_CMD 32
#define DWC_ETH_QOS_TCP_FILTERING_CMD 33
/* VLAN filtering */
#define DWC_ETH_QOS_VLAN_FILTERING_CMD 34
/* L2 DA filtering */
#define DWC_ETH_QOS_L2_DA_FILTERING_CMD 35
/* ARP Offload */
#define DWC_ETH_QOS_ARP_OFFLOAD_CMD 36
/* for AXI PBL configures */
#define DWC_ETH_QOS_AXI_PBL_CMD 37
/* for AXI Write Outstanding Request Limit configures */
#define DWC_ETH_QOS_AXI_WORL_CMD 38
/* for AXI Read Outstanding Request Limit configures */
#define DWC_ETH_QOS_AXI_RORL_CMD 39
/* for MAC LOOPBACK configuration */
#define DWC_ETH_QOS_MAC_LOOPBACK_MODE_CMD 40
/* PFC(Priority Based Flow Control) mode */
#define DWC_ETH_QOS_PFC_CMD 41
/* for PTP OFFLOADING configuration */
#define DWC_ETH_QOS_PTPOFFLOADING_CMD 42
/* To configure PPS output */
#ifdef CONFIG_PPS_OUTPUT
#define DWC_ETH_QOS_CONFIG_PTPCLK_CMD 43
#define DWC_ETH_QOS_CONFIG_PPSOUT_CMD 44
#endif
#define DWC_ETH_QOS_RWK_FILTER_LENGTH 8
/* List of command errors driver can set */
#define DWC_ETH_QOS_NO_HW_SUPPORT -1
#define DWC_ETH_QOS_CONFIG_FAIL -3
#define DWC_ETH_QOS_CONFIG_SUCCESS 0
/* RX THRESHOLD operations */
#define DWC_ETH_QOS_RX_THRESHOLD_32 0x1
#define DWC_ETH_QOS_RX_THRESHOLD_64 0x0
#define DWC_ETH_QOS_RX_THRESHOLD_96 0x2
#define DWC_ETH_QOS_RX_THRESHOLD_128 0x3
/* TX THRESHOLD operations */
#define DWC_ETH_QOS_TX_THRESHOLD_32 0x1
#define DWC_ETH_QOS_TX_THRESHOLD_64 0x0
#define DWC_ETH_QOS_TX_THRESHOLD_96 0x2
#define DWC_ETH_QOS_TX_THRESHOLD_128 0x3
#define DWC_ETH_QOS_TX_THRESHOLD_192 0x4
#define DWC_ETH_QOS_TX_THRESHOLD_256 0x5
#define DWC_ETH_QOS_TX_THRESHOLD_384 0x6
#define DWC_ETH_QOS_TX_THRESHOLD_512 0x7
/* TX and RX Store and Forward Mode operations */
#define DWC_ETH_QOS_RSF_DISABLE 0x0
#define DWC_ETH_QOS_RSF_ENABLE 0x1
#define DWC_ETH_QOS_TSF_DISABLE 0x0
#define DWC_ETH_QOS_TSF_ENABLE 0x1
/* TX DMA Operate on Second Frame operations */
#define DWC_ETH_QOS_OSF_DISABLE 0x0
#define DWC_ETH_QOS_OSF_ENABLE 0x1
/* INCR and INCRX mode */
#define DWC_ETH_QOS_INCR_ENABLE 0x1
#define DWC_ETH_QOS_INCRX_ENABLE 0x0
/* TX and RX PBL operations */
#define DWC_ETH_QOS_PBL_1 1
#define DWC_ETH_QOS_PBL_2 2
#define DWC_ETH_QOS_PBL_4 4
#define DWC_ETH_QOS_PBL_8 8
#define DWC_ETH_QOS_PBL_16 16
#define DWC_ETH_QOS_PBL_32 32
#define DWC_ETH_QOS_PBL_64 64 /* 8 x 8 */
#define DWC_ETH_QOS_PBL_128 128 /* 8 x 16 */
#define DWC_ETH_QOS_PBL_256 256 /* 8 x 32 */
/* AXI operations */
#define DWC_ETH_QOS_AXI_PBL_4 0x2
#define DWC_ETH_QOS_AXI_PBL_8 0x6
#define DWC_ETH_QOS_AXI_PBL_16 0xE
#define DWC_ETH_QOS_AXI_PBL_32 0x1E
#define DWC_ETH_QOS_AXI_PBL_64 0x3E
#define DWC_ETH_QOS_AXI_PBL_128 0x7E
#define DWC_ETH_QOS_AXI_PBL_256 0xFE
#define DWC_ETH_QOS_MAX_AXI_WORL 31
#define DWC_ETH_QOS_MAX_AXI_RORL 31
/* RX VLAN operations */
/* Do not strip VLAN tag from received pkt */
#define DWC_ETH_QOS_RX_NO_VLAN_STRIP 0x0
/* Strip VLAN tag if received pkt pass VLAN filter */
#define DWC_ETH_QOS_RX_VLAN_STRIP_IF_FILTER_PASS 0x1
/* Strip VLAN tag if received pkt fial VLAN filter */
#define DWC_ETH_QOS_RX_VLAN_STRIP_IF_FILTER_FAIL 0x2
/* Strip VALN tag always from received pkt */
#define DWC_ETH_QOS_RX_VLAN_STRIP_ALWAYS 0x3
/* TX VLAN operations */
/* Do not add a VLAN tag dring pkt transmission */
#define DWC_ETH_QOS_TX_VLAN_TAG_NONE 0x0
/* Remove the VLAN tag from the pkt before transmission */
#define DWC_ETH_QOS_TX_VLAN_TAG_DELETE 0x1
/* Insert the VLAN tag into pkt to be transmitted */
#define DWC_ETH_QOS_TX_VLAN_TAG_INSERT 0x2
/* Replace the VLAN tag into pkt to be transmitted */
#define DWC_ETH_QOS_TX_VLAN_TAG_REPLACE 0x3
/* RX split header operations */
#define DWC_ETH_QOS_RX_SPLIT_HDR_DISABLE 0x0
#define DWC_ETH_QOS_RX_SPLIT_HDR_ENABLE 0x1
/* L3/L4 filter operations */
#define DWC_ETH_QOS_L3_L4_FILTER_DISABLE 0x0
#define DWC_ETH_QOS_L3_L4_FILTER_ENABLE 0x1
/* Loopback mode */
#define DWC_ETH_QOS_MAC_LOOPBACK_DISABLE 0x0
#define DWC_ETH_QOS_MAC_LOOPBACK_ENABLE 0x1
/* PFC(Priority Based Flow Control) mode */
#define DWC_ETH_QOS_PFC_DISABLE 0x0
#define DWC_ETH_QOS_PFC_ENABLE 0x1
#define DWC_ETH_QOS_MAC0REG 0
#define DWC_ETH_QOS_MAC1REG 1
#define DWC_ETH_QOS_SA0_NONE ((DWC_ETH_QOS_MAC0REG << 2) | 0) /* Do not include the SA */
#define DWC_ETH_QOS_SA0_DESC_INSERT ((DWC_ETH_QOS_MAC0REG << 2) | 1) /* Include/Insert the SA with value given in MAC Addr 0 Reg */
#define DWC_ETH_QOS_SA0_DESC_REPLACE ((DWC_ETH_QOS_MAC0REG << 2) | 2) /* Replace the SA with the value given in MAC Addr 0 Reg */
#define DWC_ETH_QOS_SA0_REG_INSERT ((DWC_ETH_QOS_MAC0REG << 2) | 2) /* Include/Insert the SA with value given in MAC Addr 0 Reg */
#define DWC_ETH_QOS_SA0_REG_REPLACE ((DWC_ETH_QOS_MAC0REG << 2) | 3) /* Replace the SA with the value given in MAC Addr 0 Reg */
#define DWC_ETH_QOS_SA1_NONE ((DWC_ETH_QOS_MAC1REG << 2) | 0) /* Do not include the SA */
#define DWC_ETH_QOS_SA1_DESC_INSERT ((DWC_ETH_QOS_MAC1REG << 2) | 1) /* Include/Insert the SA with value given in MAC Addr 1 Reg */
#define DWC_ETH_QOS_SA1_DESC_REPLACE ((DWC_ETH_QOS_MAC1REG << 2) | 2) /* Replace the SA with the value given in MAC Addr 1 Reg */
#define DWC_ETH_QOS_SA1_REG_INSERT ((DWC_ETH_QOS_MAC1REG << 2) | 2) /* Include/Insert the SA with value given in MAC Addr 1 Reg */
#define DWC_ETH_QOS_SA1_REG_REPLACE ((DWC_ETH_QOS_MAC1REG << 2) | 3) /* Replace the SA with the value given in MAC Addr 1 Reg */
#define DWC_ETH_QOS_MAX_WFQ_WEIGHT 0X7FFF /* value for bandwidth calculation */
#define DWC_ETH_QOS_MAX_INT_FRAME_SIZE (1024 * 16)
typedef enum {
EDWC_ETH_QOS_DMA_TX_FP = 0,
EDWC_ETH_QOS_DMA_TX_WSP = 1,
EDWC_ETH_QOS_DMA_TX_WRR = 2,
} e_DWC_ETH_QOS_dma_tx_arb_algo;
typedef enum {
EDWC_ETH_QOS_DCB_WRR = 0,
EDWC_ETH_QOS_DCB_WFQ = 1,
EDWC_ETH_QOS_DCB_DWRR = 2,
EDWC_ETH_QOS_DCB_SP = 3,
} e_DWC_ETH_QOS_dcb_algorithm;
typedef enum {
EDWC_ETH_QOS_AVB_SP = 0,
EDWC_ETH_QOS_AVB_CBS = 1,
} e_DWC_ETH_QOS_avb_algorithm;
typedef enum {
EDWC_ETH_QOS_QDISABLED = 0x0,
EDWC_ETH_QOS_QAVB,
EDWC_ETH_QOS_QDCB,
EDWC_ETH_QOS_QGENERIC
} EDWC_ETH_QOS_QUEUE_OPERATING_MODE;
/* common data structure between driver and application for
* sharing info through ioctl
* */
struct ifr_data_struct {
unsigned int flags;
unsigned int qinx; /* dma channel no to be configured */
unsigned int cmd;
unsigned int context_setup;
unsigned int connected_speed;
unsigned int rwk_filter_values[DWC_ETH_QOS_RWK_FILTER_LENGTH];
unsigned int rwk_filter_length;
int command_error;
int test_done;
void *ptr;
};
struct ifr_data_struct_ipa {
unsigned int chInx_tx_ipa;
unsigned int chInx_rx_ipa;
unsigned int cmd;
unsigned short vlan_id;
};
struct DWC_ETH_QOS_dcb_algorithm {
unsigned int qinx;
unsigned int algorithm;
unsigned int weight;
EDWC_ETH_QOS_QUEUE_OPERATING_MODE op_mode;
};
struct DWC_ETH_QOS_avb_algorithm_params {
unsigned int idle_slope;
unsigned int send_slope;
unsigned int hi_credit;
unsigned int low_credit;
};
struct DWC_ETH_QOS_avb_algorithm {
unsigned int qinx;
unsigned int algorithm;
unsigned int cc;
struct DWC_ETH_QOS_avb_algorithm_params speed100params;
struct DWC_ETH_QOS_avb_algorithm_params speed1000params;
EDWC_ETH_QOS_QUEUE_OPERATING_MODE op_mode;
};
struct DWC_ETH_QOS_l3_l4_filter {
/* 0, 1,2,3,4,5,6 or 7*/
unsigned int filter_no;
/* 0 - disable and 1 - enable */
int filter_enb_dis;
/* 0 - src addr/port and 1- dst addr/port match */
int src_dst_addr_match;
/* 0 - perfect and 1 - inverse match filtering */
int perfect_inverse_match;
/* To hold source/destination IPv4 addresses */
unsigned char ip4_addr[4];
/* holds single IPv6 addresses */
unsigned short ip6_addr[8];
/* TCP/UDP src/dst port number */
unsigned short port_no;
};
struct DWC_ETH_QOS_vlan_filter {
/* 0 - disable and 1 - enable */
int filter_enb_dis;
/* 0 - perfect and 1 - hash filtering */
int perfect_hash;
/* 0 - perfect and 1 - inverse matching */
int perfect_inverse_match;
};
struct DWC_ETH_QOS_l2_da_filter {
/* 0 - perfect and 1 - hash filtering */
int perfect_hash;
/* 0 - perfect and 1 - inverse matching */
int perfect_inverse_match;
};
struct DWC_ETH_QOS_arp_offload {
unsigned char ip_addr[4];
};
#define DWC_ETH_QOS_VIA_REG 0
#define DWC_ETH_QOS_VIA_DESC 1
/* for MAC Double VLAN Processing config */
#define DWC_ETH_QOS_DVLAN_OUTER (1)
#define DWC_ETH_QOS_DVLAN_INNER (1 << 1)
#define DWC_ETH_QOS_DVLAN_BOTH (DWC_ETH_QOS_DVLAN_OUTER | DWC_ETH_QOS_DVLAN_INNER)
#define DWC_ETH_QOS_DVLAN_NONE 0
#define DWC_ETH_QOS_DVLAN_DELETE 1
#define DWC_ETH_QOS_DVLAN_INSERT 2
#define DWC_ETH_QOS_DVLAN_REPLACE 3
#define DWC_ETH_QOS_DVLAN_DISABLE 0
#define DWC_ETH_QOS_DVLAN_ENABLE 1
struct DWC_ETH_QOS_config_dvlan {
int inner_vlan_tag;
int outer_vlan_tag;
/* op_type will be
* 0/1/2/3 for none/delet/insert/replace respectively
* */
int op_type;
/* in_out will be
* 1/2/3 for outer/inner/both respectively.
* */
int in_out;
/* 0 for via registers and 1 for via descriptor */
int via_reg_or_desc;
};
/* for PTP offloading configuration */
#define DWC_ETH_QOS_PTP_OFFLOADING_DISABLE 0
#define DWC_ETH_QOS_PTP_OFFLOADING_ENABLE 1
#define DWC_ETH_QOS_PTP_ORDINARY_SLAVE 1
#define DWC_ETH_QOS_PTP_ORDINARY_MASTER 2
#define DWC_ETH_QOS_PTP_TRASPARENT_SLAVE 3
#define DWC_ETH_QOS_PTP_TRASPARENT_MASTER 4
#define DWC_ETH_QOS_PTP_PEER_TO_PEER_TRANSPARENT 5
struct DWC_ETH_QOS_config_ptpoffloading {
int en_dis;
int mode;
int domain_num;
int mc_uc;
};
#ifdef CONFIG_PPS_OUTPUT
struct ETH_PPS_Config
{
unsigned int ptpclk_freq;
unsigned int ppsout_freq;
unsigned int ppsout_ch;
unsigned int ppsout_duty;
unsigned int ppsout_start;
};
#endif
#ifdef DWC_ETH_QOS_CONFIG_PGTEST
/* uncomment below macro to enable application
* to record all run reports to file */
/* #define PGTEST_LOGFILE */
/* TX DMA CHANNEL Weights */
#define DWC_ETH_QOS_TX_CH_WEIGHT1 0x0
#define DWC_ETH_QOS_TX_CH_WEIGHT2 0x1
#define DWC_ETH_QOS_TX_CH_WEIGHT3 0x2
#define DWC_ETH_QOS_TX_CH_WEIGHT4 0x3
#define DWC_ETH_QOS_TX_CH_WEIGHT5 0x4
#define DWC_ETH_QOS_TX_CH_WEIGHT6 0x5
#define DWC_ETH_QOS_TX_CH_WEIGHT7 0x6
#define DWC_ETH_QOS_TX_CH_WEIGHT8 0x7
/* PG test sub commands macro's */
#define DWC_ETH_QOS_PG_SET_CONFIG 0x1
#define DWC_ETH_QOS_PG_CONFIG_HW 0x2
#define DWC_ETH_QOS_PG_RUN_TEST 0x3
#define DWC_ETH_QOS_PG_GET_RESULT 0x4
#define DWC_ETH_QOS_PG_TEST_DONE 0x5
/* DMA channel bandwidth allocation parameters */
struct DWC_ETH_QOS_pg_user_ch_input {
unsigned char ch_arb_weight; /* Channel weights(1/2/3/4/5/6/7/8) for arbitration */
unsigned int ch_fr_size; /* Channel Frame size */
unsigned char ch_bw_alloc; /* The percentage bandwidth allocation for ch */
unsigned char ch_use_slot_no_check; /* Should Ch use slot number checking ? */
unsigned char ch_use_adv_slot_no_check;
unsigned char ch_slot_count_to_use; /* How many slot used to report pg bits per slot value */
unsigned char ch_use_credit_shape; /* Should Ch use Credid shape algorithm for traffic shaping ? */
unsigned char CH_CREDITCONTROL; /* Sould Ch use Credit Control algorithm for traffic shaping ? */
unsigned char ch_tx_desc_slot_no_start;
unsigned char ch_tx_desc_slot_no_skip;
unsigned char ch_operating_mode;
unsigned long CH_AVGBITS;
unsigned long CH_AVGBITS_INTERRUPT_COUNT;
unsigned char ch_avb_algorithm;
unsigned char ch_debug_mode; /* enable/disable debug mode */
unsigned int ch_max_tx_frame_cnt; /* maximum pkts to be sent on this channel, can be used for debug purpose */
};
struct DWC_ETH_QOS_pg_user_input {
unsigned char duration_of_exp;
/* enable bits for DMA. bit0=>ch0, bit1=>ch1, bit2=>ch2 */
unsigned char dma_ch_en;
unsigned char ch_tx_rx_arb_scheme; /* Should Ch use Weighted RR policy with Rx:Tx/Tx:Rx or Fixed Priority */
unsigned char ch_use_tx_high_prio; /* Should Ch Tx have High priority over Rx */
unsigned char ch_tx_rx_prio_ratio; /* For RR what is the ratio between Tx:Rx/Rx:Tx */
unsigned char dma_tx_arb_algo; /* Refer DMA Mode register TAA field */
unsigned char queue_dcb_algorithm;
unsigned char mac_lb_mode; /* 0 => No MAC Loopback; 1 => MAC Loopback On */
unsigned int speed_100M_1G; /* 0 => No MAC Loopback; 1 => MAC Loopback On */
struct DWC_ETH_QOS_pg_user_ch_input ch_input[DWC_ETH_QOS_MAX_TX_QUEUE_CNT];
};
#define copy_pg_ch_input_members(to, from) do { \
(to)->interrupt_prints = (from)->interrupt_prints; \
(to)->tx_interrupts = (from)->tx_interrupts; \
(to)->ch_arb_weight = (from)->ch_arb_weight; \
(to)->ch_queue_weight = (from)->ch_queue_weight; \
(to)->ch_bw = (from)->ch_bw; \
(to)->ch_frame_size = (from)->ch_frame_size; \
(to)->CH_ENABLESLOTCHECK = (from)->CH_ENABLESLOTCHECK; \
(to)->CH_ENABLEADVSLOTCHECK = (from)->CH_ENABLEADVSLOTCHECK; \
(to)->ch_avb_algorithm = (from)->ch_avb_algorithm; \
(to)->CH_SLOTCOUNT = (from)->CH_SLOTCOUNT; \
(to)->CH_AVGBITS = (from)->CH_AVGBITS; \
(to)->CH_AVGBITS_INTERRUPT_COUNT = (from)->CH_AVGBITS_INTERRUPT_COUNT; \
(to)->CH_CREDITCONTROL = (from)->CH_CREDITCONTROL; \
(to)->ch_tx_desc_slot_no_start = (from)->ch_tx_desc_slot_no_start; \
(to)->ch_tx_desc_slot_no_skip = (from)->ch_tx_desc_slot_no_skip; \
(to)->CH_SENDSLOPE = (from)->CH_SENDSLOPE; \
(to)->CH_IDLESLOPE = (from)->CH_IDLESLOPE; \
(to)->CH_HICREDIT = (from)->CH_HICREDIT; \
(to)->CH_LOCREDIT = (from)->CH_LOCREDIT; \
(to)->CH_FRAMECOUNTTX = (from)->CH_FRAMECOUNTTX; \
(to)->CH_FRAMECOUNTRX = (from)->CH_FRAMECOUNTRX; \
(to)->ch_operating_mode = (from)->ch_operating_mode; \
(to)->ch_debug_mode = (from)->ch_debug_mode;\
(to)->ch_max_tx_frame_cnt = (from)->ch_max_tx_frame_cnt;\
} while (0)
struct DWC_ETH_QOS_pg_ch_input {
unsigned int interrupt_prints;
unsigned int tx_interrupts;
unsigned char ch_arb_weight;
unsigned int ch_queue_weight;
unsigned char ch_bw;
unsigned int ch_frame_size;
unsigned char CH_ENABLESLOTCHECK; /* Enable checking of slot numbers programmed in the Tx Desc */
unsigned char CH_ENABLEADVSLOTCHECK; /* When Set Data fetched for current slot and for next 2 slots in advance
When reset data fetched for current slot and in advance for next slot*/
unsigned char ch_avb_algorithm;
unsigned char CH_SLOTCOUNT; /* Over which transmiteed bits per slot needs to be computed (Only for Credit based shaping) */
unsigned long CH_AVGBITS;
unsigned long CH_AVGBITS_INTERRUPT_COUNT;
unsigned char CH_CREDITCONTROL; /* Will be zero (Not used) */
unsigned char ch_tx_desc_slot_no_start;
unsigned char ch_tx_desc_slot_no_skip;
unsigned int CH_SENDSLOPE;
unsigned int CH_IDLESLOPE;
unsigned int CH_HICREDIT;
unsigned int CH_LOCREDIT;
unsigned long CH_FRAMECOUNTTX; /* No of Frames Transmitted on Channel 1 */
unsigned long CH_FRAMECOUNTRX; /* No of Frames Received on Channel 1 */
unsigned char ch_operating_mode;
unsigned char ch_debug_mode; /* enable/disable debug mode */
unsigned int ch_max_tx_frame_cnt; /* maximum pkts to be sent on this channel, can be used for debug purpose */
unsigned int ch_desc_prepare; /* max packets which will be reprepared in Tx-interrupt
do not copy contents to app-copy, only driver should use this variable*/
};
#define COPY_PGSTRUCT_MEMBERS(to, from) do { \
(to)->CH_SELMASK = (from)->CH_SELMASK; \
(to)->DURATIONOFEXP = (from)->DURATIONOFEXP; \
(to)->PRIOTAGFORAV = (from)->PRIOTAGFORAV; \
(to)->queue_dcb_algorithm = (from)->queue_dcb_algorithm; \
(to)->ch_tx_rx_arb_scheme = (from)->ch_tx_rx_arb_scheme; \
(to)->ch_use_tx_high_prio = (from)->ch_use_tx_high_prio; \
(to)->ch_tx_rx_prio_ratio = (from)->ch_tx_rx_prio_ratio; \
(to)->dma_tx_arb_algo = (from)->dma_tx_arb_algo; \
(to)->mac_lb_mode = (from)->mac_lb_mode; \
} while (0)
struct DWC_ETH_QOS_PGSTRUCT {
/* This gives which DMA channel is enabled and which is disabled
* Bit0 for Ch0
* Bit1 for Ch1
* Bit2 for Ch2 and so on
* Bit7 for Ch7
* */
unsigned char CH_SELMASK;
/* Duration for which experiment should be conducted in minutes - Default 2 Minutes */
unsigned char DURATIONOFEXP;
/* Used when more than One channel enabled in Rx path (Not Used)
* for only CH1 Enabled:
* Frames sith Priority > Value programmed, frames sent to CH1
* Frames with priority < Value programmed are sent to CH0
*
* For both CH1 and CH2 Enabled:
* Frames sith Priority > Value programmed, frames sent to CH2
* Frames with priority < Value programmed are sent to CH
* */
unsigned char PRIOTAGFORAV;
unsigned char queue_dcb_algorithm;
unsigned char ch_tx_rx_arb_scheme; /* Should Ch use Weighted RR policy with Rx:Tx/Tx:Rx or Fixed Priority */
unsigned char ch_use_tx_high_prio; /* Should Ch Tx have High priority over Rx */
unsigned char ch_tx_rx_prio_ratio; /* For RR what is the ratio between Tx:Rx/Rx:Tx */
unsigned char dma_tx_arb_algo; /* Refer DMA Mode register TAA field */
unsigned char mac_lb_mode; /* 0 => No MAC Loopback; 1 => MAC Loopback On */
unsigned int speed_100M_1G;
struct DWC_ETH_QOS_pg_ch_input pg_ch_input[DWC_ETH_QOS_MAX_TX_QUEUE_CNT];
unsigned char channel_running[DWC_ETH_QOS_MAX_TX_QUEUE_CNT];
};
#endif /* end of DWC_ETH_QOS_CONFIG_PGTEST */
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,724 @@
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#ifndef __DWC_ETH_QOS__RGMII_IO_MACRO_REGACC__H__
#define __DWC_ETH_QOS__RGMII_IO_MACRO_REGACC__H__
/* Read Write register operations for EMAC_RGMII_IO_MACRO_CONFIG */
extern ULONG dwc_rgmii_io_csr_base_addr;
#define RGMII_IO_BASE_ADDRESS dwc_rgmii_io_csr_base_addr
#define RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET (0x00000000)
#define RGMII_IO_MACRO_CONFIG_RGOFFADDR ((volatile ULONG *) (RGMII_IO_BASE_ADDRESS + RGMII_IO_MACRO_CONFIG_RGOFFADDR_OFFSET))
#define RGMII_IO_MACRO_CONFIG_RGWR(data) do {\
iowrite32(data, (void *)RGMII_IO_MACRO_CONFIG_RGOFFADDR);\
} while (0)
#define RGMII_IO_MACRO_CONFIG_RGRD(data) do {\
(data) = ioread32((void *)RGMII_IO_MACRO_CONFIG_RGOFFADDR);\
} while (0)
#define RGMII_FUNC_CLK_EN_MASK (ULONG)(0x1)
#define RGMII_FUNC_CLK_EN_WR_MASK (ULONG)(0xbfffffff)
#define RGMII_FUNC_CLK_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_FUNC_CLK_EN_WR_MASK) | ((data & RGMII_FUNC_CLK_EN_MASK) << 30));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_FUNC_CLK_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 30) & RGMII_FUNC_CLK_EN_MASK);\
} while (0)
#define RGMII_GPIO_CFG_RX_INT_MASK (ULONG)(0x3)
#define RGMII_GPIO_CFG_RX_INT_WR_MASK (ULONG)(0xffe7ffff)
#define RGMII_GPIO_CFG_RX_INT_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_GPIO_CFG_RX_INT_WR_MASK) | ((data & RGMII_GPIO_CFG_RX_INT_MASK) << 19));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_GPIO_CFG_RX_INT_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 19) & RGMII_GPIO_CFG_RX_INT_MASK);\
} while (0)
#define RGMII_GPIO_CFG_TX_INT_MASK (ULONG)(0x3)
#define RGMII_GPIO_CFG_TX_INT_WR_MASK (ULONG)(0xfff9ffff)
#define RGMII_GPIO_CFG_TX_INT_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_GPIO_CFG_TX_INT_WR_MASK) | ((data & RGMII_GPIO_CFG_TX_INT_MASK) << 17));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_GPIO_CFG_TX_INT_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 17) & RGMII_GPIO_CFG_TX_INT_MASK);\
} while (0)
#define RGMII_MAX_SPD_PRG_9_MASK (ULONG)(0x1ff)
#define RGMII_MAX_SPD_PRG_9_WR_MASK (ULONG)(0xfffe00ff)
#define RGMII_MAX_SPD_PRG_9_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_MAX_SPD_PRG_9_WR_MASK) | ((data & RGMII_MAX_SPD_PRG_9_MASK) << 8));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_MAX_SPD_PRG_9_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 8) & RGMII_MAX_SPD_PRG_9_MASK);\
} while (0)
#define RGMII_MAX_SPD_PRG_2_MASK (ULONG)(0x3)
#define RGMII_MAX_SPD_PRG_2_WR_MASK (ULONG)(0xffffff3f)
#define RGMII_MAX_SPD_PRG_2_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_MAX_SPD_PRG_2_WR_MASK) | ((data & RGMII_MAX_SPD_PRG_2_MASK) << 6));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_MAX_SPD_PRG_2_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 6) & RGMII_MAX_SPD_PRG_2_MASK);\
} while (0)
#define RGMII_INTF_SEL_MASK (ULONG)(0x3)
#define RGMII_INTF_SEL_WR_MASK (ULONG)(0xffffffcf)
#define RGMII_INTF_SEL_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_INTF_SEL_WR_MASK) | ((data & RGMII_INTF_SEL_MASK) << 4));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_INTF_SEL_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 4) & RGMII_INTF_SEL_MASK);\
} while (0)
#define RGMII_POS_NEG_DATA_SEL_MASK (ULONG)(0x1)
#define RGMII_POS_NEG_DATA_SEL_WR_MASK (ULONG)(0xff7fffff)
#define RGMII_POS_NEG_DATA_SEL_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_POS_NEG_DATA_SEL_WR_MASK) | ((data & RGMII_POS_NEG_DATA_SEL_MASK) << 23));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_POS_NEG_DATA_SEL_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 23) & RGMII_POS_NEG_DATA_SEL_MASK);\
} while (0)
#define RGMII_BYPASS_TX_ID_EN_MASK (ULONG)(0x1)
#define RGMII_BYPASS_TX_ID_EN_WR_MASK (ULONG)(0xfffffff7)
#define RGMII_BYPASS_TX_ID_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_BYPASS_TX_ID_EN_WR_MASK) | ((data & RGMII_BYPASS_TX_ID_EN_MASK) << 3));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_BYPASS_TX_ID_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 3) & RGMII_BYPASS_TX_ID_EN_MASK);\
} while (0)
#define RGMII_LOOPBACK_EN_MASK (ULONG)(0x1)
#define RGMII_LOOPBACK_EN_WR_MASK (ULONG)(0xfffffffb)
#define RGMII_LOOPBACK_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_LOOPBACK_EN_WR_MASK) | ((data & RGMII_LOOPBACK_EN_MASK) << 2));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_LOOPBACK_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 2) & RGMII_LOOPBACK_EN_MASK);\
} while (0)
#define RGMII_PROG_SWAP_MASK (ULONG)(0x1)
#define RGMII_PROG_SWAP_WR_MASK (ULONG)(0xfffffffd)
#define RGMII_PROG_SWAP_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_PROG_SWAP_WR_MASK) | ((data & RGMII_PROG_SWAP_MASK) << 1));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_PROG_SWAP_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 1) & RGMII_PROG_SWAP_MASK);\
} while (0)
#define RGMII_DDR_MODE_MASK (ULONG)(0x1)
#define RGMII_DDR_MODE_WR_MASK (ULONG)(0xfffffffe)
#define RGMII_DDR_MODE_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_RGRD(v);\
v = ((v & RGMII_DDR_MODE_WR_MASK) | ((data & RGMII_DDR_MODE_MASK) << 0));\
RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)
#define RGMII_DDR_MODE_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_RGRD(data);\
data = ((data >> 0) & RGMII_DDR_MODE_MASK);\
} while (0)
/* Read Write register operations for EMAC_SDCC_HC_REG_DLL_CONFIG */
#define SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET (0x00000004)
#define SDCC_HC_REG_DLL_CONFIG_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + SDCC_HC_REG_DLL_CONFIG_RGOFFADDR_OFFSET))
#define SDCC_HC_REG_DLL_CONFIG_RGWR(data) do {\
iowrite32(data, (void *)SDCC_HC_REG_DLL_CONFIG_RGOFFADDR);\
} while (0)
#define SDCC_HC_REG_DLL_CONFIG_RGRD(data) do {\
(data) = ioread32((void *)SDCC_HC_REG_DLL_CONFIG_RGOFFADDR);\
} while (0)
#define SDCC_HC_DLL_RST_MASK (ULONG)(0x1)
#define SDCC_HC_DLL_RST_WR_MASK (ULONG)(0xbfffffff)
#define SDCC_HC_DLL_RST_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_DLL_RST_WR_MASK) | ((data & SDCC_HC_DLL_RST_MASK) << 30));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_DLL_RST_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 30) & SDCC_HC_DLL_RST_MASK);\
} while (0)
#define SDCC_HC_PDN_MASK (ULONG)(0x1)
#define SDCC_HC_PDN_WR_MASK (ULONG)(0xdfffffff)
#define SDCC_HC_PDN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_PDN_WR_MASK) | ((data & SDCC_HC_PDN_MASK) << 29));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_PDN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 29) & SDCC_HC_PDN_MASK);\
} while (0)
#define SDCC_HC_MCLK_FREQ_MASK (ULONG)(0x7)
#define SDCC_HC_MCLK_FREQ_WR_MASK (ULONG)(0xf8ffffff)
#define SDCC_HC_MCLK_FREQ_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_MCLK_FREQ_WR_MASK) | ((data & SDCC_HC_MCLK_FREQ_MASK) << 24));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_MCLK_FREQ_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 24) & SDCC_HC_MCLK_FREQ_MASK);\
} while (0)
#define SDCC_HC_CDR_SELEXT_MASK (ULONG)(0xf)
#define SDCC_HC_CDR_SELEXT_WR_MASK (ULONG)(0xff0fffff)
#define SDCC_HC_CDR_SELEXT_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_CDR_SELEXT_WR_MASK) | ((data & SDCC_HC_CDR_SELEXT_MASK) << 20));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_CDR_SELEXT_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 20) & SDCC_HC_CDR_SELEXT_MASK);\
} while (0)
#define SDCC_HC_CDR_EXT_EN_MASK (ULONG)(0x1)
#define SDCC_HC_CDR_EXT_EN_WR_MASK (ULONG)(0xfff7ffff)
#define SDCC_HC_CDR_EXT_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_CDR_EXT_EN_WR_MASK) | ((data & SDCC_HC_CDR_EXT_EN_MASK) << 19));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_CDR_EXT_EN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 19) & SDCC_HC_CDR_EXT_EN_MASK);\
} while (0)
#define SDCC_HC_CK_OUT_EN_MASK (ULONG)(0x1)
#define SDCC_HC_CK_OUT_EN_WR_MASK (ULONG)(0xfffbffff)
#define SDCC_HC_CK_OUT_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_CK_OUT_EN_WR_MASK) | ((data & SDCC_HC_CK_OUT_EN_MASK) << 18));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_CK_OUT_EN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 18) & SDCC_HC_CK_OUT_EN_MASK);\
} while (0)
#define SDCC_HC_CDR_EN_MASK (ULONG)(0x1)
#define SDCC_HC_CDR_EN_WR_MASK (ULONG)(0xfffdffff)
#define SDCC_HC_CDR_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_CDR_EN_WR_MASK) | ((data & SDCC_HC_CDR_EN_MASK) << 17));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_CDR_EN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 17) & SDCC_HC_CDR_EN_MASK);\
} while (0)
#define SDCC_HC_MCLK_GATING_ENABLE_MASK (ULONG)(0x1)
#define SDCC_HC_MCLK_GATING_ENABLE_WR_MASK (ULONG)(0xffffffdf)
#define SDCC_HC_MCLK_GATING_ENABLE_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_MCLK_GATING_ENABLE_WR_MASK) | ((data & SDCC_HC_MCLK_GATING_ENABLE_MASK) << 5));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_MCLK_GATING_ENABLE_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 5) & SDCC_HC_MCLK_GATING_ENABLE_MASK);\
} while (0)
#define SDCC_HC_CDR_FINE_PHASE_MASK (ULONG)(0x1)
#define SDCC_HC_CDR_FINE_PHASE_WR_MASK (ULONG)(0xfffffff3)
#define SDCC_HC_CDR_FINE_PHASE_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_CDR_FINE_PHASE_WR_MASK) | ((data & SDCC_HC_CDR_FINE_PHASE_MASK) << 2));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_CDR_FINE_PHASE_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 2) & SDCC_HC_CDR_FINE_PHASE_MASK);\
} while (0)
#define SDCC_HC_DLL_EN_MASK (ULONG)(0x1)
#define SDCC_HC_DLL_EN_WR_MASK (ULONG)(0xfffeffff)
#define SDCC_HC_DLL_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_DLL_EN_WR_MASK) | ((data & SDCC_HC_DLL_EN_MASK) << 16));\
SDCC_HC_REG_DLL_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_DLL_EN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_RGRD(data);\
data = ((data >> 16) & SDCC_HC_DLL_EN_MASK);\
} while (0)
/* Read Write register operations for EMAC_SDCC_HC_REG_DDR_CONFIG */
#define SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET (0x0000000C)
#define SDCC_HC_REG_DDR_CONFIG_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + SDCC_HC_REG_DDR_CONFIG_RGOFFADDR_OFFSET))
#define SDCC_HC_REG_DDR_CONFIG_RGWR(data) do {\
iowrite32(data, (void *)SDCC_HC_REG_DDR_CONFIG_RGOFFADDR);\
} while (0)
#define SDCC_HC_REG_DDR_CONFIG_RGRD(data) do {\
(data) = ioread32((void *)SDCC_HC_REG_DDR_CONFIG_RGOFFADDR);\
} while (0)
#define SDCC_HC_PRG_RCLK_DLY_MASK (ULONG)(0x1ff)
#define SDCC_HC_PRG_RCLK_DLY_WR_MASK (ULONG)(0xfffffe00)
#define SDCC_HC_PRG_RCLK_DLY_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DDR_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_PRG_RCLK_DLY_WR_MASK) | ((data & SDCC_HC_PRG_RCLK_DLY_MASK) << 0));\
SDCC_HC_REG_DDR_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_PRG_RCLK_DLY_UDFRD(data) do {\
SDCC_HC_REG_DDR_CONFIG_RGRD(data);\
data = ((data >> 0) & SDCC_HC_PRG_RCLK_DLY_MASK);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_MASK (ULONG)(0x3f)
#define SDCC_HC_EXT_PRG_RCLK_DLY_WR_MASK (ULONG)(0xf81fffff)
#define SDCC_HC_EXT_PRG_RCLK_DLY_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DDR_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_EXT_PRG_RCLK_DLY_WR_MASK) | ((data & SDCC_HC_EXT_PRG_RCLK_DLY_MASK) << 21));\
SDCC_HC_REG_DDR_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_UDFRD(data) do {\
SDCC_HC_REG_DDR_CONFIG_RGRD(data);\
data = ((data >> 0) & SDCC_HC_EXT_PRG_RCLK_DLY_MASK);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_CODE_MASK (ULONG)(0x7)
#define SDCC_HC_EXT_PRG_RCLK_DLY_CODE_WR_MASK (ULONG)(0xc7ffffff)
#define SDCC_HC_EXT_PRG_RCLK_DLY_CODE_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DDR_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_EXT_PRG_RCLK_DLY_CODE_WR_MASK) | ((data & SDCC_HC_EXT_PRG_RCLK_DLY_CODE_MASK) << 27));\
SDCC_HC_REG_DDR_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_CODE_UDFRD(data) do {\
SDCC_HC_REG_DDR_CONFIG_RGRD(data);\
data = ((data >> 0) & SDCC_HC_EXT_PRG_RCLK_DLY_CODE_MASK);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_EN_MASK (ULONG)(0x1)
#define SDCC_HC_EXT_PRG_RCLK_DLY_EN_WR_MASK (ULONG)(0xbfffffff)
#define SDCC_HC_EXT_PRG_RCLK_DLY_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DDR_CONFIG_RGRD(v);\
v = ((v & SDCC_HC_EXT_PRG_RCLK_DLY_EN_WR_MASK) | ((data & SDCC_HC_EXT_PRG_RCLK_DLY_EN_MASK) << 30));\
SDCC_HC_REG_DDR_CONFIG_RGWR(v);\
} while (0)
#define SDCC_HC_EXT_PRG_RCLK_DLY_EN_UDFRD(data) do {\
SDCC_HC_REG_DDR_CONFIG_RGRD(data);\
data = ((data >> 0) & SDCC_HC_EXT_PRG_RCLK_DLY_EN_MASK);\
} while (0)
/* Read Write register operations for EMAC_SDCC_HC_REG_DLL_CONFIG_2 */
#define SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET (0x00000010)
#define SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR_OFFSET))
#define SDCC_HC_REG_DLL_CONFIG_2_RGWR(data) do {\
iowrite32(data, (void *)SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR);\
} while (0)
#define SDCC_HC_REG_DLL_CONFIG_2_RGRD(data) do {\
(data) = ioread32((void *)SDCC_HC_REG_DLL_CONFIG_2_RGOFFADDR);\
} while (0)
#define SDCC_HC_CFG_2_MCLK_FREQ_CALC_MASK (ULONG)(0xff)
#define SDCC_HC_CFG_2_MCLK_FREQ_CALC_WR_MASK (ULONG)(0xfffc03ff)
#define SDCC_HC_CFG_2_MCLK_FREQ_CALC_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(v);\
v = ((v & SDCC_HC_CFG_2_MCLK_FREQ_CALC_WR_MASK) | ((data & SDCC_HC_CFG_2_MCLK_FREQ_CALC_MASK) << 10));\
SDCC_HC_REG_DLL_CONFIG_2_RGWR(v);\
} while (0)
#define SDCC_HC_CFG_2_MCLK_FREQ_CALC_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(data);\
data = ((data >> 10) & SDCC_HC_CFG_2_MCLK_FREQ_CALC_MASK);\
} while (0)
#define SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_MASK (ULONG)(0x1)
#define SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_WR_MASK (ULONG)(0xffdfffff)
#define SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(v);\
v = ((v & SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_WR_MASK) | ((data & SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_MASK) << 21));\
SDCC_HC_REG_DLL_CONFIG_2_RGWR(v);\
} while (0)
#define SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(data);\
data = ((data >> 21) & SDCC_HC_CFG_2_DLL_CLOCK_DISABLE_MASK);\
} while (0)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_MASK (ULONG)(0x1)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_WR_MASK (ULONG)(0xfffffff3)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(v);\
v = ((v & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_WR_MASK) | ((data & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_MASK) << 2));\
SDCC_HC_REG_DLL_CONFIG_2_RGWR(v);\
} while (0)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(data);\
data = ((data >> 2) & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SEL_MASK);\
} while (0)
#define SDCC_HC_CFG_2_DDR_CAL_EN_MASK (ULONG)(0x1)
#define SDCC_HC_CFG_2_DDR_CAL_EN_WR_MASK (ULONG)(0xfffffffe)
#define SDCC_HC_CFG_2_DDR_CAL_EN_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(v);\
v = ((v & SDCC_HC_CFG_2_DDR_CAL_EN_WR_MASK) | ((data & SDCC_HC_CFG_2_DDR_CAL_EN_MASK) << 0));\
SDCC_HC_REG_DLL_CONFIG_2_RGWR(v);\
} while (0)
#define SDCC_HC_CFG_2_DDR_CAL_EN_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(data);\
data = ((data >> 0) & SDCC_HC_CFG_2_DDR_CAL_EN_MASK);\
} while (0)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_MASK (ULONG)(0x1)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_WR_MASK (ULONG)(0xfffffffd)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_UDFWR(data) do {\
ULONG v;\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(v);\
v = ((v & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_WR_MASK) | ((data & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_MASK) << 1));\
SDCC_HC_REG_DLL_CONFIG_2_RGWR(v);\
} while (0)
#define SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_UDFRD(data) do {\
SDCC_HC_REG_DLL_CONFIG_2_RGRD(data);\
data = ((data >> 0) & SDCC_HC_CFG_2_DDR_TRAFFIC_INIT_SW_MASK);\
} while (0)
/* Read register operations for EMAC_SDC4_STATUS */
#define SDC4_STATUS_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + 0x00000014))
#define SDC4_STATUS_RGRD(data) do {\
(data) = ioread32((void *)SDC4_STATUS_RGOFFADDR);\
} while (0)
#define SDC4_STATUS_DLL_LOCK_STS_MASK (ULONG)(0x1)
#define SDC4_STATUS_DLL_LOCK_STS_UDFRD(data) do {\
SDC4_STATUS_RGRD(data);\
data = ((data >> 7) & SDC4_STATUS_DLL_LOCK_STS_MASK);\
} while (0)
/* Read register operations for EMAC_SDCC_USR_CTL */
#define SDCC_USR_CTL_RGOFFADDR_OFFSET (0x00000018)
#define SDCC_USR_CTL_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + SDCC_USR_CTL_RGOFFADDR_OFFSET))
#define SDCC_USR_CTL_BYPASS_MODE_MASK (ULONG)(0x1)
#define SDCC_USR_CTL_BYPASS_MODE_WR_MASK (ULONG)(0xbfffffff)
#define SDCC_USR_CTL_RGRD(data) do {\
(data) = ioread32((void *)SDCC_USR_CTL_RGOFFADDR);\
} while (0)
#define SDCC_USR_CTL_RGWR(data) do {\
iowrite32(data, (void *)SDCC_USR_CTL_RGOFFADDR);\
} while (0)
#define SDCC_USR_CTL_BYPASS_MODE_UDFRD(data) do {\
SDCC_USR_CTL_RGRD(data);\
data = ((data >> 30) & SDCC_USR_CTL_BYPASS_MODE_MASK);\
} while (0)
#define SDCC_USR_CTL_BYPASS_MODE_UDFWR(data) do {\
ULONG v;\
SDCC_USR_CTL_RGRD(v);\
v = ((v & SDCC_USR_CTL_BYPASS_MODE_WR_MASK) | ((data & SDCC_USR_CTL_BYPASS_MODE_MASK) << 30));\
SDCC_USR_CTL_RGWR(v);\
} while (0)
/* Read Write register operations for
* EMAC_RGMII_IO_MACRO_CONFIG_2
*/
#define RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET (0x0000001C)
#define RGMII_IO_MACRO_CONFIG_2_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + RGMII_IO_MACRO_CONFIG_2_RGOFFADDR_OFFSET))
#define RGMII_IO_MACRO_CONFIG_2_RGWR(data) do {\
iowrite32(data, (void *)RGMII_IO_MACRO_CONFIG_2_RGOFFADDR);\
} while (0)
#define RGMII_IO_MACRO_CONFIG_2_RGRD(data) do {\
(data) = ioread32((void *)RGMII_IO_MACRO_CONFIG_2_RGOFFADDR);\
} while (0)
#define RGMII_DATA_DIVIDE_CLK_SEL_MASK (ULONG)(0x1)
#define RGMII_DATA_DIVIDE_CLK_SEL_WR_MASK (ULONG)(0xffffffbf)
#define RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_DATA_DIVIDE_CLK_SEL_WR_MASK) | ((data & RGMII_DATA_DIVIDE_CLK_SEL_MASK) << 6));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_DATA_DIVIDE_CLK_SEL_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 6) & RGMII_DATA_DIVIDE_CLK_SEL_MASK);\
} while (0)
#define RGMII_TX_CLK_PHASE_SHIFT_EN_MASK (ULONG)(0x1)
#define RGMII_TX_CLK_PHASE_SHIFT_EN_WR_MASK (ULONG)(0xffffffdf)
#define RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_TX_CLK_PHASE_SHIFT_EN_WR_MASK) | ((data & RGMII_TX_CLK_PHASE_SHIFT_EN_MASK) << 5));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_TX_CLK_PHASE_SHIFT_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 5) & RGMII_TX_CLK_PHASE_SHIFT_EN_MASK);\
} while (0)
#define RGMII_TX_TO_RX_LOOPBACK_EN_MASK (ULONG)(0x1)
#define RGMII_TX_TO_RX_LOOPBACK_EN_WR_MASK (ULONG)(0xffffdfff)
#define RGMII_CONFIG_2_TX_TO_RX_LOOPBACK_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_TX_TO_RX_LOOPBACK_EN_WR_MASK) | ((data & RGMII_TX_TO_RX_LOOPBACK_EN_MASK) << 13));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_TX_TO_RX_LOOPBACK_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 13) & RGMII_TX_TO_RX_LOOPBACK_EN_MASK);\
} while (0)
#define RGMII_RX_PROG_SWAP_MASK (ULONG)(0x1)
#define RGMII_RX_PROG_SWAP_WR_MASK (ULONG)(0xffffff7f)
#define RGMII_CONFIG_2_RX_PROG_SWAP_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_RX_PROG_SWAP_WR_MASK) | ((data & RGMII_RX_PROG_SWAP_MASK) << 7));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_RX_PROG_SWAP_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 7) & RGMII_RX_PROG_SWAP_MASK);\
} while (0)
#define RGMII_CLK_DIVIDE_SEL_MASK (ULONG)(0x1)
#define RGMII_CLK_DIVIDE_SEL_WR_MASK (ULONG)(0xffffefff)
#define RGMII_CONFIG_2_CLK_DIVIDE_SEL_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_CLK_DIVIDE_SEL_WR_MASK) | ((data & RGMII_CLK_DIVIDE_SEL_MASK) << 12));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_CLK_DIVIDE_SEL_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 7) & RGMII_CLK_DIVIDE_SEL_MASK);\
} while (0)
#define RGMII_RERVED_CONFIG_16_EN_MASK (ULONG)(0xffff)
#define RGMII_RERVED_CONFIG_16_EN_WR_MASK (ULONG)(0x0000ffff)
#define RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFWR(data) do {\
ULONG v;\
RGMII_IO_MACRO_CONFIG_2_RGRD(v);\
v = ((v & RGMII_RERVED_CONFIG_16_EN_WR_MASK) | ((data & RGMII_RERVED_CONFIG_16_EN_MASK) << 16));\
RGMII_IO_MACRO_CONFIG_2_RGWR(v);\
} while (0)
#define RGMII_CONFIG_2_RERVED_CONFIG_16_EN_UDFRD(data) do {\
RGMII_IO_MACRO_CONFIG_2_RGRD(data);\
data = ((data >> 16) & RGMII_RERVED_CONFIG_16_EN_MASK);\
} while (0)
/* EMAC_RGMII_IO_MACRO_DEBUG_1 */
#define RGMII_IO_MACRO_DEBUG_1_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + 0x00000020))
#define RGMII_IO_MACRO_DEBUG_1_RGRD(data) do {\
(data) = ioread32((void *)RGMII_IO_MACRO_DEBUG_1_RGOFFADDR);\
} while (0)
/* EMAC_SYSTEM_LOW_POWER_DEBUG */
#define EMAC_SYSTEM_LOW_POWER_DEBUG_RGOFFADDR ((volatile ULONG *)(RGMII_IO_BASE_ADDRESS + 0x00000028))
#define EMAC_SYSTEM_LOW_POWER_DEBUG_RGRD(data) do {\
(data) = ioread32((void *)EMAC_SYSTEM_LOW_POWER_DEBUG_RGOFFADDR);\
} while (0)
void dump_rgmii_io_macro_registers(void);
#endif

View File

@@ -0,0 +1,13 @@
# Kernel module instructions go here.
obj-m := emac_dwc_eqos.o
emac_dwc_eqos-y := DWC_ETH_QOS_dev.o DWC_ETH_QOS_drv.o DWC_ETH_QOS_desc.o DWC_ETH_QOS_ethtool.o DWC_ETH_QOS_platform.o DWC_ETH_QOS_mdio.o DWC_ETH_QOS_eee.o DWC_ETH_QOS_rgmii_io_macro.o DWC_ETH_QOS_poll_support.o
ifeq ($(CONFIG_PTP_1588_CLOCK), y)
EXTRA_CFLAGS+=-DCONFIG_PTPSUPPORT_OBJ
emac_dwc_eqos-y += DWC_ETH_QOS_ptp.o
endif
ifeq ($(CONFIG_IPA_OFFLOAD), 1)
EXTRA_CFLAGS+=-DDWC_ETH_QOS_ENABLE_IPA
emac_dwc_eqos-y += DWC_ETH_QOS_ipa.o
endif

View File

@@ -0,0 +1,11 @@
#
# Synopsis EMAC device configuration
#
config EMAC_DWC_EQOS
tristate "Qualcomm Technologies Inc. EMAC support"
depends on (ARM || ARM64)
default y
help
This driver supports the Synopsis EMAC Gigabit
Ethernet controller.

View File

@@ -0,0 +1,6 @@
config EMAC_APP
bool "EMAC app support"
depends on EMAC_DWC_EQOS
default y
help
Say y here if you want to run Neutrino ethernet open function

View File

@@ -0,0 +1,52 @@
export PTPSUPPORT CONFIG_PTPSUPPORT_OBJ DWC_ETH_QOS_CONFIG_PTP
#default values
PTPSUPPORT=y #ptp is enabled
ifeq ($(RELEASE_PACKAGE),1)
EXTRA_CFLAGS+=-DRELEASE_PACKAGE
endif
LBITS ?= $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
CCFLAGS += -m64
EXTRA_CFLAGS+=-DSYSTEM_IS_64
else
CCFLAGS += -m32
endif
ifeq "$(PTPSUPPORT)" "y"
CONFIG_PTPSUPPORT_OBJ=y
DWC_ETH_QOS_CONFIG_PTP=-DPTPSUPPORT
EXTRA_CFLAGS+=-DCONFIG_PTPSUPPORT_OBJ
else
CONFIG_PTPSUPPORT_OBJ=y
endif
ifeq ($(CONFIG_IPA_OFFLOAD), 1)
CDEFINES+=-DDWC_ETH_QOS_ENABLE_IPA
emac_dwc_eqos-y += DWC_ETH_QOS_ipa.o
endif
obj-m := emac_dwc_eqos.o
emac_dwc_eqos-y += DWC_ETH_QOS_dev.o \
DWC_ETH_QOS_drv.o \
DWC_ETH_QOS_desc.o \
DWC_ETH_QOS_ethtool.o \
DWC_ETH_QOS_platform.o \
DWC_ETH_QOS_mdio.o \
DWC_ETH_QOS_eee.o \
DWC_ETH_QOS_rgmii_io_macro.o
emac_dwc_eqos-$(CONFIG_PTPSUPPORT_OBJ) += DWC_ETH_QOS_ptp.o
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules_install
clean:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

View File

@@ -0,0 +1,49 @@
export PTPSUPPORT CONFIG_PTPSUPPORT_OBJ DWC_ETH_QOS_CONFIG_PTP
#default values
PTPSUPPORT=y #ptp is enabled
ifeq ($(RELEASE_PACKAGE),1)
EXTRA_CFLAGS+=-DRELEASE_PACKAGE
endif
LBITS := $(shell getconf LONG_BIT)
ifeq ($(LBITS),64)
CCFLAGS += -m64
EXTRA_CFLAGS+=-DSYSTEM_IS_64
else
CCFLAGS += -m32
endif
ifeq "$(PTPSUPPORT)" "y"
CONFIG_PTPSUPPORT_OBJ=y
DWC_ETH_QOS_CONFIG_PTP=-DPTPSUPPORT
EXTRA_CFLAGS+=-DCONFIG_PTPSUPPORT_OBJ
else
CONFIG_PTPSUPPORT_OBJ=y
endif
emacdir = $(prefix)/emac
emac_CFLAGS = -Werror
KERNEL_FLAGS ?= ARCH=arm
module = emac_dwc_eqos.ko
kmake = $(MAKE) $(KERNEL_FLAGS) -C $(KERNEL_DIR) M=$(CURDIR)
$(module):
$(kmake) modules
all-local: $(module)
install-exec-local: $(module)
$(kmake) INSTALL_MOD_PATH=$(DESTDIR)$(prefix)/modules modules_install
# "make distclean" will always run clean-local in this directory,
# regardless of the KERNELMODULES conditional. Therefore, ensure
# KERNEL_DIR exists before running clean. Further, don't fail even
# if there is a problem.
clean-local:
-test ! -d "$(KERNEL_DIR)" || $(kmake) clean

View File

@@ -0,0 +1,21 @@
obj-$(CONFIG_EMAC_DWC_EQOS) += DWC_ETH_QOS_dev.o \
DWC_ETH_QOS_drv.o \
DWC_ETH_QOS_desc.o \
DWC_ETH_QOS_ethtool.o \
DWC_ETH_QOS_mdio.o \
DWC_ETH_QOS_eee.o \
DWC_ETH_QOS_platform.o \
DWC_ETH_QOS_rgmii_io_macro.o \
DWC_ETH_QOS_poll_support.o
ifeq ($(CONFIG_PTP_1588_CLOCK), y)
EXTRA_CFLAGS+=-DCONFIG_PTPSUPPORT_OBJ
obj-$(CONFIG_EMAC_DWC_EQOS) += DWC_ETH_QOS_ptp.o
endif
ifeq ($(CONFIG_IPA_OFFLOAD), y)
KBUILD_CFLAGS += -DDWC_ETH_QOS_ENABLE_IPA
obj-$(CONFIG_EMAC_DWC_EQOS) += DWC_ETH_QOS_ipa.o
endif
KBUILD_CFLAGS += -DDWC_ETH_QOS_BUILTIN

View File

@@ -0,0 +1,4 @@
#
# Makefile for the DWC_ETH_QOS app kernel module
#
obj-$(CONFIG_EMAC_APP) = DWC_ETH_QOS_app.o

View File

@@ -0,0 +1,22 @@
#!/vendor/bin/sh
#Copyright (c) 2019, The Linux Foundation. All rights reserved.
#
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License version 2 and
#only 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.
#
#
echo 12582912 > /proc/sys/net/core/wmem_max;
echo 12582912 > /proc/sys/net/core/rmem_max;
echo 10240 87380 12582912 > /proc/sys/net/ipv4/tcp_rmem;
echo 10240 87380 12582912 > /proc/sys/net/ipv4/tcp_wmem;
echo 12582912 > /proc/sys/net/ipv4/udp_rmem_min;
echo 12582912 > /proc/sys/net/ipv4/udp_wmem_min;
echo 1 > /proc/sys/net/ipv4/tcp_window_scaling;
echo 18 > /sys/class/net/eth0/queues/rx-0/rps_cpus;

View File

@@ -0,0 +1,19 @@
# Android makefile for SMEM kernel modules
ifeq ($(call is-board-platform-in-list,sun), true)
ifneq (,$(filter arm aarch64 arm64, $(TARGET_ARCH)))
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE_DDK_BUILD := true
DLKM_DIR := device/qcom/common/dlkm
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(LOCAL_PATH)/smem-mailbox.c
LOCAL_EXPORT_KO_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MODULE := smem-mailbox.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/Build_external_kernelmodule.mk
endif
endif

View File

@@ -0,0 +1,10 @@
load(":define_modules.bzl", "define_modules")
define_modules("sun", "consolidate")
define_modules("sun", "perf")
package(
default_visibility = [
"//visibility:public",
],
)

View File

@@ -0,0 +1,14 @@
KBUILD_OPTIONS += SMEM_MAILBOX_ROOT=$(KERNEL_SRC)/$(M)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) M=$(M) -C $(KERNEL_SRC) modules_install
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
clean:
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
rm -rf .tmp_versions

View File

@@ -0,0 +1,32 @@
load("//build/kernel/kleaf:kernel.bzl", "ddk_module")
load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir")
def define_modules(target, variant):
kernel_build_variant = "{}_{}".format(target, variant)
ddk_module(
name = "{}_smem_mailbox".format(kernel_build_variant),
kernel_build = "//msm-kernel:{}".format(kernel_build_variant),
deps = ["//msm-kernel:all_headers"],
srcs = [
"smem-mailbox.c"
],
hdrs = [
"include/smem-mailbox.h"
],
includes = [
"include"
],
out = "smem-mailbox.ko",
visibility = ["//visibility:public"]
)
copy_to_dist_dir(
name = "{}_smem_mailbox_dist".format(kernel_build_variant),
data = [":{}_smem_mailbox".format(kernel_build_variant)],
dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(kernel_build_variant),
flat = True,
wipe_dist_dir = False,
allow_duplicate_filenames = False,
mode_overrides = {"**/*": "644"},
)

View File

@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __SMEM_MAILBOX_H__
#include <linux/types.h>
/* Flags for Write API */
#define FLAG_URGENT 1
typedef void (*smem_mailbox_urgent_cb)(u16 pending_bytes);
/* API's Exposed to External Modules */
int smem_mailbox_start(int id, smem_mailbox_urgent_cb urgent_cb);
int smem_mailbox_stop(int id);
int smem_mailbox_read(int id, u8 **data, u16 *data_length, unsigned long long *xo_time);
int smem_mailbox_write(int id, int flags, __u8 *data, u16 data_length);
#endif

View File

@@ -0,0 +1,2 @@
LINUXINCLUDE += -I$(SMEM_MAILBOX_ROOT)/include
obj-m := smem-mailbox.o

View File

@@ -0,0 +1,577 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/types.h>
#include <linux/version.h>
#include <net/genetlink.h>
#include "smem-mailbox.h"
#define SMEM_VERSION 0x00000001 // v0.1
#define START_COOKIE 0xbeefcafe
#define END_COOKIE 0x0fed0fed
#define DEVICE_NAME "smem_mailbox"
#define HEAD_PTR_SIZE 4
#define TAIL_PTR_SIZE 4
#define BUF_IO_PTR_SIZE HEAD_PTR_SIZE + TAIL_PTR_SIZE
#define GET_READ_HEAD(smem, entry) *(u32 *)(smem + entry->start_loc)
#define GET_READ_TAIL(smem, entry) *(u32 *)(smem + entry->start_loc + HEAD_PTR_SIZE)
#define GET_READ_BUF(smem, entry) smem + entry->start_loc + BUF_IO_PTR_SIZE
#define GET_WRITE_HEAD(smem, entry) \
*(u32 *)(smem + entry->start_loc + BUF_IO_PTR_SIZE + entry->read_size)
#define GET_WRITE_TAIL(smem, entry) \
*(u32 *)(smem + entry->start_loc + BUF_IO_PTR_SIZE + entry->read_size + HEAD_PTR_SIZE)
#define GET_WRITE_BUF(smem, entry) \
smem + entry->start_loc + BUF_IO_PTR_SIZE + entry->read_size + BUF_IO_PTR_SIZE
#define UPDATE_WRITE_HEAD(smem, value) \
memcpy_toio(smem + entry->start_loc + BUF_IO_PTR_SIZE + entry->read_size, &value, \
sizeof(value));
#define UPDATE_READ_TAIL(smem, value) \
memcpy_toio(smem + entry->start_loc + HEAD_PTR_SIZE, &value, sizeof(value));
// This list must match the configured names in the device tree for the smp2p in (IRQ).
#define IRQ_NUM_NAMES 4
static char *IRQ_NAMES[] = {"smem-mailbox-smp2p-1-in", "smem-mailbox-smp2p-2-in",
"smem-mailbox-smp2p-3-in", "smem-mailbox-smp2p-4-in"};
#define SMEM_DESCRIPTOR 655
/* SMEM host id representing the modem. */
#define QCOM_SMEM_HOST_MODEM 1
struct smem_client_channel {
struct list_head list;
u32 id;
u32 start_loc;
u32 read_size;
u32 write_size;
bool client_connected;
char irq_name[24];
smem_mailbox_urgent_cb urgent_cb;
};
static LIST_HEAD(smem_client_channel_list_head);
struct mailbox_smp2p {
struct qcom_smem_state *smem_state;
u32 smem_bit;
};
struct mailbox_smp2p *mailbox;
struct device *dev;
struct client_info {
u32 id;
u32 start_loc;
u32 read_size;
u32 write_size;
};
struct smem_info {
u32 start_cookie;
u32 version;
u32 num_of_clients;
struct client_info clients[4];
u32 end_cookie;
};
bool info_validated;
#define TLV_TYPE_TIME 0
#define TLV_TYPE_DATA 1
#define TLV_TYPE_MODULE_MAX 32767
// TLV range of 32,768 - 65,535 is reserved for client use.
struct tlv {
u16 type;
u16 length;
};
int free_bytes(u32 head, u32 tail, u32 max) {
int free_bytes = 0;
if (head >= tail) {
free_bytes = max - head + tail;
} else {
free_bytes = tail - head;
}
return free_bytes;
}
static irqreturn_t smem_read_ready(int irq, void *channel)
{
int id = 0;
int pending_bytes = 0;
void *smem;
size_t size;
struct smem_client_channel *entry = NULL;
id = ((struct smem_client_channel *)channel)->id;
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
if (entry->id == id) break;
}
if (entry == NULL || entry->id != id) {
pr_err(KERN_ALERT "smem: ID does not match any smem sub allocation %d\n", id);
return IRQ_HANDLED;
}
if (!entry->client_connected) {
pr_err(KERN_ALERT "smem: there is no connected client for ID %d, ignore\n", id);
return IRQ_HANDLED;
}
smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return IRQ_HANDLED;
}
pending_bytes = entry->read_size -
free_bytes(GET_READ_HEAD(smem, entry), GET_READ_TAIL(smem, entry), entry->read_size);
entry->urgent_cb(pending_bytes);
return IRQ_HANDLED;
}
static bool read_client_info_map(void) {
int ret = 0;
int irq;
size_t info_size;
struct smem_info smem_info;
struct device_node *node = dev->of_node;
struct smem_client_channel *entry = NULL;
void *smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &info_size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return -1;
}
memcpy_fromio(&smem_info, smem, sizeof(struct smem_info));
info_validated = false;
if (smem_info.start_cookie != START_COOKIE) {
pr_err(KERN_ALERT "smem: start cookie does not match %d\n", smem_info.start_cookie);
return false;
}
if (smem_info.version != SMEM_VERSION) {
pr_err(KERN_ALERT "smem: version does not match %d\n", smem_info.version);
return false;
}
for (u32 i = 0; i < smem_info.num_of_clients && i < IRQ_NUM_NAMES; i++) {
struct client_info client = smem_info.clients[i];
u32 id = client.id;
u32 start_loc = client.start_loc;
u32 read_size = client.read_size;
u32 write_size = client.write_size;
struct smem_client_channel *new_entry;
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
new_entry->id = id;
new_entry->start_loc = start_loc;
new_entry->read_size = read_size;
new_entry->write_size = write_size;
// IRQ name is hardcoded
strscpy(new_entry->irq_name, IRQ_NAMES[i], sizeof(new_entry->irq_name));
INIT_LIST_HEAD(&new_entry->list);
list_add_tail(&new_entry->list, &smem_client_channel_list_head);
}
if (smem_info.end_cookie != END_COOKIE) {
pr_err(KERN_ALERT "smem: end cookie does not match %d\n", smem_info.end_cookie);
return false;
}
info_validated = true;
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
irq = ret = of_irq_get_byname(node, entry->irq_name);
if (ret < 0) {
pr_err("%s: smem platform_get_irq_byname fail. %d %s\n", __func__, ret,
entry->irq_name);
return 1;
}
ret = devm_request_threaded_irq(dev, irq, NULL, smem_read_ready,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, entry->irq_name,
entry);
if (ret < 0) {
pr_err("%s: smem request_threaded_irq fail. %d\n", __func__, ret);
return 1;
}
}
return true;
}
static int smem_probe(struct platform_device *pdev) {
dev = &pdev->dev;
if (mailbox == NULL) {
mailbox = kzalloc(sizeof(struct mailbox_smp2p), GFP_KERNEL);
}
mailbox->smem_state = qcom_smem_state_get(dev, "smem-mailbox-smp2p-out", &mailbox->smem_bit);
if (IS_ERR(mailbox->smem_state)) {
pr_err("%s: smem fail to get smp2p clk resp bit %ld\n", __func__,
PTR_ERR(mailbox->smem_state));
return 1;
}
// Attempt to read client map. This should fail at boot since modem is not up. Retry at first
// client connection.
read_client_info_map();
return 0;
}
static int smem_remove(struct platform_device *pdev) {
return 0;
}
int smem_mailbox_start(int id, smem_mailbox_urgent_cb urgent_cb) {
struct smem_client_channel *entry = NULL;
if (!info_validated && !read_client_info_map()) {
pr_err(KERN_ALERT "smem: client info map has not been setup by modem.\n");
return -EAGAIN;
}
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
if (entry->id == id) break;
}
if (entry == NULL || entry->id != id) {
pr_err(KERN_ALERT "smem: ID does not match any smem sub allocation %d\n", id);
return -EINVAL;
}
if (entry->client_connected) {
pr_err(KERN_ALERT "smem: there is already a client connected to this ID %d\n", id);
return -EPERM;
}
entry->urgent_cb = urgent_cb;
entry->client_connected = true;
return 1;
}
EXPORT_SYMBOL(smem_mailbox_start);
int smem_mailbox_stop(int id) {
void *smem;
size_t size;
u32 read_head_index;
u32 read_tail_index;
u32 write_head_index;
u32 write_tail_index;
struct smem_client_channel *entry = NULL;
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
if (entry->id == id) break;
}
if (entry == NULL || entry->id != id) {
pr_err(KERN_ALERT "smem: ID does not match any smem sub allocation %d\n", id);
return -EINVAL;
}
if (!entry->client_connected) {
pr_err(KERN_ALERT "smem: client never started this ID %d\n", id);
return -EPERM;
}
smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return -ENOMEM;
}
read_head_index = GET_READ_HEAD(smem, entry);
read_tail_index = GET_READ_TAIL(smem, entry);
if (read_head_index != read_tail_index) {
pr_err("%s: smem read_head_index %d does not equal read_tail_index %d.\n", __func__,
read_head_index, read_tail_index);
UPDATE_READ_TAIL(smem, read_head_index);
}
write_head_index = GET_WRITE_HEAD(smem, entry);
write_tail_index = GET_WRITE_TAIL(smem, entry);
if (write_head_index != write_tail_index) {
pr_err("%s: smem write_head_index %d does not equal write_tail_index %d.\n", __func__,
write_head_index, write_tail_index);
UPDATE_WRITE_HEAD(smem, write_tail_index);
}
entry->client_connected = false;
return 1;
}
EXPORT_SYMBOL(smem_mailbox_stop);
bool read_item(struct smem_client_channel *entry, void *item, u16 item_size) {
int offset;
void *smem;
void *read_buf;
size_t size;
u32 head_index;
u32 tail_index;
smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return false;
}
head_index = GET_READ_HEAD(smem, entry);
tail_index = GET_READ_TAIL(smem, entry);
offset = tail_index + item_size - entry->read_size;
read_buf = GET_READ_BUF(smem, entry);
if (offset > 0) {
if (offset > head_index) {
pr_err("%s: smem item size is greater than remaining buffer. head %d\n", __func__,
head_index);
tail_index = head_index;
UPDATE_READ_TAIL(smem, tail_index);
return false;
}
memcpy_fromio(item, read_buf + tail_index, item_size - offset);
memcpy_fromio(item + (item_size - offset), read_buf, offset);
UPDATE_READ_TAIL(smem, offset);
} else {
if ((tail_index + item_size) > head_index) {
pr_err("%s: smem item size is greater than remaining buffer. head %d\n", __func__,
head_index);
tail_index = head_index;
UPDATE_READ_TAIL(smem, tail_index);
return false;
}
memcpy_fromio(item, read_buf + tail_index, item_size);
tail_index = tail_index + item_size;
UPDATE_READ_TAIL(smem, tail_index);
}
return true;
}
int smem_mailbox_read(int id, u8 **data, u16 *data_length, unsigned long long *xo_time) {
bool ret;
size_t size;
void *smem;
struct smem_client_channel *entry = NULL;
u32 head_index;
u32 tail_index;
int word_offset;
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
if (entry->id == id) break;
}
if (entry == NULL || entry->id != id) {
pr_err(KERN_ALERT "smem: incorrect ID %d\n", id);
return -EINVAL;
}
if (!entry->client_connected) {
pr_err(KERN_ALERT "smem: client never started this ID %d\n", id);
return -EPERM;
}
smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return -ENOMEM;
}
head_index = GET_READ_HEAD(smem, entry);
tail_index = GET_READ_TAIL(smem, entry);
if (head_index == tail_index) {
pr_err("%s: smem qcom_smem_get nothing to read for this client %d. %d %d \n", __func__, id,
head_index, tail_index);
return -ENOMSG;
}
while (true) {
struct tlv temp_tlv;
ret = read_item(entry, &temp_tlv, sizeof(struct tlv));
if (!ret) goto exit_loop;
switch (temp_tlv.type) {
case TLV_TYPE_TIME:
ret = read_item(entry, xo_time, sizeof(unsigned long long));
if (!ret) goto exit_loop;
break;
case TLV_TYPE_DATA:
*data_length = temp_tlv.length - sizeof(struct tlv);
*data = kmalloc(*data_length, GFP_KERNEL);
ret = read_item(entry, *data, *data_length);
if (!ret) goto exit_loop;
// Round to next word.
word_offset = 4 - (*data_length % 4);
if (word_offset > 0) {
tail_index = GET_READ_TAIL(smem, entry) + word_offset;
UPDATE_READ_TAIL(smem, tail_index);
}
goto exit_loop;
break;
default:
pr_err(KERN_ALERT "smem: invalid TLV type %d.\n", temp_tlv.type);
return -ENOMSG;
break;
}
}
exit_loop:
return (entry->read_size -
free_bytes(GET_READ_HEAD(smem, entry), GET_READ_TAIL(smem, entry), entry->read_size));
}
EXPORT_SYMBOL(smem_mailbox_read);
int smem_mailbox_write(int id, int flags, __u8 *data, u16 data_length) {
size_t size;
void *smem;
void *write_buf;
u32 head_index;
u32 tail_index;
u8 *buf;
struct tlv time_tlv;
struct tlv data_tlv;
struct smem_client_channel *entry = NULL;
unsigned long long xo_time = 0;
int overflow_bytes;
int buf_length;
int word_offset;
list_for_each_entry(entry, &smem_client_channel_list_head, list) {
if (entry->id == id) break;
}
if (entry == NULL || entry->id != id) {
pr_err(KERN_ALERT "smem: incorrect ID %d\n", id);
return -EINVAL;
}
if (!entry->client_connected) {
pr_err(KERN_ALERT "smem: client never started this ID %d\n", id);
return -EPERM;
}
// Size of u32 in subtracted from max size because a full buffer would be the same as an emtpy
// buffer.
if (data_length > (entry->write_size - sizeof(u32))) {
pr_err(KERN_ALERT
"smem: data size is larger than write buffer size %d, smem allocation %d\n",
data_length, entry->write_size);
return -ENOSPC;
}
smem = qcom_smem_get(QCOM_SMEM_HOST_MODEM, SMEM_DESCRIPTOR, &size);
if (IS_ERR(smem)) {
pr_err("%s: smem qcom_smem_get fail.\n", __func__);
return -ENOMEM;
}
head_index = GET_WRITE_HEAD(smem, entry);
tail_index = GET_WRITE_TAIL(smem, entry);
buf_length = sizeof(struct tlv) + sizeof(xo_time) + sizeof(struct tlv) + data_length;
// Not enough space in circular buffer, exit.
// Subtract u32 from max size so a full buffer does not have head == tail.
if (head_index > tail_index) {
if ((tail_index + (entry->write_size - head_index)) < (buf_length - sizeof(u32))) {
pr_err("%s: smem qcom_smem_get fail, not enough room in write buffer. %d %d\n",
__func__, (tail_index - head_index), buf_length);
return -ENOSPC;
}
} else if (head_index != tail_index) {
if ((tail_index - head_index) < (buf_length - sizeof(u32))) {
pr_err("%s: smem qcom_smem_get2 fail, not enough room in write buffer. %d %d\n",
__func__, (tail_index - head_index), buf_length);
return -ENOSPC;
}
}
buf = kmalloc(buf_length, GFP_KERNEL);
if (!buf) {
pr_err("%s: smem kmalloc fail.\n", __func__);
return -ENOMEM;
}
xo_time = arch_timer_read_cntvct_el0();
time_tlv.type = TLV_TYPE_TIME;
time_tlv.length = sizeof(xo_time) + sizeof(struct tlv);
memcpy(buf, &time_tlv, sizeof(time_tlv));
memcpy(buf + sizeof(time_tlv), &xo_time, sizeof(xo_time));
data_tlv.type = TLV_TYPE_DATA;
data_tlv.length = data_length + sizeof(struct tlv);
memcpy(buf + sizeof(time_tlv) + sizeof(xo_time), &data_tlv, sizeof(data_tlv));
memcpy(buf + sizeof(time_tlv) + sizeof(xo_time) + sizeof(data_tlv), data, data_length);
// Read/Write must always be word aligned for modem.
word_offset = (~4 & (4 - (buf_length % 4)));
write_buf = GET_WRITE_BUF(smem, entry);
overflow_bytes = head_index + buf_length - entry->write_size;
if (overflow_bytes < 0) {
memcpy_toio(write_buf + head_index, buf, buf_length);
head_index = head_index + buf_length + word_offset;
UPDATE_WRITE_HEAD(smem, head_index);
} else {
memcpy_toio(write_buf + head_index, buf, buf_length - overflow_bytes);
memcpy_toio(write_buf, buf + buf_length - overflow_bytes, overflow_bytes);
head_index = overflow_bytes + word_offset;
UPDATE_WRITE_HEAD(smem, head_index);
}
if ((flags & FLAG_URGENT) == FLAG_URGENT) {
if (mailbox->smem_state) {
// FIFO 1 client ID range starts at 16 (0xF).
mailbox->smem_bit = mailbox->smem_bit ^ (1 << id);
qcom_smem_state_update_bits(mailbox->smem_state, 0xff, mailbox->smem_bit);
} else {
pr_err("%s: smem smem_state is not setup.\n", __func__);
}
}
return (free_bytes(GET_WRITE_HEAD(smem, entry), GET_WRITE_TAIL(smem, entry), entry->read_size));
}
EXPORT_SYMBOL(smem_mailbox_write);
static const struct of_device_id qcm_smem_match[] = {
{ .compatible = "qcom,smem_mailbox", },
{},
};
MODULE_DEVICE_TABLE(of, qcm_smem_match);
static struct platform_driver qcom_smem_driver = {
.probe = smem_probe,
.remove = smem_remove,
.driver = {
.name = DEVICE_NAME,
.of_match_table = qcm_smem_match,
},
};
module_platform_driver(qcom_smem_driver);
MODULE_DESCRIPTION("QCOM SMEM Mailbox Driver");
MODULE_LICENSE("GPL v2");