summaryrefslogtreecommitdiff
path: root/drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c')
-rw-r--r--drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c494
1 files changed, 449 insertions, 45 deletions
diff --git a/drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c b/drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c
index 323c3a2..4d57d7a 100644
--- a/drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c
+++ b/drivers/emac-dwc-eqos/DWC_ETH_QOS_platform.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* 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
@@ -49,6 +49,8 @@
#include "DWC_ETH_QOS_yheader.h"
#include "DWC_ETH_QOS_ipa.h"
+void *ipc_emac_log_ctxt;
+
static UCHAR dev_addr[6] = {0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7};
struct DWC_ETH_QOS_res_data dwc_eth_qos_res_data = {0, };
static struct msm_bus_scale_pdata *emac_bus_scale_vec = NULL;
@@ -62,7 +64,7 @@ struct emac_emb_smmu_cb_ctx emac_emb_smmu_ctx = {0};
static struct qmp_pkt pkt;
static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0};
extern int create_pps_interrupt_info_device_node(dev_t *pps_dev_t,
- struct cdev* pps_cdev, struct class* pps_class,
+ struct cdev** pps_cdev, struct class** pps_class,
char *pps_dev_node_name);
extern int remove_pps_interrupt_info_device_node(struct DWC_ETH_QOS_prv_data *pdata);
@@ -85,6 +87,105 @@ module_param(phy_interrupt_en, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(phy_interrupt_en,
"Enable PHY interrupt [0-DISABLE, 1-ENABLE]");
+struct ip_params pparams = {};
+#ifdef DWC_ETH_QOS_BUILTIN
+/*!
+ * \brief API to extract MAC Address from given string
+ *
+ * \param[in] pointer to MAC Address string
+ *
+ * \return None
+ */
+void DWC_ETH_QOS_extract_macid(char *mac_addr)
+{
+ char *input = NULL;
+ int i = 0;
+ UCHAR mac_id = 0;
+
+ if (!mac_addr)
+ return;
+
+ /* Extract MAC ID byte by byte */
+ input = strsep(&mac_addr, ":");
+ while(input != NULL && i < DWC_ETH_QOS_MAC_ADDR_LEN) {
+ sscanf(input, "%x", &mac_id);
+ pparams.mac_addr[i++] = mac_id;
+ input = strsep(&mac_addr, ":");
+ }
+ if (!is_valid_ether_addr(pparams.mac_addr)) {
+ EMACERR("Invalid Mac address programmed: %s\n", mac_addr);
+ return;
+ } else
+ pparams.is_valid_mac_addr = true;
+
+ return;
+}
+
+static int __init set_early_ethernet_ipv4(char *ipv4_addr_in)
+{
+ int ret = 1;
+ pparams.is_valid_ipv4_addr = false;
+
+ if (!ipv4_addr_in)
+ return ret;
+
+ strlcpy(pparams.ipv4_addr_str, ipv4_addr_in, sizeof(pparams.ipv4_addr_str));
+ EMACDBG("Early ethernet IPv4 addr: %s\n", pparams.ipv4_addr_str);
+
+ ret = in4_pton(pparams.ipv4_addr_str, -1,
+ (u8*)&pparams.ipv4_addr.s_addr, -1, NULL);
+ if (ret != 1 || pparams.ipv4_addr.s_addr == 0) {
+ EMACERR("Invalid ipv4 address programmed: %s\n", ipv4_addr_in);
+ return ret;
+ }
+
+ pparams.is_valid_ipv4_addr = true;
+ return ret;
+}
+__setup("eipv4=", set_early_ethernet_ipv4);
+
+static int __init set_early_ethernet_ipv6(char* ipv6_addr_in)
+{
+ int ret = 1;
+ pparams.is_valid_ipv6_addr = false;
+
+ if (!ipv6_addr_in)
+ return ret;
+
+ strlcpy(pparams.ipv6_addr_str, ipv6_addr_in, sizeof(pparams.ipv6_addr_str));
+ EMACDBG("Early ethernet IPv6 addr: %s\n", pparams.ipv6_addr_str);
+
+ ret = in6_pton(pparams.ipv6_addr_str, -1,
+ (u8 *)&pparams.ipv6_addr.ifr6_addr.s6_addr32, -1, NULL);
+ if (ret != 1 || pparams.ipv6_addr.ifr6_addr.s6_addr32 == 0) {
+ EMACERR("Invalid ipv6 address programmed: %s\n", ipv6_addr_in);
+ return ret;
+ }
+
+ pparams.is_valid_ipv6_addr = true;
+ return ret;
+}
+__setup("eipv6=", set_early_ethernet_ipv6);
+
+static int __init set_early_ethernet_mac(char* mac_addr)
+{
+ int ret = 1;
+ char temp_mac_addr[DWC_ETH_QOS_MAC_ADDR_STR_LEN];
+ pparams.is_valid_mac_addr = false;
+
+ if(!mac_addr)
+ return ret;
+
+ strlcpy(temp_mac_addr, mac_addr, sizeof(temp_mac_addr));
+ EMACDBG("Early ethernet MAC address assigned: %s\n", temp_mac_addr);
+ temp_mac_addr[DWC_ETH_QOS_MAC_ADDR_STR_LEN-1] = '\0';
+
+ DWC_ETH_QOS_extract_macid(temp_mac_addr);
+ return ret;
+}
+__setup("ermac=", set_early_ethernet_mac);
+#endif
+
static ssize_t read_phy_reg_dump(struct file *file,
char __user *user_buf, size_t count, loff_t *ppos)
{
@@ -425,8 +526,10 @@ static void DWC_ETH_QOS_configure_gpio_pins(struct platform_device *pdev)
return;
}
EMACDBG("get pinctrl succeed\n");
+ dwc_eth_qos_res_data.pinctrl = pinctrl;
if (dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_2_0 ||
+ dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_1_2 ||
dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_3_1) {
/* PPS0 pin */
emac_pps_0 = pinctrl_lookup_state(pinctrl, EMAC_PIN_PPS0);
@@ -618,6 +721,28 @@ static void DWC_ETH_QOS_configure_gpio_pins(struct platform_device *pdev)
else
EMACDBG("Set rgmii_rxc_state succeed\n");
+ dwc_eth_qos_res_data.rgmii_rxc_suspend_state =
+ pinctrl_lookup_state(pinctrl, EMAC_RGMII_RXC_SUSPEND);
+ if (IS_ERR_OR_NULL(dwc_eth_qos_res_data.rgmii_rxc_suspend_state)) {
+ ret = PTR_ERR(dwc_eth_qos_res_data.rgmii_rxc_suspend_state);
+ EMACERR("Failed to get rgmii_rxc_suspend_state, err = %d\n", ret);
+ dwc_eth_qos_res_data.rgmii_rxc_suspend_state = NULL;
+ }
+ else {
+ EMACDBG("Get rgmii_rxc_suspend_state succeed\n");
+ }
+
+ dwc_eth_qos_res_data.rgmii_rxc_resume_state =
+ pinctrl_lookup_state(pinctrl, EMAC_RGMII_RXC_RESUME);
+ if (IS_ERR_OR_NULL(dwc_eth_qos_res_data.rgmii_rxc_resume_state)) {
+ ret = PTR_ERR(dwc_eth_qos_res_data.rgmii_rxc_resume_state);
+ EMACERR("Failed to get rgmii_rxc_resume_state, err = %d\n", ret);
+ dwc_eth_qos_res_data.rgmii_rxc_resume_state = NULL;
+ }
+ else {
+ EMACDBG("Get rgmii_rxc_resume_state succeed\n");
+ }
+
rgmii_rx_ctl_state = pinctrl_lookup_state(pinctrl, EMAC_RGMII_RX_CTL);
if (IS_ERR_OR_NULL(rgmii_rx_ctl_state)) {
ret = PTR_ERR(rgmii_rx_ctl_state);
@@ -723,6 +848,10 @@ static int DWC_ETH_QOS_get_dts_config(struct platform_device *pdev)
}
EMACDBG(": emac_core_version = %d\n", dwc_eth_qos_res_data.emac_hw_version_type);
+ if (dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_3_1 ||
+ dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_1_2)
+ dwc_eth_qos_res_data.pps_lpass_conn_en = true;
+
if (dwc_eth_qos_res_data.emac_hw_version_type == EMAC_HW_v2_3_1) {
resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
@@ -748,6 +877,17 @@ static int DWC_ETH_QOS_get_dts_config(struct platform_device *pdev)
}
+ dwc_eth_qos_res_data.early_eth_en = 0;
+ if(pparams.is_valid_mac_addr &&
+ (pparams.is_valid_ipv4_addr || pparams.is_valid_ipv6_addr)) {
+ /* For 1000BASE-T mode, auto-negotiation is required and
+ always used to establish a link.
+ Configure phy and MAC in 100Mbps mode with autoneg disable
+ as link up takes more time with autoneg enabled */
+ dwc_eth_qos_res_data.early_eth_en = 1;
+ EMACINFO("Early ethernet is enabled\n");
+ }
+
ret = DWC_ETH_QOS_get_io_macro_config(pdev);
if (ret)
goto err_out;
@@ -829,7 +969,7 @@ int DWC_ETH_QOS_qmp_mailbox_init(struct DWC_ETH_QOS_prv_data *pdata)
pdata->qmp_mbox_client = devm_kzalloc(
&pdata->pdev->dev, sizeof(*pdata->qmp_mbox_client), GFP_KERNEL);
- if (IS_ERR(pdata->qmp_mbox_client)){
+ if (pdata->qmp_mbox_client == NULL || IS_ERR(pdata->qmp_mbox_client)){
EMACERR("qmp alloc client failed\n");
return -1;
}
@@ -968,8 +1108,15 @@ void DWC_ETH_QOS_resume_clks(struct DWC_ETH_QOS_prv_data *pdata)
else
DWC_ETH_QOS_set_clk_and_bus_config(pdata, SPEED_10);
+#ifdef DWC_ETH_QOS_CONFIG_PTP
+ if (dwc_eth_qos_res_data.ptp_clk)
+ clk_prepare_enable(dwc_eth_qos_res_data.ptp_clk);
+#endif
+
pdata->clks_suspended = 0;
- complete_all(&pdata->clk_enable_done);
+
+ if (pdata->phy_intr_en)
+ complete_all(&pdata->clk_enable_done);
EMACDBG("Exit\n");
}
@@ -978,7 +1125,9 @@ void DWC_ETH_QOS_suspend_clks(struct DWC_ETH_QOS_prv_data *pdata)
{
EMACDBG("Enter\n");
- reinit_completion(&pdata->clk_enable_done);
+ if (pdata->phy_intr_en)
+ reinit_completion(&pdata->clk_enable_done);
+
pdata->clks_suspended = 1;
DWC_ETH_QOS_set_clk_and_bus_config(pdata, 0);
@@ -992,6 +1141,11 @@ void DWC_ETH_QOS_suspend_clks(struct DWC_ETH_QOS_prv_data *pdata)
if (dwc_eth_qos_res_data.rgmii_clk)
clk_disable_unprepare(dwc_eth_qos_res_data.rgmii_clk);
+#ifdef DWC_ETH_QOS_CONFIG_PTP
+ if (dwc_eth_qos_res_data.ptp_clk)
+ clk_disable_unprepare(dwc_eth_qos_res_data.ptp_clk);
+#endif
+
EMACDBG("Exit\n");
}
@@ -1320,7 +1474,8 @@ static int DWC_ETH_QOS_init_gpios(struct device *dev)
}
}
- if (dwc_eth_qos_res_data.is_gpio_phy_reset) {
+ if (dwc_eth_qos_res_data.is_gpio_phy_reset &&
+ !dwc_eth_qos_res_data.early_eth_en) {
ret = setup_gpio_output_common(
dev, EMAC_GPIO_PHY_RESET_NAME,
&dwc_eth_qos_res_data.gpio_phy_reset, PHY_RESET_GPIO_LOW);
@@ -1349,6 +1504,104 @@ static struct of_device_id DWC_ETH_QOS_plat_drv_match[] = {
{}
};
+void is_ipv6_NW_stack_ready(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct DWC_ETH_QOS_prv_data *pdata;
+ int ret;
+
+ EMACDBG("\n");
+ dwork = container_of(work, struct delayed_work, work);
+ pdata = container_of(dwork, struct DWC_ETH_QOS_prv_data, ipv6_addr_assign_wq);
+
+ ret = DWC_ETH_QOS_add_ipv6addr(pdata);
+ if (ret)
+ return;
+
+ cancel_delayed_work_sync(&pdata->ipv6_addr_assign_wq);
+ flush_delayed_work(&pdata->ipv6_addr_assign_wq);
+ return;
+}
+
+int DWC_ETH_QOS_add_ipv6addr(struct DWC_ETH_QOS_prv_data *pdata)
+{
+ int ret;
+#ifdef DWC_ETH_QOS_BUILTIN
+ struct in6_ifreq ir6;
+ char* prefix;
+ struct ip_params *ip_info = &pparams;
+ struct net *net = dev_net(pdata->dev);
+
+ EMACDBG("\n");
+ if (!net || !net->genl_sock || !net->genl_sock->sk_socket)
+ EMACERR("Sock is null, unable to assign ipv6 address\n");
+
+ if (!net->ipv6.devconf_dflt) {
+ EMACDBG("ipv6.devconf_dflt is null, schedule wq\n");
+ schedule_delayed_work(&pdata->ipv6_addr_assign_wq, msecs_to_jiffies(1000));
+ return -EFAULT;
+ }
+
+ /*For valid IPv6 address*/
+ memset(&ir6, 0, sizeof(ir6));
+ memcpy(&ir6, &ip_info->ipv6_addr, sizeof(struct in6_ifreq));
+ ir6.ifr6_ifindex = pdata->dev->ifindex;
+
+ if ((prefix = strchr(ip_info->ipv6_addr_str, '/')) == NULL)
+ ir6.ifr6_prefixlen = 0;
+ else {
+ ir6.ifr6_prefixlen = simple_strtoul(prefix + 1, NULL, 0);
+ if (ir6.ifr6_prefixlen > 128)
+ ir6.ifr6_prefixlen = 0;
+ }
+
+ ret = inet6_ioctl(net->genl_sock->sk_socket, SIOCSIFADDR, (unsigned long)(void *)&ir6);
+ if (ret)
+ EMACERR("Can't setup IPv6 address!\r\n");
+ else
+ EMACDBG("Assigned IPv6 address: %s\r\n", ip_info->ipv6_addr_str);
+#else
+ ret = -EFAULT;
+#endif
+ return ret;
+}
+
+int DWC_ETH_QOS_add_ipaddr(struct DWC_ETH_QOS_prv_data *pdata)
+{
+ int ret=0;
+#ifdef DWC_ETH_QOS_BUILTIN
+ struct ip_params *ip_info = &pparams;
+ struct ifreq ir;
+ struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
+ struct net *net = dev_net(pdata->dev);
+
+ if (!net || !net->genl_sock || !net->genl_sock->sk_socket)
+ EMACERR("Sock is null, unable to assign ipv4 address\n");
+
+ /*For valid Ipv4 address*/
+ memset(&ir, 0, sizeof(ir));
+ memcpy(&sin->sin_addr.s_addr, &ip_info->ipv4_addr,
+ sizeof(sin->sin_addr.s_addr));
+ strlcpy(ir.ifr_ifrn.ifrn_name, pdata->dev->name, sizeof(ir.ifr_ifrn.ifrn_name) + 1);
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+
+ ret = inet_ioctl(net->genl_sock->sk_socket, SIOCSIFADDR, (unsigned long)(void *)&ir);
+ if (ret)
+ EMACERR( "Can't setup IPv4 address!: %d\r\n", ret);
+ else
+ EMACDBG("Assigned IPv4 address: %s\r\n", ip_info->ipv4_addr_str);
+#endif
+ return ret;
+}
+
+u32 l3mdev_fib_table1 (const struct net_device *dev)
+{
+ return RT_TABLE_LOCAL;
+}
+
+const struct l3mdev_ops l3mdev_op1 = {.l3mdev_fib_table = l3mdev_fib_table1};
+
static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
{
struct DWC_ETH_QOS_prv_data *pdata = NULL;
@@ -1371,6 +1624,10 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
ret = -ENOMEM;
goto err_out_dev_failed;
}
+
+ if (pparams.is_valid_mac_addr == true)
+ ether_addr_copy(dev_addr, pparams.mac_addr);
+
dev->dev_addr[0] = dev_addr[0];
dev->dev_addr[1] = dev_addr[1];
dev->dev_addr[2] = dev_addr[2];
@@ -1420,9 +1677,24 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
/* store emac hw version in pdata*/
pdata->emac_hw_version_type = dwc_eth_qos_res_data.emac_hw_version_type;
+#ifdef CONFIG_NET_L3_MASTER_DEV
+ if (pdata->res_data->early_eth_en && pdata->emac_hw_version_type == EMAC_HW_v2_3_1) {
+ EMACDBG("l3mdev_op1 set \n");
+ dev->priv_flags = IFF_L3MDEV_MASTER;
+ dev->l3mdev_ops = &l3mdev_op1;
+ }
+#endif
+
+
/* Scale the clocks to 10Mbps speed */
- pdata->speed = SPEED_10;
- DWC_ETH_QOS_set_clk_and_bus_config(pdata, SPEED_10);
+ if (pdata->res_data->early_eth_en) {
+ pdata->speed = SPEED_100;
+ DWC_ETH_QOS_set_clk_and_bus_config(pdata, SPEED_100);
+ }
+ else {
+ pdata->speed = SPEED_10;
+ DWC_ETH_QOS_set_clk_and_bus_config(pdata, SPEED_10);
+ }
DWC_ETH_QOS_set_rgmii_func_clk_en();
@@ -1440,7 +1712,7 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
pdata->ipa_enabled = 0;
#endif
- EMACINFO("EMAC IPA enabled: %d\n", pdata->ipa_enabled);
+ EMACDBG("EMAC IPA enabled: %d\n", pdata->ipa_enabled);
if (pdata->ipa_enabled) {
pdata->prv_ipa.ipa_ver = ipa_get_hw_type();
device_init_wakeup(&pdev->dev, 1);
@@ -1580,10 +1852,10 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
if (pdata->emac_hw_version_type == EMAC_HW_v2_3_1) {
create_pps_interrupt_info_device_node(&pdata->avb_class_a_dev_t,
- pdata->avb_class_a_cdev, pdata->avb_class_a_class, AVB_CLASS_A_POLL_DEV_NODE_NAME);
+ &pdata->avb_class_a_cdev, &pdata->avb_class_a_class, AVB_CLASS_A_POLL_DEV_NODE_NAME);
create_pps_interrupt_info_device_node(&pdata->avb_class_b_dev_t,
- pdata->avb_class_b_cdev ,pdata->avb_class_b_class, AVB_CLASS_B_POLL_DEV_NODE_NAME);
+ &pdata->avb_class_b_cdev ,&pdata->avb_class_b_class, AVB_CLASS_B_POLL_DEV_NODE_NAME);
}
DWC_ETH_QOS_create_debugfs(pdata);
@@ -1596,6 +1868,19 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
queue_work(system_wq, &pdata->qmp_mailbox_work);
}
+ if (pdata->res_data->early_eth_en) {
+ if (pparams.is_valid_ipv4_addr)
+ ret = DWC_ETH_QOS_add_ipaddr(pdata);
+
+ if (pparams.is_valid_ipv6_addr) {
+ INIT_DELAYED_WORK(&pdata->ipv6_addr_assign_wq, is_ipv6_NW_stack_ready);
+ ret = DWC_ETH_QOS_add_ipv6addr(pdata);
+ if (ret)
+ schedule_delayed_work(&pdata->ipv6_addr_assign_wq, msecs_to_jiffies(1000));
+ }
+
+ }
+
EMACDBG("<-- DWC_ETH_QOS_configure_netdevice\n");
return 0;
@@ -1773,7 +2058,9 @@ static int DWC_ETH_QOS_probe(struct platform_device *pdev)
int ret = 0;
EMACDBG("--> DWC_ETH_QOS_probe\n");
-
+#ifdef CONFIG_MSM_BOOT_TIME_MARKER
+ place_marker("M - Ethernet probe start");
+#endif
if (of_device_is_compatible(pdev->dev.of_node, "qcom,emac-smmu-embedded"))
return emac_emb_smmu_cb_probe(pdev);
@@ -2001,10 +2288,10 @@ static void DWC_ETH_QOS_shutdown(struct platform_device *pdev)
* \retval 0
*/
-static INT DWC_ETH_QOS_suspend(struct platform_device *pdev, pm_message_t state)
+static INT DWC_ETH_QOS_suspend(struct device *dev)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct DWC_ETH_QOS_prv_data *pdata = netdev_priv(dev);
+ struct DWC_ETH_QOS_prv_data *pdata = gDWC_ETH_QOS_prv_data;
+ struct net_device *net_dev = pdata->dev;
struct hw_if_struct *hw_if = &pdata->hw_if;
INT ret, pmt_flags = 0;
unsigned int rwk_filter_values[] = {
@@ -2040,7 +2327,7 @@ static INT DWC_ETH_QOS_suspend(struct platform_device *pdev, pm_message_t state)
EMACDBG("-->DWC_ETH_QOS_suspend\n");
- if (of_device_is_compatible(pdev->dev.of_node, "qcom,emac-smmu-embedded")) {
+ if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded")) {
EMACDBG("<--DWC_ETH_QOS_suspend smmu return\n");
return 0;
}
@@ -2049,16 +2336,10 @@ static INT DWC_ETH_QOS_suspend(struct platform_device *pdev, pm_message_t state)
pdata->power_down_type |= DWC_ETH_QOS_EMAC_INTR_WAKEUP;
enable_irq_wake(pdata->irq_number);
- /* Set PHY intr as wakeup-capable to handle change in PHY link status after suspend */
- if (pdata->phy_intr_en && pdata->phy_irq && pdata->phy_wol_wolopts) {
- pmt_flags |= DWC_ETH_QOS_PHY_INTR_WAKEUP;
- enable_irq_wake(pdata->phy_irq);
- }
-
return 0;
}
- if (!dev || !netif_running(dev)) {
+ if (!net_dev || !netif_running(net_dev)) {
return -EINVAL;
}
@@ -2070,15 +2351,26 @@ static INT DWC_ETH_QOS_suspend(struct platform_device *pdev, pm_message_t state)
if (pdata->hw_feat.mgk_sel && (pdata->wolopts & WAKE_MAGIC))
pmt_flags |= DWC_ETH_QOS_MAGIC_WAKEUP;
- if (pdata->phy_intr_en && pdata->phy_irq && pdata->phy_wol_wolopts)
- pmt_flags |= DWC_ETH_QOS_PHY_INTR_WAKEUP;
-
- ret = DWC_ETH_QOS_powerdown(dev, pmt_flags, DWC_ETH_QOS_DRIVER_CONTEXT);
+ ret = DWC_ETH_QOS_powerdown(net_dev, pmt_flags, DWC_ETH_QOS_DRIVER_CONTEXT);
DWC_ETH_QOS_suspend_clks(pdata);
- EMACDBG("<--DWC_ETH_QOS_suspend ret = %d\n", ret);
+ /* Suspend the PHY RXC clock. */
+ if (dwc_eth_qos_res_data.is_pinctrl_names &&
+ (dwc_eth_qos_res_data.rgmii_rxc_suspend_state != NULL)) {
+ /* Remove RXC clock source from Phy.*/
+ ret = pinctrl_select_state(dwc_eth_qos_res_data.pinctrl,
+ dwc_eth_qos_res_data.rgmii_rxc_suspend_state);
+ if (ret)
+ EMACERR("Unable to set rgmii_rxc_suspend_state state, err = %d\n", ret);
+ else
+ EMACDBG("Set rgmii_rxc_suspend_state succeed\n");
+ }
+ EMACDBG("<--DWC_ETH_QOS_suspend ret = %d\n", ret);
+#ifdef CONFIG_MSM_BOOT_TIME_MARKER
+ pdata->print_kpi = 0;
+#endif
return ret;
}
@@ -2104,18 +2396,18 @@ static INT DWC_ETH_QOS_suspend(struct platform_device *pdev, pm_message_t state)
* \retval 0
*/
-static INT DWC_ETH_QOS_resume(struct platform_device *pdev)
+static INT DWC_ETH_QOS_resume(struct device *dev)
{
- struct net_device *dev = platform_get_drvdata(pdev);
- struct DWC_ETH_QOS_prv_data *pdata = netdev_priv(dev);
+ struct DWC_ETH_QOS_prv_data *pdata = gDWC_ETH_QOS_prv_data;
+ struct net_device *net_dev = pdata->dev;
INT ret;
- DBGPR("-->DWC_ETH_QOS_resume\n");
- if (of_device_is_compatible(pdev->dev.of_node, "qcom,emac-smmu-embedded"))
+ EMACDBG("-->DWC_ETH_QOS_resume\n");
+ if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded"))
return 0;
- if (!dev || !netif_running(dev)) {
- DBGPR("<--DWC_ETH_QOS_dev_resume\n");
+ if (!net_dev || !netif_running(net_dev)) {
+ EMACERR("<--DWC_ETH_QOS_dev_resume\n");
return -EINVAL;
}
@@ -2132,40 +2424,143 @@ static INT DWC_ETH_QOS_resume(struct platform_device *pdev)
/* Wakeup reason can be PHY link event or a RX packet */
/* Set a wakeup event to ensure enough time for processing */
- pm_wakeup_event(&pdev->dev, 5000);
+ pm_wakeup_event(dev, 5000);
return 0;
}
+ /* Resume the PhY RXC clock. */
+ if (dwc_eth_qos_res_data.is_pinctrl_names &&
+ (dwc_eth_qos_res_data.rgmii_rxc_resume_state != NULL)) {
+
+ /* Enable RXC clock source from Phy.*/
+ ret = pinctrl_select_state(dwc_eth_qos_res_data.pinctrl,
+ dwc_eth_qos_res_data.rgmii_rxc_resume_state);
+ if (ret)
+ EMACERR("Unable to set rgmii_rxc_resume_state state, err = %d\n", ret);
+ else
+ EMACDBG("Set rgmii_rxc_resume_state succeed\n");
+ }
+
DWC_ETH_QOS_resume_clks(pdata);
- ret = DWC_ETH_QOS_powerup(dev, DWC_ETH_QOS_DRIVER_CONTEXT);
+ ret = DWC_ETH_QOS_powerup(net_dev, DWC_ETH_QOS_DRIVER_CONTEXT);
if (pdata->ipa_enabled)
DWC_ETH_QOS_ipa_offload_event_handler(pdata, EV_DPM_RESUME);
/* Wakeup reason can be PHY link event or a RX packet */
/* Set a wakeup event to ensure enough time for processing */
- pm_wakeup_event(&pdev->dev, 5000);
+ pm_wakeup_event(dev, 5000);
- DBGPR("<--DWC_ETH_QOS_resume\n");
+ EMACDBG("<--DWC_ETH_QOS_resume\n");
return ret;
}
#endif /* CONFIG_PM */
-static struct platform_driver DWC_ETH_QOS_plat_drv = {
- .probe = DWC_ETH_QOS_probe,
- .remove = DWC_ETH_QOS_remove,
- .shutdown = DWC_ETH_QOS_shutdown,
+static int DWC_ETH_QOS_hib_restore(struct device *dev) {
+ struct DWC_ETH_QOS_prv_data *pdata = gDWC_ETH_QOS_prv_data;
+ int ret = 0;
+
+ if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded"))
+ return 0;
+
+ EMACINFO(" start\n");
+
+ ret = DWC_ETH_QOS_init_regulators(dev);
+ if (ret)
+ return ret;
+
+ ret = DWC_ETH_QOS_init_gpios(dev);
+ if (ret)
+ return ret;
+
+ ret = DWC_ETH_QOS_get_clks(dev);
+ if (ret)
+ return ret;
+
+ DWC_ETH_QOS_set_clk_and_bus_config(pdata, pdata->speed);
+
+ DWC_ETH_QOS_set_rgmii_func_clk_en();
+
+#ifdef DWC_ETH_QOS_CONFIG_PTP
+ DWC_ETH_QOS_ptp_init(pdata);
+#endif /* end of DWC_ETH_QOS_CONFIG_PTP */
+
+ /* issue software reset to device */
+ pdata->hw_if.exit();
+
+ /* Bypass PHYLIB for TBI, RTBI and SGMII interface */
+ if (pdata->hw_feat.sma_sel == 1) {
+ ret = DWC_ETH_QOS_mdio_register(pdata->dev);
+ if (ret < 0) {
+ EMACERR("MDIO bus (id %d) registration failed\n",
+ pdata->bus_id);
+ return ret;
+ }
+ }
+
+ if (!(pdata->dev->flags & IFF_UP)) {
+ pdata->dev->netdev_ops->ndo_open(pdata->dev);
+ pdata->dev->flags |= IFF_UP;
+ }
+
+ EMACINFO("end\n");
+
+ return ret;
+}
+
+static int DWC_ETH_QOS_hib_freeze(struct device *dev) {
+ struct DWC_ETH_QOS_prv_data *pdata = gDWC_ETH_QOS_prv_data;
+ int ret = 0;
+
+ if (of_device_is_compatible(dev->of_node, "qcom,emac-smmu-embedded"))
+ return 0;
+
+ EMACINFO(" start\n");
+ if (pdata->dev->flags & IFF_UP) {
+ pdata->dev->netdev_ops->ndo_stop(pdata->dev);
+ pdata->dev->flags &= ~IFF_UP;
+ }
+
+ if (pdata->hw_feat.sma_sel == 1)
+ DWC_ETH_QOS_mdio_unregister(pdata->dev);
+
+#ifdef DWC_ETH_QOS_CONFIG_PTP
+ DWC_ETH_QOS_ptp_remove(pdata);
+#endif /* end of DWC_ETH_QOS_CONFIG_PTP */
+
+ DWC_ETH_QOS_disable_clks(dev);
+
+ DWC_ETH_QOS_disable_regulators();
+
+ DWC_ETH_QOS_free_gpios();
+
+ EMACINFO("end\n");
+
+ return ret;
+}
+
+static const struct dev_pm_ops DWC_ETH_QOS_pm_ops = {
+ .freeze = DWC_ETH_QOS_hib_freeze,
+ .restore = DWC_ETH_QOS_hib_restore,
+ .thaw = DWC_ETH_QOS_hib_restore,
#ifdef CONFIG_PM
.suspend = DWC_ETH_QOS_suspend,
.resume = DWC_ETH_QOS_resume,
#endif
+};
+
+static struct platform_driver DWC_ETH_QOS_plat_drv = {
+ .probe = DWC_ETH_QOS_probe,
+ .remove = DWC_ETH_QOS_remove,
+ .shutdown = DWC_ETH_QOS_shutdown,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = DWC_ETH_QOS_plat_drv_match,
+ .pm = &DWC_ETH_QOS_pm_ops,
},
};
@@ -2182,7 +2577,7 @@ static int DWC_ETH_QOS_init_module(void)
{
INT ret = 0;
- DBGPR("-->DWC_ETH_QOS_init_module\n");
+ EMACDBG("-->DWC_ETH_QOS_init_module\n");
ret = platform_driver_register(&DWC_ETH_QOS_plat_drv);
if (ret < 0) {
@@ -2190,11 +2585,17 @@ static int DWC_ETH_QOS_init_module(void)
return ret;
}
+ ipc_emac_log_ctxt = ipc_log_context_create(IPCLOG_STATE_PAGES,"emac", 0);
+ if (!ipc_emac_log_ctxt)
+ EMACERR("Error creating logging context for emac\n");
+ else
+ EMACDBG("IPC logging has been enabled for emac\n");
+
#ifdef DWC_ETH_QOS_CONFIG_DEBUGFS
create_debug_files();
#endif
- DBGPR("<--DWC_ETH_QOS_init_module\n");
+ EMACDBG("<--DWC_ETH_QOS_init_module\n");
return ret;
}
@@ -2218,6 +2619,9 @@ static void __exit DWC_ETH_QOS_exit_module(void)
platform_driver_unregister(&DWC_ETH_QOS_plat_drv);
+ if (ipc_emac_log_ctxt != NULL)
+ ipc_log_context_destroy(ipc_emac_log_ctxt);
+
DBGPR("<--DWC_ETH_QOS_exit_module\n");
}