mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-30 18:05:48 +01:00 
			
		
		
		
	This function is a no-op. Remove it. Signed-off-by: Sean Anderson <seanga2@gmail.com> Link: https://lore.kernel.org/r/20231216193843.2463779-3-seanga2@gmail.com
		
			
				
	
	
		
			612 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			612 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * (C) Copyright 2022-2023 Sumit Garg <sumit.garg@linaro.org>
 | |
|  *
 | |
|  * Qcom DWMAC specific glue layer
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <asm/global_data.h>
 | |
| #include <asm/gpio.h>
 | |
| #include <asm/io.h>
 | |
| #include <clk.h>
 | |
| #include <dm.h>
 | |
| #include <dm/device_compat.h>
 | |
| #include <phy.h>
 | |
| #include <reset.h>
 | |
| #include <syscon.h>
 | |
| #include <linux/bitops.h>
 | |
| #include <linux/delay.h>
 | |
| 
 | |
| #include "dwc_eth_qos.h"
 | |
| 
 | |
| /* RGMII_IO_MACRO_CONFIG fields */
 | |
| #define RGMII_CONFIG_FUNC_CLK_EN		BIT(30)
 | |
| #define RGMII_CONFIG_POS_NEG_DATA_SEL		BIT(23)
 | |
| #define RGMII_CONFIG_GPIO_CFG_RX_INT		GENMASK(21, 20)
 | |
| #define RGMII_CONFIG_GPIO_CFG_TX_INT		GENMASK(19, 17)
 | |
| #define RGMII_CONFIG_MAX_SPD_PRG_9		GENMASK(16, 8)
 | |
| #define RGMII_CONFIG_MAX_SPD_PRG_2		GENMASK(7, 6)
 | |
| #define RGMII_CONFIG_INTF_SEL			GENMASK(5, 4)
 | |
| #define RGMII_CONFIG_BYPASS_TX_ID_EN		BIT(3)
 | |
| #define RGMII_CONFIG_LOOPBACK_EN		BIT(2)
 | |
| #define RGMII_CONFIG_PROG_SWAP			BIT(1)
 | |
| #define RGMII_CONFIG_DDR_MODE			BIT(0)
 | |
| 
 | |
| /* SDCC_HC_REG_DLL_CONFIG fields */
 | |
| #define SDCC_DLL_CONFIG_DLL_RST			BIT(30)
 | |
| #define SDCC_DLL_CONFIG_PDN			BIT(29)
 | |
| #define SDCC_DLL_CONFIG_MCLK_FREQ		GENMASK(26, 24)
 | |
| #define SDCC_DLL_CONFIG_CDR_SELEXT		GENMASK(23, 20)
 | |
| #define SDCC_DLL_CONFIG_CDR_EXT_EN		BIT(19)
 | |
| #define SDCC_DLL_CONFIG_CK_OUT_EN		BIT(18)
 | |
| #define SDCC_DLL_CONFIG_CDR_EN			BIT(17)
 | |
| #define SDCC_DLL_CONFIG_DLL_EN			BIT(16)
 | |
| #define SDCC_DLL_MCLK_GATING_EN			BIT(5)
 | |
| #define SDCC_DLL_CDR_FINE_PHASE			GENMASK(3, 2)
 | |
| 
 | |
| /* SDCC_HC_REG_DDR_CONFIG fields */
 | |
| #define SDCC_DDR_CONFIG_PRG_DLY_EN		BIT(31)
 | |
| #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY	GENMASK(26, 21)
 | |
| #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE	GENMASK(29, 27)
 | |
| #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN	BIT(30)
 | |
| #define SDCC_DDR_CONFIG_PRG_RCLK_DLY		GENMASK(8, 0)
 | |
| 
 | |
| /* SDCC_HC_REG_DLL_CONFIG2 fields */
 | |
| #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS		BIT(21)
 | |
| #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC		GENMASK(17, 10)
 | |
| #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL	GENMASK(3, 2)
 | |
| #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW	BIT(1)
 | |
| #define SDCC_DLL_CONFIG2_DDR_CAL_EN		BIT(0)
 | |
| 
 | |
| /* SDC4_STATUS bits */
 | |
| #define SDC4_STATUS_DLL_LOCK			BIT(7)
 | |
| 
 | |
| /* RGMII_IO_MACRO_CONFIG2 fields */
 | |
| #define RGMII_CONFIG2_RSVD_CONFIG15		GENMASK(31, 17)
 | |
| #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG		BIT(16)
 | |
| #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN	BIT(13)
 | |
| #define RGMII_CONFIG2_CLK_DIVIDE_SEL		BIT(12)
 | |
| #define RGMII_CONFIG2_RX_PROG_SWAP		BIT(7)
 | |
| #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL	BIT(6)
 | |
| #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN	BIT(5)
 | |
| 
 | |
| struct dwmac_rgmii_regs {
 | |
| 	u32 io_macro_config;		/* 0x00 */
 | |
| 	u32 sdcc_hc_dll_config;		/* 0x04 */
 | |
| 	u32 reserved_1;			/* 0x08 */
 | |
| 	u32 sdcc_hc_ddr_config;		/* 0x0c */
 | |
| 	u32 sdcc_hc_dll_config2;	/* 0x10 */
 | |
| 	u32 sdc4_status;		/* 0x14 */
 | |
| 	u32 sdcc_usr_ctl;		/* 0x18 */
 | |
| 	u32 io_macro_config2;		/* 0x1c */
 | |
| 	u32 io_macro_debug1;		/* 0x20 */
 | |
| 	u32 reserved_2;			/* 0x24 */
 | |
| 	u32 emac_sys_low_power_dbg;	/* 0x28 */
 | |
| 	u32 reserved_3[53];		/* upto 0x100 */
 | |
| };
 | |
| 
 | |
| static struct dwmac_rgmii_regs emac_v2_3_0_por = {
 | |
| 	.io_macro_config = 0x00C01343,
 | |
| 	.sdcc_hc_dll_config = 0x2004642C,
 | |
| 	.sdcc_hc_ddr_config = 0x00000000,
 | |
| 	.sdcc_hc_dll_config2 = 0x00200000,
 | |
| 	.sdcc_usr_ctl = 0x00010800,
 | |
| 	.io_macro_config2 = 0x00002060
 | |
| };
 | |
| 
 | |
| static void ethqos_set_func_clk_en(struct dwmac_rgmii_regs *regs)
 | |
| {
 | |
| 	setbits_le32(®s->io_macro_config, RGMII_CONFIG_FUNC_CLK_EN);
 | |
| }
 | |
| 
 | |
| static int ethqos_dll_configure(struct udevice *dev,
 | |
| 				struct dwmac_rgmii_regs *regs)
 | |
| {
 | |
| 	unsigned int val;
 | |
| 	int retry = 1000;
 | |
| 
 | |
| 	/* Set CDR_EN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CDR_EN);
 | |
| 
 | |
| 	/* Set CDR_EXT_EN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CDR_EXT_EN);
 | |
| 
 | |
| 	/* Clear CK_OUT_EN */
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CK_OUT_EN);
 | |
| 
 | |
| 	/* Set DLL_EN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_EN);
 | |
| 
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_MCLK_GATING_EN);
 | |
| 
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CDR_FINE_PHASE);
 | |
| 
 | |
| 	/* Wait for CK_OUT_EN clear */
 | |
| 	do {
 | |
| 		val = readl(®s->sdcc_hc_dll_config);
 | |
| 		val &= SDCC_DLL_CONFIG_CK_OUT_EN;
 | |
| 		if (!val)
 | |
| 			break;
 | |
| 		mdelay(1);
 | |
| 		retry--;
 | |
| 	} while (retry > 0);
 | |
| 	if (!retry)
 | |
| 		dev_err(dev, "Clear CK_OUT_EN timedout\n");
 | |
| 
 | |
| 	/* Set CK_OUT_EN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_CK_OUT_EN);
 | |
| 
 | |
| 	/* Wait for CK_OUT_EN set */
 | |
| 	retry = 1000;
 | |
| 	do {
 | |
| 		val = readl(®s->sdcc_hc_dll_config);
 | |
| 		val &= SDCC_DLL_CONFIG_CK_OUT_EN;
 | |
| 		if (val)
 | |
| 			break;
 | |
| 		mdelay(1);
 | |
| 		retry--;
 | |
| 	} while (retry > 0);
 | |
| 	if (!retry)
 | |
| 		dev_err(dev, "Set CK_OUT_EN timedout\n");
 | |
| 
 | |
| 	/* Set DDR_CAL_EN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config2, SDCC_DLL_CONFIG2_DDR_CAL_EN);
 | |
| 
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config2,
 | |
| 		     SDCC_DLL_CONFIG2_DLL_CLOCK_DIS);
 | |
| 
 | |
| 	clrsetbits_le32(®s->sdcc_hc_dll_config2,
 | |
| 			SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 0x1A << 10);
 | |
| 
 | |
| 	clrsetbits_le32(®s->sdcc_hc_dll_config2,
 | |
| 			SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, BIT(2));
 | |
| 
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config2,
 | |
| 		     SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int ethqos_rgmii_macro_init(struct udevice *dev,
 | |
| 				   struct dwmac_rgmii_regs *regs,
 | |
| 				   unsigned long speed)
 | |
| {
 | |
| 	/* Disable loopback mode */
 | |
| 	clrbits_le32(®s->io_macro_config2,
 | |
| 		     RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN);
 | |
| 
 | |
| 	/* Select RGMII, write 0 to interface select */
 | |
| 	clrbits_le32(®s->io_macro_config, RGMII_CONFIG_INTF_SEL);
 | |
| 
 | |
| 	switch (speed) {
 | |
| 	case SPEED_1000:
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
 | |
| 		clrbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_BYPASS_TX_ID_EN);
 | |
| 		setbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_POS_NEG_DATA_SEL);
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
 | |
| 
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
 | |
| 		setbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RSVD_CONFIG15);
 | |
| 		setbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RX_PROG_SWAP);
 | |
| 
 | |
| 		/* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */
 | |
| 		clrsetbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 				SDCC_DDR_CONFIG_PRG_RCLK_DLY, 57);
 | |
| 		setbits_le32(®s->sdcc_hc_ddr_config, SDCC_DDR_CONFIG_PRG_DLY_EN);
 | |
| 
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
 | |
| 		break;
 | |
| 
 | |
| 	case SPEED_100:
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
 | |
| 		setbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_BYPASS_TX_ID_EN);
 | |
| 		clrbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_POS_NEG_DATA_SEL);
 | |
| 		clrbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
 | |
| 		clrsetbits_le32(®s->io_macro_config,
 | |
| 				RGMII_CONFIG_MAX_SPD_PRG_2, BIT(6));
 | |
| 
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
 | |
| 		setbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RSVD_CONFIG15);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RX_PROG_SWAP);
 | |
| 
 | |
| 		/* Write 0x5 to PRG_RCLK_DLY_CODE */
 | |
| 		clrsetbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 				SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
 | |
| 				(BIT(29) | BIT(27)));
 | |
| 		setbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 			     SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY);
 | |
| 		setbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 			     SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN);
 | |
| 
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
 | |
| 		break;
 | |
| 
 | |
| 	case SPEED_10:
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_DDR_MODE);
 | |
| 		setbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_BYPASS_TX_ID_EN);
 | |
| 		clrbits_le32(®s->io_macro_config,
 | |
| 			     RGMII_CONFIG_POS_NEG_DATA_SEL);
 | |
| 		clrbits_le32(®s->io_macro_config, RGMII_CONFIG_PROG_SWAP);
 | |
| 		clrsetbits_le32(®s->io_macro_config,
 | |
| 				RGMII_CONFIG_MAX_SPD_PRG_9,
 | |
| 				BIT(12) | GENMASK(9, 8));
 | |
| 
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RSVD_CONFIG15);
 | |
| 		clrbits_le32(®s->io_macro_config2,
 | |
| 			     RGMII_CONFIG2_RX_PROG_SWAP);
 | |
| 
 | |
| 		/* Write 0x5 to PRG_RCLK_DLY_CODE */
 | |
| 		clrsetbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 				SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE,
 | |
| 				(BIT(29) | BIT(27)));
 | |
| 		setbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 			     SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY);
 | |
| 		setbits_le32(®s->sdcc_hc_ddr_config,
 | |
| 			     SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN);
 | |
| 
 | |
| 		setbits_le32(®s->io_macro_config, RGMII_CONFIG_LOOPBACK_EN);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		dev_err(dev, "Invalid speed %ld\n", speed);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int ethqos_configure(struct udevice *dev,
 | |
| 			    struct dwmac_rgmii_regs *regs,
 | |
| 			    unsigned long speed)
 | |
| {
 | |
| 	unsigned int retry = 1000;
 | |
| 
 | |
| 	/* Reset to POR values and enable clk */
 | |
| 	writel(emac_v2_3_0_por.io_macro_config, ®s->io_macro_config);
 | |
| 	writel(emac_v2_3_0_por.sdcc_hc_dll_config, ®s->sdcc_hc_dll_config);
 | |
| 	writel(emac_v2_3_0_por.sdcc_hc_ddr_config, ®s->sdcc_hc_ddr_config);
 | |
| 	writel(emac_v2_3_0_por.sdcc_hc_dll_config2, ®s->sdcc_hc_dll_config2);
 | |
| 	writel(emac_v2_3_0_por.sdcc_usr_ctl, ®s->sdcc_usr_ctl);
 | |
| 	writel(emac_v2_3_0_por.io_macro_config2, ®s->io_macro_config2);
 | |
| 
 | |
| 	ethqos_set_func_clk_en(regs);
 | |
| 
 | |
| 	/* Initialize the DLL first */
 | |
| 
 | |
| 	/* Set DLL_RST */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_RST);
 | |
| 
 | |
| 	/* Set PDN */
 | |
| 	setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_PDN);
 | |
| 
 | |
| 	/* Clear DLL_RST */
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_RST);
 | |
| 
 | |
| 	/* Clear PDN */
 | |
| 	clrbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_PDN);
 | |
| 
 | |
| 	if (speed == SPEED_1000) {
 | |
| 		/* Set DLL_EN */
 | |
| 		setbits_le32(®s->sdcc_hc_dll_config, SDCC_DLL_CONFIG_DLL_EN);
 | |
| 
 | |
| 		/* Set CK_OUT_EN */
 | |
| 		setbits_le32(®s->sdcc_hc_dll_config,
 | |
| 			     SDCC_DLL_CONFIG_CK_OUT_EN);
 | |
| 
 | |
| 		/* Set USR_CTL bit 26 with mask of 3 bits */
 | |
| 		clrsetbits_le32(®s->sdcc_usr_ctl, GENMASK(26, 24), BIT(26));
 | |
| 
 | |
| 		/* wait for DLL LOCK */
 | |
| 		do {
 | |
| 			mdelay(1);
 | |
| 			if (readl(®s->sdc4_status) & SDC4_STATUS_DLL_LOCK)
 | |
| 				break;
 | |
| 			retry--;
 | |
| 		} while (retry > 0);
 | |
| 		if (!retry)
 | |
| 			dev_err(dev, "Timeout while waiting for DLL lock\n");
 | |
| 
 | |
| 		ethqos_dll_configure(dev, regs);
 | |
| 	}
 | |
| 
 | |
| 	ethqos_rgmii_macro_init(dev, regs, speed);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void ethqos_rgmii_dump(struct udevice *dev,
 | |
| 			      struct dwmac_rgmii_regs *regs)
 | |
| {
 | |
| 	dev_dbg(dev, "Rgmii register dump\n");
 | |
| 	dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %08x\n",
 | |
| 		readl(®s->io_macro_config));
 | |
| 	dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %08x\n",
 | |
| 		readl(®s->sdcc_hc_dll_config));
 | |
| 	dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %08x\n",
 | |
| 		readl(®s->sdcc_hc_ddr_config));
 | |
| 	dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %08x\n",
 | |
| 		readl(®s->sdcc_hc_dll_config2));
 | |
| 	dev_dbg(dev, "SDC4_STATUS: %08x\n",
 | |
| 		readl(®s->sdc4_status));
 | |
| 	dev_dbg(dev, "SDCC_USR_CTL: %08x\n",
 | |
| 		readl(®s->sdcc_usr_ctl));
 | |
| 	dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %08x\n",
 | |
| 		readl(®s->io_macro_config2));
 | |
| 	dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %08x\n",
 | |
| 		readl(®s->io_macro_debug1));
 | |
| 	dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %08x\n",
 | |
| 		readl(®s->emac_sys_low_power_dbg));
 | |
| }
 | |
| 
 | |
| static int qcom_eqos_rgmii_set_speed(struct udevice *dev,
 | |
| 				     void *rgmii_regs,
 | |
| 				     unsigned long speed)
 | |
| {
 | |
| 	int ret;
 | |
| 
 | |
| 	ethqos_rgmii_dump(dev, rgmii_regs);
 | |
| 
 | |
| 	ret = ethqos_configure(dev, rgmii_regs, speed);
 | |
| 	if (ret)
 | |
| 		return ret;
 | |
| 
 | |
| 	ethqos_rgmii_dump(dev, rgmii_regs);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int qcom_eqos_rgmii_reset(struct udevice *dev, void *rgmii_regs)
 | |
| {
 | |
| 	ethqos_set_func_clk_en(rgmii_regs);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int eqos_start_clks_qcom(struct udevice *dev)
 | |
| {
 | |
| 	if (IS_ENABLED(CONFIG_CLK)) {
 | |
| 		struct clk_bulk clocks;
 | |
| 		int ret;
 | |
| 
 | |
| 		ret = clk_get_bulk(dev, &clocks);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 
 | |
| 		ret = clk_enable_bulk(&clocks);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 	}
 | |
| 
 | |
| 	debug("%s: OK\n", __func__);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int eqos_stop_clks_qcom(struct udevice *dev)
 | |
| {
 | |
| 	if (IS_ENABLED(CONFIG_CLK)) {
 | |
| 		struct clk_bulk clocks;
 | |
| 		int ret;
 | |
| 
 | |
| 		ret = clk_get_bulk(dev, &clocks);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 
 | |
| 		ret = clk_disable_bulk(&clocks);
 | |
| 		if (ret)
 | |
| 			return ret;
 | |
| 	}
 | |
| 
 | |
| 	debug("%s: OK\n", __func__);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int eqos_start_resets_qcom(struct udevice *dev)
 | |
| {
 | |
| 	struct eqos_priv *eqos = dev_get_priv(dev);
 | |
| 	int ret;
 | |
| 
 | |
| 	debug("%s(dev=%p):\n", __func__, dev);
 | |
| 
 | |
| 	if (!eqos->phy) {
 | |
| 		ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
 | |
| 		if (ret < 0) {
 | |
| 			pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret);
 | |
| 			return ret;
 | |
| 		}
 | |
| 
 | |
| 		udelay(eqos->reset_delays[0]);
 | |
| 
 | |
| 		ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
 | |
| 		if (ret < 0) {
 | |
| 			pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret);
 | |
| 			return ret;
 | |
| 		}
 | |
| 
 | |
| 		udelay(eqos->reset_delays[1]);
 | |
| 
 | |
| 		ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
 | |
| 		if (ret < 0) {
 | |
| 			pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret);
 | |
| 			return ret;
 | |
| 		}
 | |
| 
 | |
| 		udelay(eqos->reset_delays[2]);
 | |
| 	}
 | |
| 
 | |
| 	ret = reset_deassert(&eqos->reset_ctl);
 | |
| 	if (ret < 0) {
 | |
| 		pr_err("reset_deassert() failed: %d", ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = qcom_eqos_rgmii_reset(dev, eqos->eqos_qcom_rgmii_regs);
 | |
| 	if (ret < 0) {
 | |
| 		pr_err("qcom rgmii_reset failed: %d", ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	debug("%s: OK\n", __func__);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* Clock rates */
 | |
| #define RGMII_1000_NOM_CLK_FREQ			(250 * 1000 * 1000UL)
 | |
| #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ	 (50 * 1000 * 1000UL)
 | |
| #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ	  (5 * 1000 * 1000UL)
 | |
| 
 | |
| static int eqos_set_tx_clk_speed_qcom(struct udevice *dev)
 | |
| {
 | |
| 	struct eqos_priv *eqos = dev_get_priv(dev);
 | |
| 	ulong rate;
 | |
| 	int ret;
 | |
| 
 | |
| 	debug("%s(dev=%p):\n", __func__, dev);
 | |
| 
 | |
| 	switch (eqos->phy->speed) {
 | |
| 	case SPEED_1000:
 | |
| 		rate = RGMII_1000_NOM_CLK_FREQ;
 | |
| 		break;
 | |
| 	case SPEED_100:
 | |
| 		rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ;
 | |
| 		break;
 | |
| 	case SPEED_10:
 | |
| 		rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ;
 | |
| 		break;
 | |
| 	default:
 | |
| 		pr_err("invalid speed %d", eqos->phy->speed);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	ret = clk_set_rate(&eqos->clk_tx, rate);
 | |
| 	if (ret < 0) {
 | |
| 		pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	ret = qcom_eqos_rgmii_set_speed(dev, eqos->eqos_qcom_rgmii_regs,
 | |
| 					eqos->phy->speed);
 | |
| 	if (ret < 0) {
 | |
| 		pr_err("qcom set_speed: %d, failed: %d", eqos->phy->speed, ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int eqos_probe_resources_qcom(struct udevice *dev)
 | |
| {
 | |
| 	struct eqos_priv *eqos = dev_get_priv(dev);
 | |
| 	phy_interface_t interface;
 | |
| 	int reset_flags = GPIOD_IS_OUT;
 | |
| 	int ret;
 | |
| 
 | |
| 	debug("%s(dev=%p):\n", __func__, dev);
 | |
| 
 | |
| 	interface = eqos->config->interface(dev);
 | |
| 
 | |
| 	if (interface == PHY_INTERFACE_MODE_NA) {
 | |
| 		pr_err("Invalid PHY interface\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
 | |
| 
 | |
| 	eqos->tx_fifo_sz = dev_read_u32_default(dev, "tx-fifo-depth", 0);
 | |
| 	eqos->rx_fifo_sz = dev_read_u32_default(dev, "rx-fifo-depth", 0);
 | |
| 
 | |
| 	ret = reset_get_by_name(dev, "emac", &eqos->reset_ctl);
 | |
| 	if (ret) {
 | |
| 		pr_err("reset_get_by_name(rst) failed: %d", ret);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	if (dev_read_bool(dev, "snps,reset-active-low"))
 | |
| 		reset_flags |= GPIOD_ACTIVE_LOW;
 | |
| 
 | |
| 	ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
 | |
| 				   &eqos->phy_reset_gpio, reset_flags);
 | |
| 	if (ret == 0) {
 | |
| 		ret = dev_read_u32_array(dev, "snps,reset-delays-us",
 | |
| 					 eqos->reset_delays, 3);
 | |
| 	} else if (ret == -ENOENT) {
 | |
| 		ret = 0;
 | |
| 	}
 | |
| 
 | |
| 	eqos->eqos_qcom_rgmii_regs = (void *)dev_read_addr_name(dev, "rgmii");
 | |
| 	if ((fdt_addr_t)eqos->eqos_qcom_rgmii_regs == FDT_ADDR_T_NONE) {
 | |
| 		pr_err("Invalid RGMII address\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	ret = clk_get_by_name(dev, "rgmii", &eqos->clk_tx);
 | |
| 	if (ret) {
 | |
| 		pr_err("clk_get_by_name(tx) failed: %d", ret);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	debug("%s: OK\n", __func__);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int eqos_remove_resources_qcom(struct udevice *dev)
 | |
| {
 | |
| 	struct eqos_priv *eqos = dev_get_priv(dev);
 | |
| 
 | |
| 	debug("%s(dev=%p):\n", __func__, dev);
 | |
| 
 | |
| 	dm_gpio_free(dev, &eqos->phy_reset_gpio);
 | |
| 	reset_free(&eqos->reset_ctl);
 | |
| 
 | |
| 	debug("%s: OK\n", __func__);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct eqos_ops eqos_qcom_ops = {
 | |
| 	.eqos_inval_desc = eqos_inval_desc_generic,
 | |
| 	.eqos_flush_desc = eqos_flush_desc_generic,
 | |
| 	.eqos_inval_buffer = eqos_inval_buffer_generic,
 | |
| 	.eqos_flush_buffer = eqos_flush_buffer_generic,
 | |
| 	.eqos_probe_resources = eqos_probe_resources_qcom,
 | |
| 	.eqos_remove_resources = eqos_remove_resources_qcom,
 | |
| 	.eqos_stop_resets = eqos_null_ops,
 | |
| 	.eqos_start_resets = eqos_start_resets_qcom,
 | |
| 	.eqos_stop_clks = eqos_stop_clks_qcom,
 | |
| 	.eqos_start_clks = eqos_start_clks_qcom,
 | |
| 	.eqos_calibrate_pads = eqos_null_ops,
 | |
| 	.eqos_disable_calibration = eqos_null_ops,
 | |
| 	.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_qcom,
 | |
| 	.eqos_get_enetaddr = eqos_null_ops,
 | |
| };
 | |
| 
 | |
| struct eqos_config __maybe_unused eqos_qcom_config = {
 | |
| 	.reg_access_always_ok = false,
 | |
| 	.mdio_wait = 10,
 | |
| 	.swr_wait = 50,
 | |
| 	.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
 | |
| 	.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
 | |
| 	.axi_bus_width = EQOS_AXI_WIDTH_64,
 | |
| 	.interface = dev_read_phy_mode,
 | |
| 	.ops = &eqos_qcom_ops
 | |
| };
 |