diff options
Diffstat (limited to 'drivers')
28 files changed, 2272 insertions, 155 deletions
diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c index 78a2410ca21..2e0c382ef30 100644 --- a/drivers/clk/clk_versal.c +++ b/drivers/clk/clk_versal.c @@ -326,6 +326,7 @@ static int __versal_clock_get_parents(struct clock_parent *parents, u32 *data, parent = &parents[i]; parent->id = data[i] & CLK_PARENTS_ID_MASK; if (data[i] == DUMMY_PARENT) { + parent->id = 0; strcpy(parent->name, "dummy_name"); parent->flag = 0; } else { diff --git a/drivers/clk/mediatek/clk-mt8189.c b/drivers/clk/mediatek/clk-mt8189.c index 9e640059f11..d11947ee461 100644 --- a/drivers/clk/mediatek/clk-mt8189.c +++ b/drivers/clk/mediatek/clk-mt8189.c @@ -1641,6 +1641,46 @@ static const struct mtk_gate mminfra_config_clks[] = { GATE_MMINFRA_CONFIG1(CLK_MMINFRA_GCE_26M, CLK_TOP_MMINFRA_SEL, 17), }; +static const struct mtk_gate_regs ufscfg_ao_reg_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x4, +}; + +#define GATE_UFSCFG_AO_REG_EXT(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_EXT) + +#define GATE_UFSCFG_AO_REG_TOP(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate ufs_config_ao_clks[] = { + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM, CLK_PAD_CLK26M, 1), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0, CLK_PAD_CLK26M, 2), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1, CLK_PAD_CLK26M, 3), + GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_UNIPRO_SYS, CLK_TOP_U_SEL, 4), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_U_SAP_CFG, CLK_PAD_CLK26M, 5), + GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS, CLK_TOP_AXI_U_SEL, 6), +}; + +static const struct mtk_gate_regs ufscfg_pdn_reg_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x4, +}; + +#define GATE_UFSCFG_PDN_REG(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_pdn_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate ufs_config_pdn_clks[] = { + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_UFS, CLK_TOP_U_SEL, 0), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_AES, CLK_TOP_AES_UFSFDE_SEL, 1), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AHB, CLK_TOP_AXI_U_SEL, 3), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AXI, CLK_TOP_MEM_SUB_U_SEL, 5), +}; + static const struct mtk_parent vlp_26m_oscd10_parents[] = { EXT_PARENT(CLK_PAD_CLK26M), TOP_PARENT(CLK_TOP_OSC_D10), @@ -1955,6 +1995,8 @@ GATE_CLK_DATA(perao_clks); GATE_CLK_DATA(imp_clks); GATE_CLK_DATA(mm_clks); GATE_CLK_DATA(mminfra_config_clks); +GATE_CLK_DATA(ufs_config_ao_clks); +GATE_CLK_DATA(ufs_config_pdn_clks); GATE_CLK_DATA(vlpcfg_ao_clks); static const struct udevice_id of_match_mt8189_clk_gate[] = { @@ -1962,6 +2004,8 @@ static const struct udevice_id of_match_mt8189_clk_gate[] = { { .compatible = "mediatek,mt8189-iic-wrap", .data = (ulong)&imp_clks_data }, { .compatible = "mediatek,mt8189-dispsys", .data = (ulong)&mm_clks_data }, { .compatible = "mediatek,mt8189-mm-infra", .data = (ulong)&mminfra_config_clks_data }, + { .compatible = "mediatek,mt8189-ufscfg-ao", .data = (ulong)&ufs_config_ao_clks_data }, + { .compatible = "mediatek,mt8189-ufscfg-pdn", .data = (ulong)&ufs_config_pdn_clks_data }, { .compatible = "mediatek,mt8189-vlpcfg-ao", .data = (ulong)&vlpcfg_ao_clks_data }, { } }; diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 3557aeac3d5..9d0a6cd79cf 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -204,10 +204,6 @@ static ulong mtk_clk_find_parent_rate(struct clk *clk, int id, return clk_get_rate(&parent); } -const struct clk_ops mtk_clk_apmixedsys_ops; -const struct clk_ops mtk_clk_topckgen_ops; -const struct clk_ops mtk_clk_infrasys_ops; - static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk, const int parent, u16 flags) { @@ -216,15 +212,21 @@ static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk, switch (flags & CLK_PARENT_MASK) { case CLK_PARENT_APMIXED: /* APMIXEDSYS can be parent or grandparent. */ - if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops) + if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(clk->dev) == &mtk_clk_fixed_pll_ops) { parent_dev = clk->dev; - else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops) + } else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(priv->parent) == &mtk_clk_fixed_pll_ops) { parent_dev = priv->parent; - else if (dev_get_driver_ops(dev_get_parent(priv->parent)) == &mtk_clk_apmixedsys_ops) - parent_dev = dev_get_parent(priv->parent); - else - return -EINVAL; - + } else { + struct udevice *grandparent_dev = dev_get_parent(priv->parent); + + if (dev_get_driver_ops(grandparent_dev) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(grandparent_dev) == &mtk_clk_fixed_pll_ops) + parent_dev = grandparent_dev; + else + return -EINVAL; + } break; case CLK_PARENT_TOPCKGEN: if (dev_get_driver_ops(clk->dev) == &mtk_clk_topckgen_ops) diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index b11e36202c1..969492aae37 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -598,6 +598,25 @@ int of_read_u64(const struct device_node *np, const char *propname, u64 *outp) return of_read_u64_index(np, propname, 0, outp); } +int of_read_u64_array(const struct device_node *np, const char *propname, + u64 *out_values, size_t sz) +{ + const __be64 *val; + + log_debug("%s: %s: ", __func__, propname); + val = of_find_property_value_of_size(np, propname, + sz * sizeof(*out_values)); + + if (IS_ERR(val)) + return PTR_ERR(val); + + log_debug("size %zd\n", sz); + while (sz--) + *out_values++ = be64_to_cpup(val++); + + return 0; +} + int of_property_match_string(const struct device_node *np, const char *propname, const char *string) { @@ -845,6 +864,39 @@ int of_count_phandle_with_args(const struct device_node *np, cell_count); } +/** + * of_property_count_elems_of_size - Count the number of elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @elem_size: size of the individual element + * + * Search for a property in a device node and count the number of elements of + * size elem_size in it. + * + * Return: The number of elements on sucess, -EINVAL if the property does not + * exist or its length does not match a multiple of elem_size and -ENODATA if + * the property does not have a value. + */ +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + const struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + if (prop->length % elem_size != 0) { + pr_err("size of %s in node %pOF is not a multiple of %d\n", + propname, np, elem_size); + return -EINVAL; + } + + return prop->length / elem_size; +} + static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 3a36b6fdd03..d605c0f7b7c 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -664,6 +664,54 @@ int ofnode_read_u32_array(ofnode node, const char *propname, } } +int ofnode_read_u64_array(ofnode node, const char *propname, + u64 *out_values, size_t sz) +{ + assert(ofnode_valid(node)); + log_debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + return of_read_u64_array(ofnode_to_np(node), propname, + out_values, sz); + } else { + int ret; + + ret = fdtdec_get_long_array(ofnode_to_fdt(node), + ofnode_to_offset(node), propname, + out_values, sz); + + /* get the error right, but space is more important in SPL */ + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { + if (ret == -FDT_ERR_NOTFOUND) + return -EINVAL; + else if (ret == -FDT_ERR_BADLAYOUT) + return -EOVERFLOW; + } + return ret; + } +} + +int ofnode_count_elems_of_size(ofnode node, const char *propname, int elem_size) +{ + const char *prop; + int len; + assert(ofnode_valid(node)); + + if (ofnode_is_np(node)) { + return of_property_count_elems_of_size(node.np, propname, elem_size); + } else { + prop = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), propname, &len); + if (!prop) + return -ENOENT; + if (len % elem_size != 0) { + log_debug("size of %s in node %pOF is not a multiple of %d\n", + propname, &node, elem_size); + return -EINVAL; + } + return len / elem_size; + } +} + #if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE) bool ofnode_is_enabled(ofnode node) { diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig index 0a45340ffb6..b953bca4f06 100644 --- a/drivers/ddr/imx/imx9/Kconfig +++ b/drivers/ddr/imx/imx9/Kconfig @@ -24,9 +24,9 @@ config IMX9_DRAM_INLINE_ECC config SAVED_DRAM_TIMING_BASE hex "Define the base address for saved dram timing" + default 0x2051C000 help after DRAM is trained, need to save the dram related timming info into memory for low power use. - default 0x2051C000 endmenu diff --git a/drivers/ddr/imx/phy/helper.c b/drivers/ddr/imx/phy/helper.c index b0dfc3a0b4f..147ec9ab061 100644 --- a/drivers/ddr/imx/phy/helper.c +++ b/drivers/ddr/imx/phy/helper.c @@ -38,6 +38,8 @@ binman_sym_declare(ulong, ddr_2d_dmem_fw, image_pos); binman_sym_declare(ulong, ddr_2d_dmem_fw, size); #endif +binman_sym_declare(ulong, u_boot_spl, image_pos); + /* We need PHY iMEM PHY is 32KB padded */ void ddr_load_train_firmware(enum fw_type type) { @@ -49,6 +51,7 @@ void ddr_load_train_firmware(enum fw_type type) unsigned long dmem_start; unsigned long imem_len = IMEM_LEN, dmem_len = DMEM_LEN; static enum fw_type last_type = -1; + unsigned long spl_start = 0; /* If FW doesn't change, we can save the loading. */ if (last_type == type) @@ -67,6 +70,9 @@ void ddr_load_train_firmware(enum fw_type type) dmem_start = imem_start + imem_len; if (BINMAN_SYMS_OK) { + if (IS_ENABLED(CONFIG_IMX8MQ)) + spl_start = binman_sym(ulong, u_boot_spl, image_pos); + switch (type) { case FW_1D_IMAGE: imem_start = binman_sym(ulong, ddr_1d_imem_fw, image_pos); @@ -83,6 +89,13 @@ void ddr_load_train_firmware(enum fw_type type) #endif break; } + + if (IS_ENABLED(CONFIG_IMX8MQ)) { + imem_start -= spl_start; + imem_start += CONFIG_SPL_TEXT_BASE; + dmem_start -= spl_start; + dmem_start += CONFIG_SPL_TEXT_BASE; + } } pr_from32 = imem_start; diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 25b348648ef..44d7ad6bd54 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -11,6 +11,7 @@ * Xilinx FPGA support */ +#include <env.h> #include <fpga.h> #include <log.h> #include <virtex2.h> @@ -92,7 +93,11 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, __func__); printf("%s: Bitstream ID %s, current device ID %d/%s\n", __func__, dataptr, devnum, xdesc->name); - return FPGA_FAIL; + if (!CONFIG_IS_ENABLED(ENV_SUPPORT) || + env_get_yesno("fpga_skip_idcheck") != 1) + return FPGA_FAIL; + + printf("%s: Skipping ID check\n", __func__); } } else { printf("%s: Please fill correct device ID to xilinx_desc\n", diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index a4ba27904bc..206f1a381bb 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -8,6 +8,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <fdt_support.h> #include <malloc.h> @@ -20,14 +21,21 @@ #include <linux/bug.h> #include <linux/delay.h> #include <linux/build_bug.h> +#include <linux/bitfield.h> +#include <power/regulator.h> +#include "fsl_enetc.h" #ifdef CONFIG_ARCH_IMX9 #include <asm/mach-imx/sys_proto.h> #include <cpu_func.h> +#include "fsl_enetc_xpcs_phy.c" +#else +static inline int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + return 0; +} #endif -#include "fsl_enetc.h" - #define ENETC_DRIVER_NAME "enetc_eth" /* @@ -454,19 +462,23 @@ static void enetc_setup_mac_iface(struct udevice *dev, /* set up serdes for SXGMII */ static int enetc_init_sxgmii(struct udevice *dev) { - struct enetc_priv *priv = dev_get_priv(dev); - if (!enetc_has_imdio(dev)) return 0; - /* Dev ability - SXGMII */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); + if (enetc_is_imx95(dev)) { + xpcs_phy_usxgmii_pma_config(dev); + } else { + struct enetc_priv *priv = dev_get_priv(dev); + + /* Dev ability - SXGMII */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); - /* Restart PCS AN */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_CR, - ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + /* Restart PCS AN */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_CR, + ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + } return 0; } @@ -523,6 +535,10 @@ static int enetc_config_phy(struct udevice *dev) return -ENODEV; supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; + + if (enetc_is_imx95(dev)) + supported |= PHY_10G_FEATURES; + priv->phy->supported &= supported; priv->phy->advertising &= supported; @@ -537,12 +553,31 @@ static int enetc_probe(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); int res; + struct udevice *supply = NULL; if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_enabled(dev_ofnode(dev))) { enetc_dbg(dev, "interface disabled\n"); return -ENODEV; } + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + res = device_get_supply_regulator(dev, "serdes-supply", + &supply); + if (res && res != -ENOENT) { + printf("%s: device_get_supply_regulator failed: %d\n", + __func__, res); + return res; + } + + if (supply) { + res = regulator_set_enable_if_allowed(supply, true); + if (res) { + printf("%s: Error enabling phy supply\n", dev->name); + return res; + } + } + } + priv->enetc_txbd = memalign(ENETC_BD_ALIGN, sizeof(struct enetc_tx_bd) * ENETC_BD_CNT); priv->enetc_rxbd = memalign(ENETC_BD_ALIGN, diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 804df853bf5..6d868e82f8c 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -205,6 +205,7 @@ struct enetc_data { /* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */ #define ENETC_PCS_PHY_ADDR 0 +#define ENETC_NON_PCS_PHY_ADDR 16 /* PCS registers */ #define ENETC_PCS_CR 0x00 diff --git a/drivers/net/fsl_enetc_xpcs_phy.c b/drivers/net/fsl_enetc_xpcs_phy.c new file mode 100644 index 00000000000..4039690223d --- /dev/null +++ b/drivers/net/fsl_enetc_xpcs_phy.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP + */ + +#define XPCS_PHY_GLOBAL 0x0 +#define XPCS_PHY_MPLLA 0x1 +#define XPCS_PHY_MPLLB 0x2 +#define XPCS_PHY_LANE 0x3 +#define XPCS_PHY_MAC_ADAPTER 0x1f + +#define XPCS_PHY_REG(x) (((x) & 0x1fffe) >> 1) + +/* MAC ADAPTER */ +#define MAC_ADAPTER_LOCK_PHY 0x200 +#define MAC_ADAPTER_LOCK_MPLLA 0x204 +#define MAC_ADAPTER_LOCK_MPLLB 0x208 +#define MAC_ADAPTER_LOCK_ROM 0x20c +#define MAC_ADAPTER_LOCK_RAM 0x210 +#define MAC_ADAPTER_LOCK_EVENT 0x214 + +#define MAC_ADAPTER_LOCK_LOCK BIT(7) + +/* PMA */ +#define PMA_RX_LSTS 0x10040 +#define PMA_RX_LSTS_RX_VALID_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL0 0x10060 +#define PMA_TX_GENCTRL0_TX_RST_0 BIT(8) +#define PMA_TX_GENCTRL0_TX_DT_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL1 0x10062 +#define PMA_TX_GENCTRL1_VBOOST_EN_0 BIT(4) +#define PMA_TX_GENCTRL1_VBOOST_LVL_MASK GENMASK(10, 8) +#define PMA_TX_GENCTRL1_VBOOST_LVL(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_TX_GENCTRL1_TX_CLK_RDY_0 BIT(12) +#define PMA_MP_12G_16G_TX_GENCTRL2 0x10064 +#define PMA_TX_GENCTRL2_TX_REQ_0 BIT(0) +#define PMA_TX_GENCTRL2_TX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_TX_GENCTRL2_TX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_25G_TX_BOOST_CTRL 0x10066 +#define PMA_TX_BOOST_CTRL_TX0_IBOOST_MASK GENMASK(3, 0) +#define PMA_TX_BOOST_CTRL_TX0_IBOOST(x) ((x) & GENMASK(3, 0)) +#define PMA_MP_12G_16G_25G_TX_RATE_CTRL 0x10068 +#define PMA_TX_RATE_CTRL_TX0_RATE_MASK GENMASK(2, 0) +#define PMA_TX_RATE_CTRL_TX0_RATE(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL 0x1006A +#define PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_POWER_STATE_CTRL_TX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_POWER_STATE_CTRL_TX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL0 0x1006C +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE(x) ((x) & GENMASK(5, 0)) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK GENMASK(13, 8) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN(x) (((x) << 8) & GENMASK(13, 8)) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL1 0x1006E +#define PMA_TX_EQ_CTRL1_TX_EQ_POST_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL1_TX_EQ_POST(x) ((x) & GENMASK(5, 0)) +#define PMA_MP_16G_25G_TX_MISC_CTRL0 0x1007C +#define PMA_TX_MISC_CTRL0_TX0_MISC_MASK GENMASK(7, 0) +#define PMA_TX_MISC_CTRL0_TX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_12G_16G_25G_RX_GENCTRL0 0x100A0 +#define PMA_RX_GENCTRL0_RX_DT_EN_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_GENCTRL1 0x100A2 +#define PMA_RX_GENCTRL1_RX_RST_0 BIT(4) +#define PMA_RX_GENCTRL1_RX_TERM_ACDC_0 BIT(8) +#define PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0 BIT(12) +#define PMA_MP_12G_16G_RX_GENCTRL2 0x100A4 +#define PMA_RX_GENCTRL2_RX_REQ_0 BIT(0) +#define PMA_RX_GENCTRL2_RX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_RX_GENCTRL2_RX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_RX_GENCTRL3 0x100A6 +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK GENMASK(2, 0) +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0(x) ((x) & GENMASK(2, 0)) +#define PMA_RX_GENCTRL3_LOS_LFPS_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_RX_RATE_CTRL 0x100A8 +#define PMA_RX_RATE_CTRL_RX0_RATE_MASK GENMASK(1, 0) +#define PMA_RX_RATE_CTRL_RX0_RATE(x) ((x) & GENMASK(1, 0)) +#define PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL 0x100AA +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_CDR_CTRL 0x100AC +#define PMA_RX_CDR_CTRL_CDR_SSC_EN_0 BIT(4) +#define PMA_MP_12G_16G_25G_RX_ATTN_CTRL 0x100AE +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL_MASK GENMASK(2, 0) +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_16G_25G_RX_EQ_CTRL0 0x100B0 +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK GENMASK(4, 0) +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0(x) ((x) & GENMASK(4, 0)) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK GENMASK(6, 5) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0(x) (((x) << 5) & GENMASK(6, 5)) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK GENMASK(10, 8) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK GENMASK(14, 12) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0(x) (((x) << 12) & GENMASK(14, 12)) +#define PMA_MP_12G_16G_25G_RX_EQ_CTRL4 0x100B8 +#define PMA_RX_EQ_CTRL4_CONT_ADAPT_0 BIT(0) +#define PMA_RX_EQ_CTRL4_RX_AD_REQ BIT(12) +#define PMA_MP_16G_25G_RX_EQ_CTRL5 0x100BA +#define PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0 BIT(0) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK GENMASK(5, 4) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE(x) (((x) << 4) & GENMASK(5, 4)) +#define PMA_MP_12G_16G_25G_DFE_TAP_CTRL0 0x100BC +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0_MASK GENMASK(7, 0) +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_RX_CDR_CTRL1 0x100C8 +#define PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0 BIT(0) +#define PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0 BIT(4) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK GENMASK(9, 8) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_16G_25G_RX_PPM_CTRL0 0x100CA +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX_MASK GENMASK(4, 0) +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(x) ((x) & GENMASK(4, 0)) +#define PMA_MP_16G_25G_RX_GENCTRL4 0x100D0 +#define PMA_RX_GENCTRL4_RX_DFE_BYP_0 BIT(8) +#define PMA_MP_16G_25G_RX_MISC_CTRL0 0x100D2 +#define PMA_RX_MISC_CTRL0_RX0_MISC_MASK GENMASK(7, 0) +#define PMA_RX_MISC_CTRL0_RX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_25G_RX_IQ_CTRL0 0x100D6 +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ_MASK GENMASK(6, 0) +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ(x) ((x) & GENMASK(6, 0)) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK GENMASK(11, 8) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ(x) (((x) << 8) & GENMASK(11, 8)) +#define PMA_MP_12G_16G_25G_MPLL_CMN_CTRL 0x100E0 +#define PMA_MPLL_CMN_CTRL_MPLL_EN_0 BIT(0) +#define PMA_MPLL_CMN_CTRL_MPLLB_SEL_0 BIT(4) +#define PMA_MP_12G_16G_MPLLA_CTRL0 0x100E2 +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_MPLLA_CTRL1 0x100E4 +#define PMA_MPLLA_CTRL1_MPLLA_SSC_EN BIT(0) +#define PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL BIT(4) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK GENMASK(15, 5) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL(x) (((x) << 5) & GENMASK(15, 5)) +#define PMA_MP_12G_16G_MPLLA_CTRL2 0x100E6 +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK GENMASK(6, 0) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT(x) ((x) & GENMASK(6, 0)) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN BIT(7) +#define PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN BIT(8) +#define PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN BIT(9) +#define PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN BIT(10) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK GENMASK(12, 11) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV(x) (((x) << 11) & GENMASK(12, 11)) +#define PMA_MP_16G_MPLLA_CTRL3 0x100EE +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH_MASK GENMASK(15, 0) +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(x) ((x) & GENMASK(15, 0)) +#define PMA_MP_16G_MPLLA_CTRL4 0x100F2 +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT_MASK GENMASK(11, 0) +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT(x) ((x) & GENMASK(11, 0)) +#define PMA_MP_16G_MPLLA_CTRL5 0x100F4 +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK(x) ((x) & GENMASK(7, 0)) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN BIT(8) +#define PMA_MP_12G_16G_25G_MISC_CTRL0 0x10120 +#define PMA_MISC_CTRL0_RX_VREF_CTRL_MASK GENMASK(12, 8) +#define PMA_MISC_CTRL0_RX_VREF_CTRL(x) (((x) << 8) & GENMASK(12, 8)) +#define PMA_MP_12G_16G_25G_REF_CLK_CTRL 0x10122 +#define PMA_REF_CLK_CTRL_REF_CLK_DIV2 BIT(2) +#define PMA_REF_CLK_CTRL_REF_RANGE_MASK GENMASK(5, 3) +#define PMA_REF_CLK_CTRL_REF_RANGE(x) (((x) << 3) & GENMASK(5, 3)) +#define PMA_REF_CLK_CTRL_REF_MPLLA_DIV2 BIT(6) +#define PMA_MP_12G_16G_25G_VCO_CAL_LD0 0x10124 +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0_MASK GENMASK(12, 0) +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0(x) ((x) & GENMASK(12, 0)) +#define PMA_MP_16G_25G_VCO_CAL_REF0 0x1012C +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0_MASK GENMASK(6, 0) +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0(x) ((x) & GENMASK(6, 0)) +#define PMA_MP_12G_16G_25G_MISC_STS 0x10130 +#define PMA_MISC_STS_RX_ADPT_ACK BIT(12) +#define PMA_MP_12G_16G_25G_SRAM 0x10136 +#define PMA_SRAM_INIT_DN BIT(0) +#define PMA_SRAM_EXT_LD_DN BIT(1) +#define PMA_MP_16G_25G_MISC_CTRL2 0x10138 +#define PMA_MISC_CTRL2_SUP_MISC_MASK GENMASK(7, 0) +#define PMA_MISC_CTRL2_SUP_MISC(x) ((x) & GENMASK(7, 0)) + +/* PCS */ +#define PCS_CTRL1 0x0 +#define PCS_CTRL1_RESET BIT(15) +#define PCS_CTRL2 0xE +#define PCS_CTRL2_PCS_TYPE_SEL_MASK GENMASK(3, 0) +#define PCS_CTRL2_PCS_TYPE_SEL(x) ((x) & GENMASK(3, 0)) +#define PCS_DIG_CTRL1 0x10000 +#define PCS_DIG_CTRL1_USXG_EN BIT(9) +#define PCS_DIG_CTRL1_USRA_RST BIT(10) +#define PCS_DIG_CTRL1_VR_RST BIT(15) +#define PCS_DEBUG_CTRL 0x1000A +#define PCS_DEBUG_CTRL_SUPRESS_LOS_DET BIT(4) +#define PCS_DEBUG_CTRL_RX_DT_EN_CTL BIT(6) +#define PCS_DEBUG_CTRL_TX_PMBL_CTL BIT(8) +#define PCS_KR_CTRL1 0x1000E +#define PCS_KR_CTRL1_USXG_MODE_MASK GENMASK(12, 10) +#define PCS_KR_CTRL1_USXG_MODE(x) (((x) << 10) & GENMASK(12, 10)) + +/* VS MII MMD */ +#define MII_CTRL 0x0 +#define MII_CTRL_SS5 BIT(5) +#define MII_CTRL_SS6 BIT(6) +#define MII_CTRL_AN_ENABLE BIT(12) +#define MII_CTRL_SS13 BIT(13) +#define MII_DIG_CTRL1 0x10000 +#define MII_DIG_CTRL1_CL37_TMR_OVR_RIDE BIT(3) +#define MII_AN_CTRL 0x10002 +#define MII_AN_CTRL_MII_AN_INTR_EN BIT(0) +#define MII_AN_CTRL_TX_CONFIG BIT(3) +#define MII_AN_INTR_STS 0x10004 +#define MII_AN_INTR_STS_CL37_ANCMPLT_INTR BIT(0) +#define MII_LINK_TIMER_CTRL 0x10014 +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME_MASK GENMASK(15, 0) +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME(x) ((x) & GENMASK(15, 0)) + +/* E16 MEM MAP */ +#define IDCODE_LO 0x0 +#define IDCODE_HI 0x4 +#define GLOBAL_CTRL_EX_0 0x114 +#define GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS BIT(0) +#define L0_RX_VCO_OVRD_OUT_0 0x20c +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE_MASK GENMASK(12, 3) +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE(x) (((x) << 3) & GENMASK(12, 3)) +#define L0_RX_VCO_OVRD_OUT_0_RX_CDR_FREQ_TUNE_OVRD_EN BIT(15) +#define L0_RX_VCO_OVRD_OUT_2 0x214 +#define L0_RX_VCO_OVRD_OUT_2_RX_ANA_CDR_FREQ_TUNE_CLK BIT(0) + +static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg); +static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val); + +int xpcs_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_phy_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read_pma(struct udevice *dev, u32 reg) +{ + return xpcs_read(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg)); +} + +int xpcs_phy_write_pma(struct udevice *dev, int reg, u16 val) +{ + return xpcs_write(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg), val); +} + +int xpcs_phy_usxgmii_init_seq_2(struct udevice *dev) +{ + ulong begin; + u16 val; + + /* Seq 2.1 Keep preamble data */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_TX_PMBL_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* Seq 2.2 Power up MPLLA to P1 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 2, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.3 Assert request of transmitand receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.4 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* Seq 2.5 Turn transmit to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 0, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val &= ~PMA_POWER_STATE_CTRL_TX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.6 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* Seq 2.7 Enable transmitter output driver in the PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* Seq 2.8 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* Seq 2.9 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.10 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + return 0; + +timeout: + return -ETIMEDOUT; +} + +void xpcs_phy_reg_lock(struct udevice *dev) +{ + u16 val; + ulong begin; + + if (xpcs_phy_read(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY)) & MAC_ADAPTER_LOCK_LOCK) + return; + + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLA), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLB), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_ROM), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_RAM), MAC_ADAPTER_LOCK_LOCK); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* Work around */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_CTRL1_RESET); + + mdelay(1); + +timeout: + return; +} + +int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + ulong begin; + u16 val; + + xpcs_phy_reg_lock(dev); + + /* 1.6 Turn off C37 auto-negotiation */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_AN_ENABLE; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + /* 1.7 Assert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.8 Wait for more than 1us */ + udelay(5); + + /* 1.9 Deassert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.10 Power down MPLLA */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* 1.11 Change RX0 power state to P2 */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val &= ~PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* TODO: check if it is needed */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 1, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 1.12 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 1.13 Poll for acknlowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 2 Config MPLL for 10G XGMII */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val = u16_replace_bits(val, 6, PMA_REF_CLK_CTRL_REF_RANGE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val &= ~PMA_REF_CLK_CTRL_REF_CLK_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val |= PMA_REF_CLK_CTRL_REF_MPLLA_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val = u16_replace_bits(val, 5, PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL4, 0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 33, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val = u16_replace_bits(val, 5, PMA_TX_GENCTRL1_VBOOST_LVL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0); + val = u16_replace_bits(val, 0x11, PMA_MISC_CTRL0_RX_VREF_CTRL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0, val); + + val = PMA_MISC_CTRL2_SUP_MISC(1); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_MISC_CTRL2, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_PPM_CTRL0, val); + + /* 3 Configure LANE0 for 10G XGMII */ + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_TX_MISC_CTRL0, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLLB_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_TX_BOOST_CTRL_TX0_IBOOST(0xf); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_BOOST_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0, PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + val = PMA_TX_EQ_CTRL1_TX_EQ_POST(0x20); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0x20, PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x2, PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val = u16_replace_bits(val, 0x7, PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_CDR_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val &= ~PMA_RX_GENCTRL3_LOS_LFPS_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_ATTN_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_DFE_TAP_CTRL0, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_TERM_ACDC_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val &= ~PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + /* 4 Configure XPCS for 10G XGMII */ + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL2), 0x0); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_USXG_EN; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1)); + val = u16_replace_bits(val, 0x0, PCS_KR_CTRL1_USXG_MODE_MASK); + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1), val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 0x21, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_CONT_ADAPT_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val &= ~PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* 5 Assert soft reset */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_VR_RST; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + /* 6 Poll for SRAM initialization done */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* 7 Assert SRAM external loading done */ + /* Workaround */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + /* 8 Poll for vendor-specific soft reset */ + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_DIG_CTRL1_VR_RST); + + /* 9 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 10 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* 11 Assert request of receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 11.1 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 12 Assert TX0 clock is active and stable */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* + * 13.1 Configure XPCS to consider Loss-of-Signal indicated by the + * PHY while evaluating the receive link status + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_SUPRESS_LOS_DET; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + /* + * 13.2 Configure XPCS to deassert "receiver data enable" on + * detecting of Loss-of-Signal + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_RX_DT_EN_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* 14 Poll for DPLL lock status for Lane 0 */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_RX_LSTS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_RX_LSTS_RX_VALID_0)); + + /* 15 Assert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 16 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_STS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_MISC_STS_RX_ADPT_ACK)); + + /* 17 Deassert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val &= ~PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 18 Set the value of Config_Reg to 0 for Clause 37 autonegotiation. */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL)); + val &= ~MII_AN_CTRL_TX_CONFIG; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL), val); + + /* 19 Select XGMII speed */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_SS5; + val |= MII_CTRL_SS6 | MII_CTRL_SS13; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + val = xpcs_phy_usxgmii_init_seq_2(dev); + if (val) + return val; + + return 0; + +timeout: + return -ETIMEDOUT; +} + +u32 xpcs_phy_get_id(struct udevice *dev) +{ + int ret; + u32 id; + + /* First, search C73 PCS using PCS MMD */ + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_HI)); + if (ret < 0) + return 0xffffffff; + + id = ret << 16; + + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_LO)); + if (ret < 0) + return 0xffffffff; + + /* If Device IDs are not all zeros or all ones, + * we found C73 AN-type device + */ + if ((id | ret) && (id | ret) != 0xffffffff) + return id | ret; + + return 0xffffffff; +} diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 10b87dfb8ab..83da3e1cc77 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -400,7 +400,7 @@ int aquantia_config(struct phy_device *phydev) int interface = phydev->interface; u32 val, id, rstatus, fault; u32 reg_val1 = 0; - int num_retries = 5; + int num_retries = 200; int usx_an = 0; /* diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index e9cc5db52d2..1ea81fe1830 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -28,6 +28,10 @@ #define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */ #define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */ +/* Reset and Address Filter (RAF) Register bit definitions */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject rx multicast dst addr */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject rx broadcast dst addr */ + /* Interrupt Status/Enable/Mask Registers bit definitions */ #define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */ #define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */ @@ -153,7 +157,8 @@ static struct axidma_bd tx_bd __attribute((aligned(DMAALIGN))); static struct axidma_bd rx_bd __attribute((aligned(DMAALIGN))); struct axi_regs { - u32 reserved[3]; + u32 raf; /* 0x0: Reset and Address Filter */ + u32 reserved[2]; u32 is; /* 0xC: Interrupt status */ u32 reserved2; u32 ie; /* 0x14: Interrupt enable */ @@ -528,6 +533,19 @@ static int axi_ethernet_init(struct axidma_priv *priv) /* Set default MDIO divisor */ writel(XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK, ®s->mdio_mc); + /* + * Reject broadcast and multicast frames at MAC level to reduce + * unnecessary traffic processing. Multicast rejection is only + * enabled when IPv6 is not configured because IPv6 Neighbor + * Discovery and DHCPv6 rely on multicast. + */ + if (!IS_ENABLED(CONFIG_IPV6)) + writel(readl(®s->raf) | XAE_RAF_MCSTREJ_MASK | + XAE_RAF_BCSTREJ_MASK, ®s->raf); + else + writel(readl(®s->raf) | XAE_RAF_BCSTREJ_MASK, + ®s->raf); + debug("axiemac: InitHw done\n"); return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index a50d5aee03f..f570ae9ee73 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -69,10 +69,13 @@ #define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x08000000 /* SGMII Enable */ #define ZYNQ_GEM_NWCFG_PCS_SEL 0x00000800 /* PCS select */ +#define ZYNQ_GEM_DBUS_WIDTH_MASK (3 << 21) /* bits 22:21 */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (2 << 21) /* 128 bit bus */ #else # define ZYNQ_GEM_DBUS_WIDTH (0 << 21) /* 32 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (0 << 21) /* 32 bit bus */ #endif #define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_DBUS_WIDTH | \ @@ -134,6 +137,7 @@ #define ZYNQ_GEM_FREQUENCY_10 2500000UL #define ZYNQ_GEM_FREQUENCY_100 25000000UL #define ZYNQ_GEM_FREQUENCY_1000 125000000UL +#define ZYNQ_GEM_FREQUENCY_10000 150000000UL #define RXCLK_EN BIT(0) @@ -470,28 +474,6 @@ static int zynq_gem_init(struct udevice *dev) for (i = 0; i < STAT_SIZE; i++) readl(®s->stat[i]); - /* Setup RxBD space */ - memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); - - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = - (lower_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#if defined(CONFIG_PHYS_64BIT) - priv->rx_bd[i].addr_hi = - (upper_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#endif - } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); -#if defined(CONFIG_PHYS_64BIT) - writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); -#endif - /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); @@ -520,6 +502,35 @@ static int zynq_gem_init(struct udevice *dev) priv->init++; } + /* + * Reinitialize RX BDs on every init. The 10GBE USX block asserts + * RX_SYNC_RESET during setup which resets the GEM RX DMA pointer + * back to rxqbase, so BDs and rxqbase must be refreshed each time + * to keep the hardware and driver ring indices in sync. + */ + priv->rxbd_current = 0; + priv->rx_first_buf = 0; + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (lower_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#if defined(CONFIG_PHYS_64BIT) + priv->rx_bd[i].addr_hi = + (upper_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#endif + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + + /* Write RxBDs to IP */ + writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); +#if defined(CONFIG_PHYS_64BIT) + writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); +#endif + ret = phy_startup(priv->phydev); if (ret) return ret; @@ -532,6 +543,8 @@ static int zynq_gem_init(struct udevice *dev) nwconfig = ZYNQ_GEM_NWCFG_INIT; if (device_is_compatible(dev, "amd,versal2-10gbe")) { + nwconfig &= ~ZYNQ_GEM_DBUS_WIDTH_MASK; + nwconfig |= ZYNQ_GEM_DBUS_WIDTH_128; if (priv->interface == PHY_INTERFACE_MODE_10GBASER) { ctrl = readl(®s->nwcfg); ctrl |= PCSSEL; @@ -602,6 +615,9 @@ static int zynq_gem_init(struct udevice *dev) } switch (priv->phydev->speed) { + case SPEED_10000: + clk_rate = ZYNQ_GEM_FREQUENCY_10000; + break; case SPEED_1000: nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000; clk_rate = ZYNQ_GEM_FREQUENCY_1000; @@ -615,6 +631,7 @@ static int zynq_gem_init(struct udevice *dev) break; } nwcfg = readl(®s->nwcfg); + nwcfg &= ~(ZYNQ_GEM_NWCFG_SPEED100 | ZYNQ_GEM_NWCFG_SPEED1000); nwcfg |= nwconfig; if (nwcfg) writel(nwcfg, ®s->nwcfg); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8fc57895a78..39df0e776df 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -456,6 +456,17 @@ config PCIE_STARFIVE_JH7110 Say Y here if you want to enable PLDA XpressRich PCIe controller support on StarFive JH7110 SoC. +config PCIE_DW_AMD + bool "AMD Versal2 DW PCIe host controller" + depends on ARCH_VERSAL2 + depends on DM_GPIO + select PCIE_DW_COMMON + select SYS_PCI_64BIT + help + Say Y here to enable support for the AMD Versal Gen 2 PCIe + host controller. This is a DesignWare-based PCIe controller + used in AMD Versal Gen 2 SoCs. + config PCIE_DW_IMX bool "i.MX DW PCIe controller support" depends on ARCH_IMX8M || ARCH_IMX9 diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98f3c226f63..e6d71fd172b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,4 +56,5 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o obj-$(CONFIG_PCIE_PLDA_COMMON) += pcie_plda_common.o obj-$(CONFIG_PCIE_STARFIVE_JH7110) += pcie_starfive_jh7110.o +obj-$(CONFIG_PCIE_DW_AMD) += pcie_dw_amd.o obj-$(CONFIG_PCIE_DW_IMX) += pcie_dw_imx.o diff --git a/drivers/pci/pcie_dw_amd.c b/drivers/pci/pcie_dw_amd.c new file mode 100644 index 00000000000..81c6d8f2817 --- /dev/null +++ b/drivers/pci/pcie_dw_amd.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal2 DesignWare PCIe host controller driver + * + * Copyright (C) 2025 - 2026, Advanced Micro Devices, Inc. + * Author: Pranav Sanwal <[email protected]> + */ + +#include <dm.h> +#include <log.h> +#include <pci.h> +#include <wait_bit.h> + +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <linux/delay.h> + +#include "pcie_dw_common.h" + +/* + * SLCR (System Level Control Register) Interrupt Register Offsets + * These are relative to the SLCR base address from device tree + */ +#define AMD_DW_TLP_IR_STATUS_MISC 0x4c0 +#define AMD_DW_TLP_IR_DISABLE_MISC 0x4cc + +/* Interrupt bit definitions */ +#define AMD_DW_PCIE_INTR_CMPL_TIMEOUT 15 +#define AMD_DW_PCIE_INTR_PM_PME_RCVD 24 +#define AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD 25 +#define AMD_DW_PCIE_INTR_MISC_CORRECTABLE 26 +#define AMD_DW_PCIE_INTR_NONFATAL 27 +#define AMD_DW_PCIE_INTR_FATAL 28 + +#define AMD_DW_PCIE_INTR_INTX_MASK GENMASK(23, 16) + +#define AMD_DW_PCIE_IMR_ALL_MASK \ + (BIT(AMD_DW_PCIE_INTR_CMPL_TIMEOUT) | \ + BIT(AMD_DW_PCIE_INTR_PM_PME_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_MISC_CORRECTABLE) | \ + BIT(AMD_DW_PCIE_INTR_NONFATAL) | \ + BIT(AMD_DW_PCIE_INTR_FATAL) | \ + AMD_DW_PCIE_INTR_INTX_MASK) + +/* DW PCIe Debug Registers (in DBI space) */ +#define AMD_DW_PCIE_PORT_DEBUG1 0x72c +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_UP BIT(4) +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29) +#define AMD_DW_PCIE_DBI_64BIT_MEM_DECODE BIT(0) + +/* Link training timeout */ +#define LINK_WAIT_MSLEEP_MAX 1000 + +/* PCIe spec timing requirements */ +#define PCIE_RESET_CONFIG_WAIT_MS 100 +#define PCIE_T_PERST_WAIT_MS 1 + +/** + * struct amd_dw_pcie - AMD DesignWare PCIe controller private data + * @dw: DesignWare PCIe common structure + * @slcr_base: System Level Control Register base (for interrupts) + */ +struct amd_dw_pcie { + struct pcie_dw dw; + void __iomem *slcr_base; +}; + +static void amd_dw_pcie_init_port(struct amd_dw_pcie *pcie) +{ + u32 val; + + if (!pcie->slcr_base) + return; + + /* Disable all TLP interrupts */ + writel(AMD_DW_PCIE_IMR_ALL_MASK, + pcie->slcr_base + AMD_DW_TLP_IR_DISABLE_MISC); + + /* Clear any pending TLP interrupts */ + val = readl(pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); + val &= AMD_DW_PCIE_IMR_ALL_MASK; + writel(val, pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); +} + +static void amd_dw_pcie_start_link(struct amd_dw_pcie *pcie) +{ + void __iomem *reg = pcie->dw.dbi_base + AMD_DW_PCIE_PORT_DEBUG1; + struct udevice *dev = pcie->dw.dev; + struct pcie_dw *pci = &pcie->dw; + int ret; + + ret = wait_for_bit_le32(reg, AMD_DW_PCIE_PORT_DEBUG1_LINK_UP, + true, LINK_WAIT_MSLEEP_MAX, + false); + if (!ret) + ret = wait_for_bit_le32(reg, + AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING, + false, LINK_WAIT_MSLEEP_MAX, false); + if (ret) + dev_warn(dev, "PCIE-%d: Link down\n", dev_seq(dev)); + else + dev_dbg(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", + dev_seq(dev), pcie_dw_get_link_speed(pci), + pcie_dw_get_link_width(pci), pci->first_busno); +} + +static void amd_dw_pcie_host_init(struct amd_dw_pcie *pcie) +{ + struct pcie_dw *pci = &pcie->dw; + + /* + * Set 64-bit prefetchable memory decode capability. U-Boot's pci_auto.c + * reads this bit before assigning prefetchable BARs. If cleared, it skips + * PCI_PREF_BASE_UPPER32 programming, causing 64-bit BAR assignment to fail. + */ + dw_pcie_dbi_write_enable(pci, true); + setbits_le32(pci->dbi_base + PCI_PREF_MEMORY_BASE, + AMD_DW_PCIE_DBI_64BIT_MEM_DECODE); + dw_pcie_dbi_write_enable(pci, false); + + amd_dw_pcie_init_port(pcie); + pcie_dw_setup_host(pci); +} + +static void amd_dw_pcie_request_gpio(struct udevice *dev) +{ + struct gpio_desc perst_gpio; + ofnode child_node; + int ret; + + /* + * PERST# reset GPIO is optional. Child PCI endpoint nodes may carry a + * 'reset-gpios' property to toggle the endpoint reset signal during + * initialization. If absent, the endpoint is assumed to be already + * released from reset. + */ + ofnode_for_each_subnode(child_node, dev_ofnode(dev)) { + ret = gpio_request_by_name_nodev(child_node, "reset-gpios", 0, + &perst_gpio, GPIOD_IS_OUT); + if (!ret) { + dev_dbg(dev, "Found reset-gpios in child node %s\n", + ofnode_get_name(child_node)); + dm_gpio_set_value(&perst_gpio, 1); + mdelay(PCIE_T_PERST_WAIT_MS); + dm_gpio_set_value(&perst_gpio, 0); + mdelay(PCIE_RESET_CONFIG_WAIT_MS); + dm_gpio_free(dev, &perst_gpio); + } + } +} + +static int amd_dw_pcie_of_to_plat(struct udevice *dev) +{ + struct pci_region *io_region, *mem_region, *pref_region; + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + int ret; + + pci->dev = dev; + + pci->dbi_base = dev_read_addr_name_ptr(dev, "dbi"); + if (!pci->dbi_base) { + dev_err(dev, "Missing 'dbi' register region\n"); + return -EINVAL; + } + + pci->cfg_base = dev_read_addr_size_name_ptr(dev, "config", &pci->cfg_size); + if (!pci->cfg_base) { + dev_err(dev, "Missing 'config' register region\n"); + return -EINVAL; + } + + pci->atu_base = dev_read_addr_name_ptr(dev, "atu"); + if (!pci->atu_base) { + dev_dbg(dev, "No 'atu' region, using default offset from DBI\n"); + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + + pcie->slcr_base = dev_read_addr_name_ptr(dev, "slcr"); + if (!pcie->slcr_base) + dev_dbg(dev, "No 'slcr' region, interrupt features disabled\n"); + + ret = pci_get_regions(dev, &io_region, &mem_region, &pref_region); + if (ret < 0) { + dev_err(dev, "Failed to get PCI regions: %d\n", ret); + return ret; + } + + if (mem_region) + pci->mem = *mem_region; + + return 0; +} + +static int amd_dw_pcie_probe(struct udevice *dev) +{ + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + + /* Set first bus number */ + pci->first_busno = dev_seq(dev); + + amd_dw_pcie_request_gpio(dev); + amd_dw_pcie_host_init(pcie); + amd_dw_pcie_start_link(pcie); + + if (pci->mem.size) { + dev_dbg(dev, "Programming ATU region 0 for MEM: phys=0x%llx bus=0x%llx size=0x%llx\n", + (unsigned long long)pci->mem.phys_start, + (unsigned long long)pci->mem.bus_start, + (unsigned long long)pci->mem.size); + pcie_dw_prog_outbound_atu_unroll(pci, + PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + pci->mem.phys_start, + pci->mem.bus_start, + pci->mem.size); + } else { + dev_warn(dev, "No MEM region configured!\n"); + } + + dev_dbg(dev, "dbi: 0x%lx | config: 0x%lx | atu: 0x%lx | slcr: 0x%lx\n", + (long)pci->dbi_base, (long)pci->cfg_base, + (long)pci->atu_base, (long)pcie->slcr_base); + + return 0; +} + +static const struct dm_pci_ops amd_dw_pcie_ops = { + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, +}; + +static const struct udevice_id amd_dw_pcie_ids[] = { + { .compatible = "amd,versal2-mdb-host" }, + { } +}; + +U_BOOT_DRIVER(pcie_dw_amd) = { + .name = "pcie_dw_amd", + .id = UCLASS_PCI, + .of_match = amd_dw_pcie_ids, + .ops = &amd_dw_pcie_ops, + .of_to_plat = amd_dw_pcie_of_to_plat, + .probe = amd_dw_pcie_probe, + .priv_auto = sizeof(struct amd_dw_pcie), +}; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 09810b62b51..fc4daa00661 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -292,6 +292,17 @@ config PHY_MTK_UFS initialization, power on and power off flow of specified M-PHYs. +config PHY_MTK_XSPHY + bool "MediaTek XS-PHY Driver" + depends on PHY + depends on ARCH_MEDIATEK + select REGMAP + select SYSCON + help + Enable this to support the SuperSpeedPlus XS-PHY transceiver for + USB3.1 GEN2 controllers on MediaTek chips. The driver supports + multiple USB2.0, USB3.1 GEN2 ports. + config PHY_NPCM_USB bool "Nuvoton NPCM USB PHY support" depends on PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 83102349669..684e9a99af8 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o +obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o diff --git a/drivers/phy/phy-mtk-ufs.c b/drivers/phy/phy-mtk-ufs.c index 1eda3df858d..c4c214dcde0 100644 --- a/drivers/phy/phy-mtk-ufs.c +++ b/drivers/phy/phy-mtk-ufs.c @@ -6,52 +6,41 @@ * Copyright (c) 2025, Igor Belwon <[email protected]> */ -#include "dm/ofnode.h" -#include "dm/read.h" -#include <clk.h> -#include <dm.h> -#include <generic-phy.h> -#include <malloc.h> -#include <mapmem.h> -#include <regmap.h> -#include <syscon.h> #include <asm/io.h> +#include <clk.h> +#include <dm/device.h> #include <dm/device_compat.h> -#include <dm/devres.h> -#include <linux/bitfield.h> +#include <dm/read.h> +#include <generic-phy.h> #include <linux/bitops.h> #include <linux/delay.h> - -#include <dt-bindings/phy/phy.h> +#include <mapmem.h> /* mphy register and offsets */ -#define MP_GLB_DIG_8C 0x008C -#define FRC_PLL_ISO_EN BIT(8) -#define PLL_ISO_EN BIT(9) -#define FRC_FRC_PWR_ON BIT(10) -#define PLL_PWR_ON BIT(11) - -#define MP_LN_DIG_RX_9C 0xA09C -#define FSM_DIFZ_FRC BIT(18) +#define MP_GLB_DIG_8C 0x008C +#define FRC_PLL_ISO_EN BIT(8) +#define PLL_ISO_EN BIT(9) +#define FRC_FRC_PWR_ON BIT(10) +#define PLL_PWR_ON BIT(11) -#define MP_LN_DIG_RX_AC 0xA0AC -#define FRC_RX_SQ_EN BIT(0) -#define RX_SQ_EN BIT(1) +#define MP_LN_DIG_RX_9C 0xA09C +#define FSM_DIFZ_FRC BIT(18) -#define MP_LN_RX_44 0xB044 -#define FRC_CDR_PWR_ON BIT(17) -#define CDR_PWR_ON BIT(18) -#define FRC_CDR_ISO_EN BIT(19) -#define CDR_ISO_EN BIT(20) +#define MP_LN_DIG_RX_AC 0xA0AC +#define FRC_RX_SQ_EN BIT(0) +#define RX_SQ_EN BIT(1) -#define UFSPHY_CLKS_CNT 2 +#define MP_LN_RX_44 0xB044 +#define FRC_CDR_PWR_ON BIT(17) +#define CDR_PWR_ON BIT(18) +#define FRC_CDR_ISO_EN BIT(19) +#define CDR_ISO_EN BIT(20) struct mtk_ufs_phy { struct udevice *dev; void __iomem *mmio; - struct clk *unipro_clk; - struct clk *mp_clk; + struct clk_bulk clk_bulk; }; static void ufs_mtk_phy_set_active(struct mtk_ufs_phy *phy) @@ -88,16 +77,9 @@ static int mtk_phy_power_on(struct phy *phy) struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); int ret; - ret = clk_enable(ufs_phy->mp_clk); - if (ret < 0) { - dev_err(phy->dev, "failed to enable mp_clk\n"); - return ret; - } - - ret = clk_enable(ufs_phy->unipro_clk); - if (ret < 0) { - dev_err(phy->dev, "failed to enable unipro_clk %d\n", ret); - clk_disable(ufs_phy->unipro_clk); + ret = clk_enable_bulk(&ufs_phy->clk_bulk); + if (ret) { + dev_err(phy->dev, "failed to enable clocks (ret=%d)\n", ret); return ret; } @@ -106,34 +88,44 @@ static int mtk_phy_power_on(struct phy *phy) return 0; } -static int mtk_phy_power_off(struct phy *phy) +static void ufs_mtk_phy_set_inactive(struct mtk_ufs_phy *phy) { - struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); - /* Set PHY to Deep Hibernate mode */ - setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + setbits_le32(phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); /* force DA_MP_RX0_SQ_EN */ - setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); - clrbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); + setbits_le32(phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + clrbits_le32(phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); /* force DA_MP_CDR_ISO_EN */ - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_ISO_EN); + setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); + setbits_le32(phy->mmio + MP_LN_RX_44, CDR_ISO_EN); /* force DA_MP_CDR_PWR_ON */ - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); - clrbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_PWR_ON); + setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); + clrbits_le32(phy->mmio + MP_LN_RX_44, CDR_PWR_ON); /* force DA_MP_PLL_ISO_EN */ - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); /* force DA_MP_PLL_PWR_ON */ - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); - clrbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + clrbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); +} - return 0; +static int mtk_phy_power_off(struct phy *phy) +{ + struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); + int ret; + + ufs_mtk_phy_set_inactive(ufs_phy); + + ret = clk_disable_bulk(&ufs_phy->clk_bulk); + if (ret) + dev_err(phy->dev, "failed to disable clocks (ret=%d)\n", ret); + + return ret; } static const struct phy_ops mtk_ufs_phy_ops = { @@ -147,10 +139,6 @@ static int mtk_ufs_phy_probe(struct udevice *dev) fdt_addr_t addr; int ret; - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENOMEM; - addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -ENOMEM; @@ -158,21 +146,11 @@ static int mtk_ufs_phy_probe(struct udevice *dev) phy->dev = dev; phy->mmio = map_sysmem(addr, 0); - phy->mp_clk = devm_clk_get(dev, "mp"); - if (IS_ERR(phy->mp_clk)) { - ret = PTR_ERR(phy->mp_clk); - dev_err(dev, "Failed to get mp clock (ret=%d)\n", ret); - return ret; - } + ret = clk_get_bulk(dev, &phy->clk_bulk); + if (ret) + dev_err(dev, "Failed to get clocks (ret=%d)\n", ret); - phy->unipro_clk = devm_clk_get(dev, "unipro"); - if (IS_ERR(phy->unipro_clk)) { - ret = PTR_ERR(phy->unipro_clk); - dev_err(dev, "Failed to get unipro clock (ret=%d)\n", ret); - return ret; - } - - return 0; + return ret; } static const struct udevice_id mtk_ufs_phy_id_table[] = { diff --git a/drivers/phy/phy-mtk-xsphy.c b/drivers/phy/phy-mtk-xsphy.c new file mode 100644 index 00000000000..d3418ffb101 --- /dev/null +++ b/drivers/phy/phy-mtk-xsphy.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MediaTek USB3.1 gen2 xsphy Driver + * + * Copyright (c) 2026 MediaTek Inc. + * Copyright (c) 2026 BayLibre, SAS + * + * Based on Linux mtk-xsphy driver: + * Copyright (c) 2018 MediaTek Inc. + * Author: Chunfeng Yun <[email protected]> + * + * And U-Boot mtk-tphy driver: + * Copyright (c) 2015 - 2019 MediaTek Inc. + * Author: Chunfeng Yun <[email protected]> + * Ryder Lee <[email protected]> + */ + +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <malloc.h> +#include <mapmem.h> +#include <regmap.h> +#include <syscon.h> + +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include <dt-bindings/phy/phy.h> + +/* u2 phy banks */ +#define SSUSB_SIFSLV_MISC 0x000 +#define SSUSB_SIFSLV_U2FREQ 0x100 +#define SSUSB_SIFSLV_U2PHY_COM 0x300 + +/* u3 phy shared banks */ +#define SSPXTP_SIFSLV_DIG_GLB 0x000 +#define SSPXTP_SIFSLV_PHYA_GLB 0x100 + +/* u3 phy banks */ +#define SSPXTP_SIFSLV_DIG_LN_TOP 0x000 +#define SSPXTP_SIFSLV_DIG_LN_TX0 0x100 +#define SSPXTP_SIFSLV_DIG_LN_RX0 0x200 +#define SSPXTP_SIFSLV_DIG_LN_DAIF 0x300 +#define SSPXTP_SIFSLV_PHYA_LN 0x400 + +#define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00) +#define P2F_RG_FREQDET_EN BIT(24) +#define P2F_RG_CYCLECNT GENMASK(23, 0) + +#define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c) + +#define XSP_U2FREQ_FMMONR1 ((SSUSB_SIFSLV_U2FREQ) + 0x10) +#define P2F_RG_FRCK_EN BIT(8) +#define P2F_USB_FM_VALID BIT(0) + +#define XSP_USBPHYACR0 ((SSUSB_SIFSLV_U2PHY_COM) + 0x00) +#define P2A0_RG_INTR_EN BIT(5) + +#define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04) +#define P2A1_RG_INTR_CAL GENMASK(23, 19) +#define P2A1_RG_VRT_SEL GENMASK(14, 12) +#define P2A1_RG_TERM_SEL GENMASK(10, 8) + +#define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014) +#define P2A5_RG_HSTX_SRCAL_EN BIT(15) +#define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12) + +#define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018) +#define P2A6_RG_BC11_SW_EN BIT(23) +#define P2A6_RG_OTG_VBUSCMP_EN BIT(20) + +#define XSP_U2PHYDTM1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x06C) +#define P2D_FORCE_IDDIG BIT(9) +#define P2D_RG_VBUSVALID BIT(5) +#define P2D_RG_SESSEND BIT(4) +#define P2D_RG_AVALID BIT(2) +#define P2D_RG_IDDIG BIT(1) + +#define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00) +#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16) + +#define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04) +#define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0) + +#define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014) +#define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0) + +#define XSP_REF_CLK_MHZ 26 +#define XSP_SLEW_RATE_COEF 17 +#define XSP_SR_COEF_DIVISOR 1000 +#define XSP_FM_DET_CYCLE_CNT 1024 + +/* PHY switch between pcie/usb3/sgmii */ +#define USB_PHY_SWITCH_CTRL 0x0 +#define RG_PHY_SW_TYPE GENMASK(3, 0) +#define RG_PHY_SW_PCIE 0x0 +#define RG_PHY_SW_USB3 0x1 +#define RG_PHY_SW_SGMII 0x2 + +struct mtk_xsphy_instance { + void __iomem *port_base; + struct device_node *np; + struct clk ref_clk; /* reference clock of analog phy */ + u32 index; + u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; + /* only for HQA test */ + u32 efuse_intr; + u32 efuse_tx_imp; + u32 efuse_rx_imp; + /* u2 eye diagram */ + u32 eye_src; + u32 eye_vrt; + u32 eye_term; +}; + +struct mtk_xsphy { + struct udevice *dev; + void __iomem *sif_base; + struct mtk_xsphy_instance **phys; + u32 nphys; + u32 src_ref_clk_mhz; /* reference clock for slew rate calibrate */ + u32 src_coef; /* coefficient for slew rate calibrate */ +}; + +static void mtk_xsphy_u2_slew_rate_calibrate(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + u32 calib_val; + u32 fm_out; + u32 tmp; + + /* use force value */ + if (instance->eye_src) + return; + + /* enable USB ring oscillator */ + setbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); + /* wait for clock to become stable */ + udelay(1); + + /* enable free run clock */ + setbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); + + /* set cycle count as 1024 */ + clrsetbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT, + FIELD_PREP(P2F_RG_CYCLECNT, XSP_FM_DET_CYCLE_CNT)); + + /* enable frequency meter */ + setbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); + + /* ignore return value */ + readl_poll_sleep_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp, + (tmp & P2F_USB_FM_VALID), 10, 200); + + fm_out = readl(pbase + XSP_U2FREQ_MMONR0); + + /* disable frequency meter */ + clrbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); + + /* disable free run clock */ + clrbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); + + if (fm_out) { + /* (1024 / FM_OUT) x reference clock frequency x coefficient */ + tmp = xsphy->src_ref_clk_mhz * xsphy->src_coef; + tmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out; + calib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR); + } else { + /* if FM detection fail, set default value */ + calib_val = 3; + } + dev_dbg(xsphy->dev, "phy.%u, fm_out:%u, calib:%u (clk:%u, coef:%u)\n", + instance->index, fm_out, calib_val, xsphy->src_ref_clk_mhz, + xsphy->src_coef); + + /* set HS slew rate */ + clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, + FIELD_PREP(P2A5_RG_HSTX_SRCTRL, calib_val)); + + /* disable USB ring oscillator */ + clrbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); +} + +static void mtk_xsphy_u2_instance_init(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + /* DP/DM BC1.1 path Disable */ + clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_BC11_SW_EN); + + setbits_le32(pbase + XSP_USBPHYACR0, P2A0_RG_INTR_EN); +} + +static void mtk_xsphy_u2_instance_power_on(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + setbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); + + clrsetbits_le32(pbase + XSP_U2PHYDTM1, + P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, + P2D_RG_VBUSVALID | P2D_RG_AVALID); + + dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index); +} + +static void mtk_xsphy_u2_instance_power_off(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); + + clrsetbits_le32(pbase + XSP_U2PHYDTM1, + P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, + P2D_RG_SESSEND); + + dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index); +} + +static void mtk_xsphy_u2_instance_set_mode(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance, + enum phy_mode mode) +{ + u32 tmp; + + tmp = readl(instance->port_base + XSP_U2PHYDTM1); + + switch (mode) { + case PHY_MODE_USB_DEVICE: + tmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG; + break; + case PHY_MODE_USB_HOST: + tmp |= P2D_FORCE_IDDIG; + tmp &= ~P2D_RG_IDDIG; + break; + case PHY_MODE_USB_OTG: + tmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG); + break; + default: + return; + } + + writel(tmp, instance->port_base + XSP_U2PHYDTM1); +} + +static void mtk_xsphy_parse_property(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + ofnode node = np_to_ofnode(instance->np); + + switch (instance->type) { + case PHY_TYPE_USB2: + ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr); + ofnode_read_u32(node, "mediatek,eye-src", &instance->eye_src); + ofnode_read_u32(node, "mediatek,eye-vrt", &instance->eye_vrt); + ofnode_read_u32(node, "mediatek,eye-term", &instance->eye_term); + + dev_dbg(xsphy->dev, "intr:%u, src:%u, vrt:%u, term:%u\n", + instance->efuse_intr, instance->eye_src, + instance->eye_vrt, instance->eye_term); + return; + case PHY_TYPE_USB3: + ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr); + ofnode_read_u32(node, "mediatek,efuse-tx-imp", &instance->efuse_tx_imp); + ofnode_read_u32(node, "mediatek,efuse-rx-imp", &instance->efuse_rx_imp); + + dev_dbg(xsphy->dev, "intr:%u, tx-imp:%u, rx-imp:%u\n", + instance->efuse_intr, instance->efuse_tx_imp, + instance->efuse_rx_imp); + return; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do */ + return; + default: + dev_err(xsphy->dev, "incompatible PHY type\n"); + return; + } +} + +static void mtk_xsphy_u2_props_set(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + if (instance->efuse_intr) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL, + FIELD_PREP(P2A1_RG_INTR_CAL, instance->efuse_intr)); + + if (instance->eye_src) + clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, + FIELD_PREP(P2A5_RG_HSTX_SRCTRL, instance->eye_src)); + + if (instance->eye_vrt) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL, + FIELD_PREP(P2A1_RG_VRT_SEL, instance->eye_vrt)); + + if (instance->eye_term) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL, + FIELD_PREP(P2A1_RG_TERM_SEL, instance->eye_term)); +} + +static void mtk_xsphy_u3_props_set(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + if (instance->efuse_intr) + clrsetbits_le32(xsphy->sif_base + SSPXTP_PHYA_GLB_00, + RG_XTP_GLB_BIAS_INTR_CTRL, + FIELD_PREP(RG_XTP_GLB_BIAS_INTR_CTRL, instance->efuse_intr)); + + if (instance->efuse_tx_imp) + clrsetbits_le32(pbase + SSPXTP_PHYA_LN_04, RG_XTP_LN0_TX_IMPSEL, + FIELD_PREP(RG_XTP_LN0_TX_IMPSEL, instance->efuse_tx_imp)); + + if (instance->efuse_rx_imp) + clrsetbits_le32(pbase + SSPXTP_PHYA_LN_14, RG_XTP_LN0_RX_IMPSEL, + FIELD_PREP(RG_XTP_LN0_RX_IMPSEL, instance->efuse_rx_imp)); +} + +/* type switch for usb3/pcie/sgmii */ +static int mtk_xsphy_type_syscon_get(struct udevice *dev, + struct mtk_xsphy_instance *instance, + ofnode dn) +{ + struct ofnode_phandle_args args; + int ret; + + if (!ofnode_read_bool(dn, "mediatek,syscon-type")) + return 0; + + ret = ofnode_parse_phandle_with_args(dn, "mediatek,syscon-type", + NULL, 2, 0, &args); + if (ret) + return ret; + + instance->type_sw_reg = args.args[0]; + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ + instance->type_sw = syscon_node_to_regmap(args.node); + if (IS_ERR(instance->type_sw)) + return PTR_ERR(instance->type_sw); + + dev_dbg(dev, "phy-%s.%d: type_sw - reg %#x, index %d\n", + dev->name, instance->index, instance->type_sw_reg, + instance->type_sw_index); + + return 0; +} + +static int mtk_xsphy_type_set(struct mtk_xsphy_instance *instance) +{ + int type; + u32 offset; + + if (!instance->type_sw) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB3: + type = RG_PHY_SW_USB3; + break; + case PHY_TYPE_PCIE: + type = RG_PHY_SW_PCIE; + break; + case PHY_TYPE_SGMII: + type = RG_PHY_SW_SGMII; + break; + case PHY_TYPE_USB2: + default: + return 0; + } + + offset = instance->type_sw_index * BITS_PER_BYTE; + regmap_update_bits(instance->type_sw, instance->type_sw_reg, + RG_PHY_SW_TYPE << offset, type << offset); + + return 0; +} + +static int mtk_xsphy_init(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + int ret; + + ret = clk_enable(&instance->ref_clk); + if (ret) { + dev_err(xsphy->dev, "failed to enable ref_clk\n"); + return ret; + } + + switch (instance->type) { + case PHY_TYPE_USB2: + mtk_xsphy_u2_instance_init(xsphy, instance); + mtk_xsphy_u2_props_set(xsphy, instance); + break; + case PHY_TYPE_USB3: + mtk_xsphy_u3_props_set(xsphy, instance); + break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do, only used to set type */ + break; + default: + dev_err(xsphy->dev, "incompatible PHY type\n"); + clk_disable(&instance->ref_clk); + return -EINVAL; + } + + return 0; +} + +static int mtk_xsphy_power_on(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) { + mtk_xsphy_u2_instance_power_on(xsphy, instance); + mtk_xsphy_u2_slew_rate_calibrate(xsphy, instance); + } + + return 0; +} + +static int mtk_xsphy_power_off(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) + mtk_xsphy_u2_instance_power_off(xsphy, instance); + + return 0; +} + +static int mtk_xsphy_exit(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + clk_disable(&instance->ref_clk); + + return 0; +} + +static int mtk_xsphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) + mtk_xsphy_u2_instance_set_mode(xsphy, instance, mode); + + return 0; +} + +static int mtk_xsphy_xlate(struct phy *phy, struct ofnode_phandle_args *args) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = NULL; + const struct device_node *phy_np = ofnode_to_np(args->node); + u32 index; + + if (!phy_np) { + dev_err(phy->dev, "null pointer phy node\n"); + return -EINVAL; + } + + if (args->args_count != 2) { + dev_err(phy->dev, "invalid number of cells in 'phy' property\n"); + return -EINVAL; + } + + for (index = 0; index < xsphy->nphys; index++) + if (phy_np == xsphy->phys[index]->np) { + instance = xsphy->phys[index]; + break; + } + + if (!instance) { + dev_err(phy->dev, "failed to find appropriate phy\n"); + return -EINVAL; + } + + phy->id = index; + instance->type = args->args[1]; + if (!(instance->type == PHY_TYPE_USB2 || + instance->type == PHY_TYPE_USB3 || + instance->type == PHY_TYPE_PCIE || + instance->type == PHY_TYPE_SGMII)) { + dev_err(phy->dev, "unsupported PHY type\n"); + return -EINVAL; + } + + mtk_xsphy_parse_property(xsphy, instance); + mtk_xsphy_type_set(instance); + + return 0; +} + +static const struct phy_ops mtk_xsphy_ops = { + .init = mtk_xsphy_init, + .exit = mtk_xsphy_exit, + .power_on = mtk_xsphy_power_on, + .power_off = mtk_xsphy_power_off, + .set_mode = mtk_xsphy_set_mode, + .of_xlate = mtk_xsphy_xlate, +}; + +static int mtk_xsphy_probe(struct udevice *dev) +{ + struct mtk_xsphy *xsphy = dev_get_priv(dev); + fdt_addr_t sif_addr; + ofnode subnode; + int index = 0; + + xsphy->nphys = dev_get_child_count(dev); + + xsphy->phys = devm_kcalloc(dev, xsphy->nphys, sizeof(*xsphy->phys), + GFP_KERNEL); + if (!xsphy->phys) + return -ENOMEM; + + xsphy->dev = dev; + + sif_addr = ofnode_get_addr(dev_ofnode(dev)); + /* optional, may not exist if no u3 phys */ + if (sif_addr != FDT_ADDR_T_NONE) + xsphy->sif_base = map_sysmem(sif_addr, 0); + + xsphy->src_ref_clk_mhz = XSP_REF_CLK_MHZ; + xsphy->src_coef = XSP_SLEW_RATE_COEF; + /* update parameters of slew rate calibrate if exist */ + ofnode_read_u32(dev_ofnode(dev), "mediatek,src-ref-clk-mhz", + &xsphy->src_ref_clk_mhz); + ofnode_read_u32(dev_ofnode(dev), "mediatek,src-coef", &xsphy->src_coef); + + dev_for_each_subnode(subnode, dev) { + struct mtk_xsphy_instance *inst; + fdt_addr_t addr; + int ret; + + inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + xsphy->phys[index] = inst; + + addr = ofnode_get_addr(subnode); + if (addr == FDT_ADDR_T_NONE) + return -EADDRNOTAVAIL; + + inst->port_base = map_sysmem(addr, 0); + inst->index = index; + inst->np = ofnode_to_np(subnode); + + ret = clk_get_by_name_nodev(subnode, "ref", &inst->ref_clk); + if (ret) { + dev_err(dev, "failed to get ref_clk(id-%d)\n", index); + return ret; + } + + ret = mtk_xsphy_type_syscon_get(dev, inst, subnode); + if (ret) + return ret; + + index++; + } + + return 0; +} + +static const struct udevice_id mtk_xsphy_id_table[] = { + { .compatible = "mediatek,xsphy" }, + { } +}; + +U_BOOT_DRIVER(mtk_xsphy) = { + .name = "mtk-xsphy", + .id = UCLASS_PHY, + .of_match = mtk_xsphy_id_table, + .ops = &mtk_xsphy_ops, + .probe = mtk_xsphy_probe, + .priv_auto = sizeof(struct mtk_xsphy), +}; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c index 8875c276f36..5219b147797 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -106,7 +106,7 @@ static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = { PIN_FIELD_BASE(9, 9, 5, 0x20, 0x10, 9, 1), PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1), - PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(11, 11, 5, 0x20, 0x10, 10, 1), PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1), PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1), @@ -215,7 +215,7 @@ static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = { PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1), PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1), PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1), - PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 7, 0x70, 0x10, 8, 1), PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1), PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1), PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1), @@ -279,8 +279,8 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3), - PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1), - PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 3), PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3), PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3), PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3), @@ -288,9 +288,9 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(9, 9, 5, 0x00, 0x10, 27, 3), PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3), - PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(11, 11, 5, 0x10, 0x10, 0, 3), PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3), - PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(13, 13, 5, 0x10, 0x10, 3, 3), PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3), @@ -302,7 +302,7 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3), PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3), PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3), - PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(23, 23, 2, 0x10, 0x10, 0, 3), PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3), PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3), @@ -368,7 +368,7 @@ static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = { PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1), PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1), PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1), - PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(20, 20, 2, 0x30, 0x10, 3, 1), PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1), PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1), PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1), diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index b97cd443c60..4abc73013eb 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -71,6 +71,11 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_EG_LR, }, { + .id = 0x0468A093, + .device = 1, + .variants = ZYNQMP_VARIANT_EG_LR, + }, + { .id = 0x04711093, .device = 2, .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, @@ -209,6 +214,16 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR, }, { + .id = 0x047F9093, + .device = 58, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FC093, + .device = 59, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x046d0093, .device = 67, .variants = ZYNQMP_VARIANT_DR, @@ -219,6 +234,36 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR_SE, }, { + .id = 0x046D1093, + .device = 65, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D2093, + .device = 55, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D3093, + .device = 57, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D4093, + .device = 42, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D5093, + .device = 63, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D6093, + .device = 64, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x04712093, .device = 24, .variants = 0, diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c index e860d765eea..268627d5863 100644 --- a/drivers/ufs/ufs-mediatek.c +++ b/drivers/ufs/ufs-mediatek.c @@ -182,19 +182,15 @@ static int ufs_mtk_bind_mphy(struct ufs_hba *hba) struct ufs_mtk_host *host = dev_get_priv(hba->dev); int err = 0; - err = generic_phy_get_by_index(hba->dev, 0, host->mphy); + err = generic_phy_get_by_index(hba->dev, 0, &host->mphy); - if (IS_ERR(host->mphy)) { - err = PTR_ERR(host->mphy); - if (err != -ENODEV) { - dev_info(hba->dev, "%s: Could NOT get a valid PHY %d\n", __func__, - err); - } + if (err) { + if (err == -ENOENT) + return 0; /* no PHY, nothing to do */ + dev_err(hba->dev, "Failed to get PHY: %d.\n", err); + return err; } - if (err) - host->mphy = NULL; - return err; } @@ -321,19 +317,35 @@ static int ufs_mtk_init(struct ufs_hba *hba) ufs_mtk_init_reset(hba); - // TODO: Clocking + err = clk_get_bulk(hba->dev, &priv->clks); + if (err) { + dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err); + return err; + } + + err = clk_enable_bulk(&priv->clks); + if (err) { + dev_err(hba->dev, "failed to enable clocks, err:%d\n", err); + goto err_clk_enable; + } - err = generic_phy_power_on(priv->mphy); + err = generic_phy_power_on(&priv->mphy); if (err) { dev_err(hba->dev, "%s: phy init failed, err = %d\n", __func__, err); - return err; + goto err_phy_power_on; } ufs_mtk_setup_ref_clk(hba, true); ufs_mtk_get_hw_ip_version(hba); return 0; + +err_phy_power_on: + clk_disable_bulk(&priv->clks); +err_clk_enable: + clk_release_bulk(&priv->clks); + return err; } static int ufs_mtk_device_reset(struct ufs_hba *hba) @@ -383,7 +395,9 @@ static int ufs_mtk_probe(struct udevice *dev) static const struct udevice_id ufs_mtk_ids[] = { { .compatible = "mediatek,mt6878-ufshci" }, - {}, + { .compatible = "mediatek,mt8183-ufshci" }, + { .compatible = "mediatek,mt8195-ufshci" }, + { } }; U_BOOT_DRIVER(mediatek_ufshci) = { diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h index 11a83d34c5b..0ffd0483eff 100644 --- a/drivers/ufs/ufs-mediatek.h +++ b/drivers/ufs/ufs-mediatek.h @@ -154,7 +154,7 @@ struct ufs_mtk_mcq_intr_info { }; struct ufs_mtk_host { - struct phy *mphy; + struct phy mphy; struct reset_ctl *unipro_reset; struct reset_ctl *crypto_reset; struct reset_ctl *hci_reset; diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 984768ea156..dbc3018d716 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_$(PHASE_)PANEL) += panel-uclass.o obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o obj-$(CONFIG_$(PHASE_)SIMPLE_PANEL) += simple_panel.o -obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o +obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.bmp.o obj-$(CONFIG_$(PHASE_)BMP) += bmp.o endif diff --git a/drivers/video/fonts/Makefile b/drivers/video/fonts/Makefile index 1111f92a2c6..4d32fa43994 100644 --- a/drivers/video/fonts/Makefile +++ b/drivers/video/fonts/Makefile @@ -3,8 +3,8 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, [email protected]. -obj-$(CONFIG_CONSOLE_TRUETYPE_NIMBUS) += nimbus_sans_l_regular.o -obj-$(CONFIG_CONSOLE_TRUETYPE_ANKACODER) += ankacoder_c75_r.o -obj-$(CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT) += rufscript010.o -obj-$(CONFIG_CONSOLE_TRUETYPE_CANTORAONE) += cantoraone_regular.o -obj-$(CONFIG_CONSOLE_TRUETYPE_DEJAVU) += dejavu_mono.o +obj-$(CONFIG_CONSOLE_TRUETYPE_NIMBUS) += nimbus_sans_l_regular.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_ANKACODER) += ankacoder_c75_r.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT) += rufscript010.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_CANTORAONE) += cantoraone_regular.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_DEJAVU) += dejavu_mono.ttf.o diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 1cd737aca24..62afe609ec0 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -354,7 +354,7 @@ static int virtio_mmio_probe(struct udevice *udev) magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE); if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) { debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic); - return 0; + return -ENODEV; } /* Check device version */ @@ -362,7 +362,7 @@ static int virtio_mmio_probe(struct udevice *udev) if (priv->version < 1 || priv->version > 2) { debug("(%s): version %d not supported!\n", udev->name, priv->version); - return 0; + return -ENXIO; } /* Check device ID */ @@ -372,7 +372,7 @@ static int virtio_mmio_probe(struct udevice *udev) * virtio-mmio device with an ID 0 is a (dummy) placeholder * with no function. End probing now with no error reported. */ - return 0; + return -ENODEV; } uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID); |
