From d4a489c1b21cba778600b441b59c8bcf2a879388 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:27 +0200 Subject: phy: phy-mtk-tphy: add support for phy type switch Add support for PHY type switch via the mediatek topmisc syscon. This is needed on mt7981 to make the PCIe correctly work and display LinkUp. Follow the same implementation done on Linux kernel with the usage of the mediatek,syscon-type property. Example: u3port0: usb-phy@11e10700 { reg = <0x11e10700 0x900>; clocks = <&topckgen CK_TOP_USB3_PHY_SEL>; clock-names = "ref"; #phy-cells = <1>; mediatek,syscon-type = <&topmisc 0x218 0>; status = "okay"; }; Signed-off-by: Christian Marangi --- drivers/phy/Kconfig | 2 ++ drivers/phy/phy-mtk-tphy.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8f767877e73..e12347e8a03 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -263,6 +263,8 @@ config PHY_MTK_TPHY bool "MediaTek T-PHY Driver" depends on PHY depends on ARCH_MEDIATEK || SOC_MT7621 + select REGMAP + select SYSCON help MediaTek T-PHY driver supports usb2.0, usb3.0 ports, PCIe and SATA, and meanwhile supports two version T-PHY which have diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c index 6f9ac1528e8..0a45dc58629 100644 --- a/drivers/phy/phy-mtk-tphy.c +++ b/drivers/phy/phy-mtk-tphy.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -215,6 +217,14 @@ #define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) +/* PHY switch between pcie/usb3/sgmii/sata */ +#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 +#define RG_PHY_SW_SATA 0x3 + enum mtk_phy_version { MTK_TPHY_V1 = 1, MTK_TPHY_V2, @@ -257,6 +267,10 @@ struct mtk_phy_instance { u32 index; u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; + u32 eye_vrt; u32 eye_term; u32 discth; @@ -616,6 +630,67 @@ static void u2_phy_props_set(struct mtk_tphy *tphy, FIELD_PREP(PA6_RG_U2_PRE_EMP, instance->pre_emphasis)); } +/* type switch for usb3/pcie/sgmii/sata */ +static int phy_type_syscon_get(struct udevice *dev, struct mtk_phy_instance *instance, + ofnode dn) +{ + struct ofnode_phandle_args args; + int err; + + if (!ofnode_read_bool(dn, "mediatek,syscon-type")) + return 0; + + err = ofnode_parse_phandle_with_args(dn, "mediatek,syscon-type", + NULL, 2, 0, &args); + if (err) + return err; + + 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); + + debug("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 phy_type_set(struct mtk_phy_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_SATA: + type = RG_PHY_SW_SATA; + 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_phy_init(struct phy *phy) { struct mtk_tphy *tphy = dev_get_priv(phy->dev); @@ -746,6 +821,7 @@ static int mtk_phy_xlate(struct phy *phy, } phy_parse_property(tphy, instance); + phy_type_set(instance); return 0; } @@ -807,6 +883,10 @@ static int mtk_tphy_probe(struct udevice *dev) &instance->da_ref_clk); if (err) return err; + + err = phy_type_syscon_get(dev, instance, subnode); + if (err) + return err; } return 0; -- cgit v1.2.3 From 1a75300d94387598fff4e53abe36c25d16a105ae Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 24 Jun 2024 23:03:28 +0200 Subject: pci: mediatek: add PCIe controller support for filogic silicon Add MediaTek GEN3 PCIe controller support for filogic silicon. This is adapted from the Linux version of the driver. Signed-off-by: John Crispin [ fix minor problems, fix checkpatch errors ] Signed-off-by: Christian Marangi --- drivers/pci/Kconfig | 7 + drivers/pci/Makefile | 1 + drivers/pci/pcie_mediatek_gen3.c | 382 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 390 insertions(+) create mode 100644 drivers/pci/pcie_mediatek_gen3.c diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8d02ab82ad9..22a56f4ca38 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -350,6 +350,13 @@ config PCIE_MEDIATEK Say Y here if you want to enable Gen2 PCIe controller, which could be found on MT7623 SoC family. +config PCIE_MEDIATEK_GEN3 + bool "MediaTek PCIe Gen3 controller" + depends on ARCH_MEDIATEK + help + Say Y here if you want to enable Gen3 PCIe controller, + which could be found on the Mediatek Filogic SoC family. + config PCIE_DW_MESON bool "Amlogic Meson DesignWare based PCIe controller" depends on ARCH_MESON diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 2927c519129..5b2d2969802 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o +obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie_mediatek_gen3.o obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o obj-$(CONFIG_PCIE_DW_MESON) += pcie_dw_meson.o diff --git a/drivers/pci/pcie_mediatek_gen3.c b/drivers/pci/pcie_mediatek_gen3.c new file mode 100644 index 00000000000..673813b8b75 --- /dev/null +++ b/drivers/pci/pcie_mediatek_gen3.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek PCIe host controller driver. + * + * Copyright (c) 2023 John Crispin + * Driver is based on u-boot gen1/2 and upstream linux gen3 code + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pci_internal.h" + +/* PCIe shared registers */ +#define PCIE_CFG_ADDR 0x20 +#define PCIE_CFG_DATA 0x24 + +#define PCIE_SETTING_REG 0x80 + +#define PCIE_PCI_IDS_1 0x9c +#define PCIE_RC_MODE BIT(0) +#define PCI_CLASS(class) ((class) << 8) + +#define PCIE_CFGNUM_REG 0x140 +#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0)) +#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8)) +#define PCIE_CFG_BYTE_EN(bytes) (((bytes) << 16) & GENMASK(19, 16)) +#define PCIE_CFG_FORCE_BYTE_EN BIT(20) +#define PCIE_CFG_OFFSET_ADDR 0x1000 +#define PCIE_CFG_HEADER(bus, devfn) (PCIE_CFG_BUS(bus) | PCIE_CFG_DEVFN(devfn)) + +#define PCIE_RST_CTRL_REG 0x148 +#define PCIE_MAC_RSTB BIT(0) +#define PCIE_PHY_RSTB BIT(1) +#define PCIE_BRG_RSTB BIT(2) +#define PCIE_PE_RSTB BIT(3) + +#define PCIE_LINK_STATUS_REG 0x154 +#define PCIE_PORT_LINKUP BIT(8) + +#define PCIE_INT_ENABLE_REG 0x180 + +#define PCIE_MISC_CTRL_REG 0x348 +#define PCIE_DISABLE_DVFSRC_VLT_REQ BIT(1) + +#define PCIE_TRANS_TABLE_BASE_REG 0x800 +#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4 +#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8 +#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc +#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10 +#define PCIE_ATR_TLB_SET_OFFSET 0x20 + +#define PCIE_MAX_TRANS_TABLES 8 +#define PCIE_ATR_EN BIT(0) +#define PCIE_ATR_SIZE(size) \ + (((((size) - 1) << 1) & GENMASK(6, 1)) | PCIE_ATR_EN) +#define PCIE_ATR_ID(id) ((id) & GENMASK(3, 0)) +#define PCIE_ATR_TYPE_MEM PCIE_ATR_ID(0) +#define PCIE_ATR_TYPE_IO PCIE_ATR_ID(1) +#define PCIE_ATR_TLP_TYPE(type) (((type) << 16) & GENMASK(18, 16)) +#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0) +#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2) + +struct mtk_pcie { + void __iomem *base; + void *priv; + struct clk pl_250m_ck; + struct clk tl_26m_ck; + struct clk peri_26m_ck; + struct clk top_133m_ck; + struct reset_ctl reset_phy; + struct reset_ctl reset_mac; + struct phy phy; +}; + +static void mtk_pcie_config_tlp_header(const struct udevice *bus, + pci_dev_t devfn, + int where, int size) +{ + struct mtk_pcie *pcie = dev_get_priv(bus); + int bytes; + u32 val; + + size = 1 << size; + bytes = (GENMASK(size - 1, 0) & 0xf) << (where & 0x3); + + val = PCIE_CFG_FORCE_BYTE_EN | PCIE_CFG_BYTE_EN(bytes) | + PCIE_CFG_HEADER(PCI_BUS(devfn), (devfn >> 8)); + + writel(val, pcie->base + PCIE_CFGNUM_REG); +} + +static int mtk_pcie_config_address(const struct udevice *udev, pci_dev_t bdf, + uint offset, void **paddress) +{ + struct mtk_pcie *pcie = dev_get_priv(udev); + + *paddress = pcie->base + PCIE_CFG_OFFSET_ADDR + offset; + + return 0; +} + +static int mtk_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + int ret; + + mtk_pcie_config_tlp_header(bus, bdf, offset, size); + ret = pci_generic_mmap_read_config(bus, mtk_pcie_config_address, + bdf, offset, valuep, size); + return ret; +} + +static int mtk_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + mtk_pcie_config_tlp_header(bus, bdf, offset, size); + + switch (size) { + case PCI_SIZE_8: + case PCI_SIZE_16: + value <<= (offset & 0x3) * 8; + case PCI_SIZE_32: + break; + default: + return -EINVAL; + } + + return pci_generic_mmap_write_config(bus, mtk_pcie_config_address, + bdf, (offset & ~0x3), value, PCI_SIZE_32); +} + +static const struct dm_pci_ops mtk_pcie_ops = { + .read_config = mtk_pcie_read_config, + .write_config = mtk_pcie_write_config, +}; + +static int mtk_pcie_set_trans_table(struct udevice *dev, struct mtk_pcie *pcie, + u64 cpu_addr, u64 pci_addr, u64 size, + unsigned long type, int num) +{ + void __iomem *table; + u32 val; + + if (num >= PCIE_MAX_TRANS_TABLES) { + dev_err(dev, "not enough translate table for addr: %#llx, limited to [%d]\n", + (unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES); + return -ENODEV; + } + + dev_dbg(dev, "set trans table %d: %#llx %#llx, %#llx\n", num, cpu_addr, + pci_addr, size); + table = pcie->base + PCIE_TRANS_TABLE_BASE_REG + + num * PCIE_ATR_TLB_SET_OFFSET; + + writel(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(size) - 1), table); + writel(upper_32_bits(cpu_addr), table + PCIE_ATR_SRC_ADDR_MSB_OFFSET); + writel(lower_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET); + writel(upper_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET); + + if (type == PCI_REGION_IO) + val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO; + else + val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM; + writel(val, table + PCIE_ATR_TRSL_PARAM_OFFSET); + + return 0; +} + +static int mtk_pcie_startup_port(struct udevice *dev) +{ + struct mtk_pcie *pcie = dev_get_priv(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + u32 val; + int i, err; + + /* Set as RC mode */ + val = readl(pcie->base + PCIE_SETTING_REG); + val |= PCIE_RC_MODE; + writel(val, pcie->base + PCIE_SETTING_REG); + + /* setup RC BARs */ + writel(PCI_BASE_ADDRESS_MEM_TYPE_64, + pcie->base + PCI_BASE_ADDRESS_0); + writel(0x0, pcie->base + PCI_BASE_ADDRESS_1); + + /* setup interrupt pins */ + clrsetbits_le32(pcie->base + PCI_INTERRUPT_LINE, + 0xff00, 0x100); + + /* setup bus numbers */ + clrsetbits_le32(pcie->base + PCI_PRIMARY_BUS, + 0xffffff, 0x00ff0100); + + /* setup command register */ + clrsetbits_le32(pcie->base + PCI_PRIMARY_BUS, + 0xffff, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SERR); + + /* Set class code */ + val = readl(pcie->base + PCIE_PCI_IDS_1); + val &= ~GENMASK(31, 8); + val |= PCI_CLASS(PCI_CLASS_BRIDGE_PCI << 8); + writel(val, pcie->base + PCIE_PCI_IDS_1); + + /* Mask all INTx interrupts */ + val = readl(pcie->base + PCIE_INT_ENABLE_REG); + val &= ~0xFF000000; + writel(val, pcie->base + PCIE_INT_ENABLE_REG); + + /* Disable DVFSRC voltage request */ + val = readl(pcie->base + PCIE_MISC_CTRL_REG); + val |= PCIE_DISABLE_DVFSRC_VLT_REQ; + writel(val, pcie->base + PCIE_MISC_CTRL_REG); + + /* Assert all reset signals */ + val = readl(pcie->base + PCIE_RST_CTRL_REG); + val |= PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB | PCIE_PE_RSTB; + writel(val, pcie->base + PCIE_RST_CTRL_REG); + + /* + * Described in PCIe CEM specification sections 2.2 (PERST# Signal) + * and 2.2.1 (Initial Power-Up (G3 to S0)). + * The deassertion of PERST# should be delayed 100ms (TPVPERL) + * for the power and clock to become stable. + */ + mdelay(100); + + /* De-assert reset signals */ + val &= ~(PCIE_MAC_RSTB | PCIE_PHY_RSTB | PCIE_BRG_RSTB); + writel(val, pcie->base + PCIE_RST_CTRL_REG); + + mdelay(100); + + /* De-assert PERST# signals */ + val &= ~(PCIE_PE_RSTB); + writel(val, pcie->base + PCIE_RST_CTRL_REG); + + /* 100ms timeout value should be enough for Gen1/2 training */ + err = readl_poll_timeout(pcie->base + PCIE_LINK_STATUS_REG, val, + !!(val & PCIE_PORT_LINKUP), + 100 * 1000); + if (err) { + dev_dbg(dev, "no card detected\n"); + return -ETIMEDOUT; + } + dev_dbg(dev, "detected a card\n"); + + for (i = 0; i < hose->region_count; i++) { + struct pci_region *reg = &hose->regions[i]; + + if (reg->flags != PCI_REGION_MEM) + continue; + + mtk_pcie_set_trans_table(dev, pcie, reg->bus_start, reg->phys_start, + reg->size, reg->flags, 0); + } + + return 0; +} + +static int mtk_pcie_power_on(struct udevice *dev) +{ + struct mtk_pcie *pcie = dev_get_priv(dev); + int err; + + pcie->base = dev_remap_addr_name(dev, "pcie-mac"); + if (!pcie->base) + return -ENOENT; + + pcie->priv = dev; + + err = generic_phy_get_by_name(dev, "pcie-phy", &pcie->phy); + if (err) + return err; + + /* + * Upstream linux kernel devine these clock without clock-names + * and use clk bulk API to enable them all. + */ + err = clk_get_by_index(dev, 0, &pcie->pl_250m_ck); + if (err) + return err; + + err = clk_get_by_index(dev, 1, &pcie->tl_26m_ck); + if (err) + return err; + + err = clk_get_by_index(dev, 2, &pcie->peri_26m_ck); + if (err) + return err; + + err = clk_get_by_index(dev, 3, &pcie->top_133m_ck); + if (err) + return err; + + err = generic_phy_init(&pcie->phy); + if (err) + return err; + + err = generic_phy_power_on(&pcie->phy); + if (err) + goto err_phy_on; + + err = clk_enable(&pcie->pl_250m_ck); + if (err) + goto err_clk_pl_250m; + + err = clk_enable(&pcie->tl_26m_ck); + if (err) + goto err_clk_tl_26m; + + err = clk_enable(&pcie->peri_26m_ck); + if (err) + goto err_clk_peri_26m; + + err = clk_enable(&pcie->top_133m_ck); + if (err) + goto err_clk_top_133m; + + err = mtk_pcie_startup_port(dev); + if (err) + goto err_startup; + + return 0; + +err_startup: +err_clk_top_133m: + clk_disable(&pcie->top_133m_ck); +err_clk_peri_26m: + clk_disable(&pcie->peri_26m_ck); +err_clk_tl_26m: + clk_disable(&pcie->tl_26m_ck); +err_clk_pl_250m: + clk_disable(&pcie->pl_250m_ck); +err_phy_on: + generic_phy_exit(&pcie->phy); + + return err; +} + +static int mtk_pcie_probe(struct udevice *dev) +{ + struct mtk_pcie *pcie = dev_get_priv(dev); + int err; + + pcie->priv = dev; + + err = mtk_pcie_power_on(dev); + if (err) + return err; + + return 0; +} + +static const struct udevice_id mtk_pcie_ids[] = { + { .compatible = "mediatek,mt8192-pcie" }, + { } +}; + +U_BOOT_DRIVER(pcie_mediatek_gen3) = { + .name = "pcie_mediatek_gen3", + .id = UCLASS_PCI, + .of_match = mtk_pcie_ids, + .ops = &mtk_pcie_ops, + .probe = mtk_pcie_probe, + .priv_auto = sizeof(struct mtk_pcie), +}; -- cgit v1.2.3 From 6f0e7663ef757f555f9d1f8bf17d606653881296 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:29 +0200 Subject: spi: mtk_spim: add support for upstream mediatek, spi-ipm compatible Upstream kernel linux use a different compatible mediatek,spi-ipm. Add support for this compatible and add handling for the additional clock similar to how it's done by the upstream driver and handling for all the property enabled by default. Signed-off-by: Christian Marangi --- drivers/spi/mtk_spim.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/spi/mtk_spim.c b/drivers/spi/mtk_spim.c index 90f4c3cecb9..b360eca2b91 100644 --- a/drivers/spi/mtk_spim.c +++ b/drivers/spi/mtk_spim.c @@ -137,6 +137,8 @@ struct mtk_spim_capability { * @state: Controller state * @sel_clk: Pad clock * @spi_clk: Core clock + * @parent_clk: Parent clock (needed for mediatek,spi-ipm, upstream DTSI) + * @hclk: HCLK clock (needed for mediatek,spi-ipm, upstream DTSI) * @pll_clk_rate: Controller's PLL source clock rate, which is different * from SPI bus clock rate * @xfer_len: Current length of data for transfer @@ -151,6 +153,7 @@ struct mtk_spim_priv { void __iomem *base; u32 state; struct clk sel_clk, spi_clk; + struct clk parent_clk, hclk; u32 pll_clk_rate; u32 xfer_len; struct mtk_spim_capability hw_cap; @@ -650,7 +653,21 @@ static int mtk_spim_probe(struct udevice *dev) if (!priv->base) return -EINVAL; - mtk_spim_get_attr(priv, dev); + /* + * Upstream linux driver for ipm design enable all the modes + * and setup the calibrarion values directly in the driver with + * standard values. + */ + if (device_is_compatible(dev, "mediatek,spi-ipm")) { + priv->hw_cap.enhance_timing = true; + priv->hw_cap.dma_ext = true; + priv->hw_cap.ipm_design = true; + priv->hw_cap.support_quad = true; + priv->sample_sel = 0; + priv->tick_dly = 2; + } else { + mtk_spim_get_attr(priv, dev); + } ret = clk_get_by_name(dev, "sel-clk", &priv->sel_clk); if (ret < 0) { @@ -664,8 +681,31 @@ static int mtk_spim_probe(struct udevice *dev) return ret; } - clk_enable(&priv->sel_clk); + /* + * Upstream DTSI use a different compatible that provide additional + * clock instead of the assigned-clock implementation. + */ + if (device_is_compatible(dev, "mediatek,spi-ipm")) { + ret = clk_get_by_name(dev, "parent-clk", &priv->parent_clk); + if (ret < 0) { + dev_err(dev, "failed to get parent-clk\n"); + return ret; + } + + ret = clk_get_by_name(dev, "hclk", &priv->hclk); + if (ret < 0) { + dev_err(dev, "failed to get hclk\n"); + return ret; + } + + clk_enable(&priv->parent_clk); + clk_set_parent(&priv->sel_clk, &priv->parent_clk); + + clk_enable(&priv->hclk); + } + clk_enable(&priv->spi_clk); + clk_enable(&priv->sel_clk); priv->pll_clk_rate = clk_get_rate(&priv->spi_clk); if (priv->pll_clk_rate == 0) @@ -698,6 +738,7 @@ static const struct dm_spi_ops mtk_spim_ops = { static const struct udevice_id mtk_spim_ids[] = { { .compatible = "mediatek,ipm-spi" }, + { .compatible = "mediatek,spi-ipm", }, {} }; -- cgit v1.2.3 From 1223e5bb17b15ffb4587de8aa6ed2b6ac051734f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:30 +0200 Subject: net: mediatek: handle alternative name for pn_swap property Handle alternative name for pn_swap property as upstream linux use mediatek,pnswap. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 94f17a97fe0..5098afef8a8 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -1964,7 +1964,9 @@ static int mtk_eth_of_to_plat(struct udevice *dev) return -ENODEV; } - priv->pn_swap = ofnode_read_bool(args.node, "pn_swap"); + /* Upstream linux use mediatek,pnswap instead of pn_swap */ + priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") || + ofnode_read_bool(args.node, "mediatek,pnswap"); } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) { /* get corresponding usxgmii phandle */ ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys", -- cgit v1.2.3 From 72d01e4345ef0d2baa420505dc93c3803d0fee27 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:31 +0200 Subject: i2c: mediatek: add support for optional arb and pmic clock Add support for optional arb and pmic clock for i2c provided in upstream linux DTSI. Signed-off-by: Christian Marangi Reviewed-by: Heiko Schocher --- drivers/i2c/mtk_i2c.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/i2c/mtk_i2c.c b/drivers/i2c/mtk_i2c.c index 5592fe91817..3450177741a 100644 --- a/drivers/i2c/mtk_i2c.c +++ b/drivers/i2c/mtk_i2c.c @@ -221,6 +221,8 @@ struct mtk_i2c_priv { void __iomem *pdmabase; /* dma base address*/ struct clk clk_main; /* main clock for i2c bus */ struct clk clk_dma; /* DMA clock for i2c via DMA */ + struct clk clk_arb; /* DMA clock for i2c ARB */ + struct clk clk_pmic; /* DMA clock for i2c PMIC */ const struct mtk_i2c_soc_data *soc_data; /* Compatible data for different IC */ int op; /* operation mode */ bool zero_len; /* Only transfer slave address, no data */ @@ -255,6 +257,18 @@ static int mtk_i2c_clk_enable(struct mtk_i2c_priv *priv) if (ret) return log_msg_ret("enable clk_dma", ret); + if (priv->clk_arb.dev) { + ret = clk_enable(&priv->clk_arb); + if (ret) + return log_msg_ret("enable clk_arb", ret); + } + + if (priv->clk_pmic.dev) { + ret = clk_enable(&priv->clk_pmic); + if (ret) + return log_msg_ret("enable clk_pmic", ret); + } + return 0; } @@ -262,6 +276,18 @@ static int mtk_i2c_clk_disable(struct mtk_i2c_priv *priv) { int ret; + if (priv->clk_pmic.dev) { + ret = clk_disable(&priv->clk_pmic); + if (ret) + return log_msg_ret("disable clk_pmic", ret); + } + + if (priv->clk_arb.dev) { + ret = clk_disable(&priv->clk_arb); + if (ret) + return log_msg_ret("disable clk_arb", ret); + } + ret = clk_disable(&priv->clk_dma); if (ret) return log_msg_ret("disable clk_dma", ret); @@ -748,6 +774,10 @@ static int mtk_i2c_of_to_plat(struct udevice *dev) ret = clk_get_by_index(dev, 1, &priv->clk_dma); + /* optional i2c clock */ + clk_get_by_name(dev, "arb", &priv->clk_arb); + clk_get_by_name(dev, "pmic", &priv->clk_pmic); + return ret; } -- cgit v1.2.3 From 41d2cab1fcecfda40cbcc4add57761b1050dfa99 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:32 +0200 Subject: serial: mediatek: add support for bus clock and enable it Upstream linux also provide the additional optional bus clock. Add support for it and also enable the baud and bus clock on probe. Signed-off-by: Christian Marangi --- drivers/serial/serial_mtk.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c index 3f569c68f22..78e8d9dc735 100644 --- a/drivers/serial/serial_mtk.c +++ b/drivers/serial/serial_mtk.c @@ -76,6 +76,7 @@ struct mtk_serial_regs { * driver * @regs: Register base of the serial port * @clk: The baud clock device + * @clk_bus: The bus clock device * @fixed_clk_rate: Fallback fixed baud clock rate if baud clock * device is not specified * @force_highspeed: Force using high-speed mode @@ -83,6 +84,7 @@ struct mtk_serial_regs { struct mtk_serial_priv { struct mtk_serial_regs __iomem *regs; struct clk clk; + struct clk clk_bus; u32 fixed_clk_rate; bool force_highspeed; }; @@ -220,6 +222,10 @@ static int mtk_serial_probe(struct udevice *dev) writel(UART_MCRVAL, &priv->regs->mcr); writel(UART_FCRVAL, &priv->regs->fcr); + clk_enable(&priv->clk); + if (priv->clk_bus.dev) + clk_enable(&priv->clk_bus); + return 0; } @@ -250,6 +256,8 @@ static int mtk_serial_of_to_plat(struct udevice *dev) } } + clk_get_by_name(dev, "bus", &priv->clk_bus); + priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed"); return 0; -- cgit v1.2.3 From 8bae5bf622c764a48d957a5ffc456dd3650dcb6b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:33 +0200 Subject: serial: mediatek: add special handling for highspeed and linux compat Upstream linux serial driver use a different logic to setup serial regs. They have 2 interval: - < 115200 we use lowspeed regs and 16 * baud - >= 115200 we use highspeed We currently use force_highspeed property to force usage of highspeed regs even with low baud rate. Add special handling if the upstream compatible is used where we just apply the same interval with anything >= 115200 in highspeed simulating force_highspeed. Signed-off-by: Christian Marangi --- drivers/serial/serial_mtk.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c index 78e8d9dc735..becf9317076 100644 --- a/drivers/serial/serial_mtk.c +++ b/drivers/serial/serial_mtk.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ struct mtk_serial_regs { * @fixed_clk_rate: Fallback fixed baud clock rate if baud clock * device is not specified * @force_highspeed: Force using high-speed mode + * @upstream_highspeed_logic: Apply upstream high-speed logic */ struct mtk_serial_priv { struct mtk_serial_regs __iomem *regs; @@ -87,6 +89,7 @@ struct mtk_serial_priv { struct clk clk_bus; u32 fixed_clk_rate; bool force_highspeed; + bool upstream_highspeed_logic; }; static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud, @@ -113,7 +116,12 @@ static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud, goto set_baud; } - if (priv->force_highspeed) + /* + * Upstream linux use highspeed for anything >= 115200 and lowspeed + * for < 115200. Simulate this if we are using the upstream compatible. + */ + if (priv->force_highspeed || + (priv->upstream_highspeed_logic && baud >= 115200)) goto use_hs3; if (baud <= 115200) { @@ -259,6 +267,8 @@ static int mtk_serial_of_to_plat(struct udevice *dev) clk_get_by_name(dev, "bus", &priv->clk_bus); priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed"); + priv->upstream_highspeed_logic = + device_is_compatible(dev, "mediatek,mt6577-uart"); return 0; } -- cgit v1.2.3 From 98686fa2f572a2ff695d4f7cced9bf9a9af303e8 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:34 +0200 Subject: mmc: mediatek: add support for upstream linux clock and property Add support for upstream linux clock and map U-Boot property to the one use in upstream linux where supported. Also add handling for the use_internal_cd that on upstream is hardcoded enabled on mt7620. Signed-off-by: Christian Marangi --- drivers/mmc/mtk-sd.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 3a9258255a7..ebd72178b59 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -335,6 +335,7 @@ struct msdc_compatible { bool enhance_rx; bool builtin_pad_ctrl; bool default_pad_dly; + bool use_internal_cd; }; struct msdc_delay_phase { @@ -365,6 +366,10 @@ struct msdc_host { struct clk src_clk_cg; /* optional, MSDC source clock control gate */ struct clk h_clk; /* MSDC core clock */ + /* upstream linux clock */ + struct clk axi_cg_clk; /* optional, AXI clock */ + struct clk ahb_cg_clk; /* optional, AHB clock */ + u32 src_clk_freq; /* source clock */ u32 mclk; /* mmc framework required bus clock */ u32 sclk; /* actual calculated bus clock */ @@ -1637,6 +1642,11 @@ static void msdc_ungate_clock(struct msdc_host *host) clk_enable(&host->h_clk); if (host->src_clk_cg.dev) clk_enable(&host->src_clk_cg); + + if (host->axi_cg_clk.dev) + clk_enable(&host->axi_cg_clk); + if (host->ahb_cg_clk.dev) + clk_enable(&host->ahb_cg_clk); } static int msdc_drv_probe(struct udevice *dev) @@ -1650,6 +1660,9 @@ static int msdc_drv_probe(struct udevice *dev) host->dev_comp = (struct msdc_compatible *)dev_get_driver_data(dev); + if (host->dev_comp->use_internal_cd) + host->builtin_cd = 1; + host->src_clk_freq = clk_get_rate(&host->src_clk); if (host->dev_comp->clk_div_bits == 8) @@ -1715,18 +1728,31 @@ static int msdc_of_to_plat(struct udevice *dev) clk_get_by_name(dev, "source_cg", &host->src_clk_cg); /* optional */ + /* upstream linux clock */ + clk_get_by_name(dev, "axi_cg", &host->axi_cg_clk); /* optional */ + clk_get_by_name(dev, "ahb_cg", &host->ahb_cg_clk); /* optional */ + #if CONFIG_IS_ENABLED(DM_GPIO) gpio_request_by_name(dev, "wp-gpios", 0, &host->gpio_wp, GPIOD_IS_IN); gpio_request_by_name(dev, "cd-gpios", 0, &host->gpio_cd, GPIOD_IS_IN); #endif host->hs400_ds_delay = dev_read_u32_default(dev, "hs400-ds-delay", 0); - host->hs200_cmd_int_delay = - dev_read_u32_default(dev, "cmd_int_delay", 0); + if (dev_read_u32(dev, "mediatek,hs200-cmd-int-delay", + &host->hs200_cmd_int_delay)) + host->hs200_cmd_int_delay = + dev_read_u32_default(dev, "cmd_int_delay", 0); + host->hs200_write_int_delay = dev_read_u32_default(dev, "write_int_delay", 0); - host->latch_ck = dev_read_u32_default(dev, "latch-ck", 0); + + if (dev_read_u32(dev, "mediatek,latch-ck", &host->latch_ck)) + host->latch_ck = dev_read_u32_default(dev, "latch-ck", 0); + host->r_smpl = dev_read_u32_default(dev, "r_smpl", 0); + if (dev_read_bool(dev, "mediatek,hs400-cmd-resp-sel-rising")) + host->r_smpl = 1; + host->builtin_cd = dev_read_u32_default(dev, "builtin-cd", 0); host->cd_active_high = dev_read_bool(dev, "cd-active-high"); @@ -1775,6 +1801,7 @@ static const struct msdc_compatible mt7620_compat = { .enhance_rx = false, .builtin_pad_ctrl = true, .default_pad_dly = true, + .use_internal_cd = true, }; static const struct msdc_compatible mt7621_compat = { @@ -1805,7 +1832,7 @@ static const struct msdc_compatible mt7623_compat = { .data_tune = true, .busy_check = false, .stop_clk_fix = false, - .enhance_rx = false + .enhance_rx = false, }; static const struct msdc_compatible mt7986_compat = { -- cgit v1.2.3 From 55269f10196b7ee5be0eb6c650d93137ffc0abdc Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:35 +0200 Subject: clk: mediatek: mt7981: support alternative compatible for fixed-plls Support alternative compatible for fixed-plls clocks used upstream with the compatible mediatek,mt7981-apmixedsys. Signed-off-by: Christian Marangi --- drivers/clk/mediatek/clk-mt7981.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/clk-mt7981.c b/drivers/clk/mediatek/clk-mt7981.c index 7fcb81419cd..13dc3df0e9e 100644 --- a/drivers/clk/mediatek/clk-mt7981.c +++ b/drivers/clk/mediatek/clk-mt7981.c @@ -543,6 +543,7 @@ static const struct mtk_clk_tree mt7981_infracfg_clk_tree = { static const struct udevice_id mt7981_fixed_pll_compat[] = { { .compatible = "mediatek,mt7981-fixed-plls" }, + { .compatible = "mediatek,mt7981-apmixedsys" }, {} }; -- cgit v1.2.3 From e499d5d430edc69acfee8023d104c389d752ed56 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:36 +0200 Subject: pinctrl: mediatek: add support for gpio-controller property in root node Add support for gpio-controller property in root pinctrl node. This is to follow upstream linux DTSI that doesn't define the gpio-controller and cells in dedicated nodes. Signed-off-by: Christian Marangi --- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 37fc28bb779..ede3959c94f 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -761,6 +761,15 @@ static int mtk_gpiochip_register(struct udevice *parent) if (!drv) return -ENOENT; + /* + * Support upstream linux DTSI that define gpio-controller + * in the root node (instead of a dedicated subnode) + */ + if (dev_read_bool(parent, "gpio-controller")) { + node = dev_ofnode(parent); + goto bind; + } + ret = -ENOENT; dev_for_each_subnode(node, parent) if (ofnode_read_bool(node, "gpio-controller")) { @@ -771,6 +780,7 @@ static int mtk_gpiochip_register(struct udevice *parent) if (ret) return ret; +bind: ret = device_bind_with_driver_data(parent, &mtk_gpio_driver, "mediatek_gpio", 0, node, &dev); -- cgit v1.2.3 From 63d0f683efb70399a93ea7f95eeb78062cc613f0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:37 +0200 Subject: pinctrl: mediatek: mt7981: init device before relocation Upstream kernel linux define pinctrl for uart0, hence this pin group and pinctrl driver is needed before relocation. Add DM_FLAG_PRE_RELOC flag to init and mute mtk_serial error on early serial init. Signed-off-by: Christian Marangi --- drivers/pinctrl/mediatek/pinctrl-mt7981.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c index 3fa198ed79c..4bc4abe6518 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -1050,4 +1050,5 @@ U_BOOT_DRIVER(mt7981_pinctrl) = { .ops = &mtk_pinctrl_ops, .probe = mtk_pinctrl_mt7981_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), + .flags = DM_FLAG_PRE_RELOC, }; -- cgit v1.2.3 From ca54ef2434e4451f5f07bce201fee4d3a32b02ca Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:38 +0200 Subject: pci: mediatek: make pcie-phy optional for gen3 Set pcie-phy optional for PCIe gen3. MT7988 doesn't require it and making it mandatory prevent the driver to correctly probe. Signed-off-by: Christian Marangi --- drivers/pci/pcie_mediatek_gen3.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pcie_mediatek_gen3.c b/drivers/pci/pcie_mediatek_gen3.c index 673813b8b75..0149edae0bf 100644 --- a/drivers/pci/pcie_mediatek_gen3.c +++ b/drivers/pci/pcie_mediatek_gen3.c @@ -284,9 +284,8 @@ static int mtk_pcie_power_on(struct udevice *dev) pcie->priv = dev; - err = generic_phy_get_by_name(dev, "pcie-phy", &pcie->phy); - if (err) - return err; + /* pcie-phy is optional (mt7988 doesn't need it) */ + generic_phy_get_by_name(dev, "pcie-phy", &pcie->phy); /* * Upstream linux kernel devine these clock without clock-names @@ -308,13 +307,15 @@ static int mtk_pcie_power_on(struct udevice *dev) if (err) return err; - err = generic_phy_init(&pcie->phy); - if (err) - return err; + if (pcie->phy.dev) { + err = generic_phy_init(&pcie->phy); + if (err) + return err; - err = generic_phy_power_on(&pcie->phy); - if (err) - goto err_phy_on; + err = generic_phy_power_on(&pcie->phy); + if (err) + goto err_phy_on; + } err = clk_enable(&pcie->pl_250m_ck); if (err) @@ -348,7 +349,8 @@ err_clk_tl_26m: err_clk_pl_250m: clk_disable(&pcie->pl_250m_ck); err_phy_on: - generic_phy_exit(&pcie->phy); + if (pcie->phy.dev) + generic_phy_exit(&pcie->phy); return err; } -- cgit v1.2.3 From 2fa520c124984f828fa5fdae4ab6f32efae6795a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:39 +0200 Subject: clk: mediatek: mt7988: support alternative compatible for fixed-plls Support alternative compatible for fixed-plls clocks used upstream with the compatible mediatek,mt7988-apmixedsys. Signed-off-by: Christian Marangi --- drivers/clk/mediatek/clk-mt7988.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/clk-mt7988.c b/drivers/clk/mediatek/clk-mt7988.c index 34e7b2d734c..32b04511781 100644 --- a/drivers/clk/mediatek/clk-mt7988.c +++ b/drivers/clk/mediatek/clk-mt7988.c @@ -833,6 +833,7 @@ static const struct mtk_clk_tree mt7988_infracfg_clk_tree = { static const struct udevice_id mt7988_fixed_pll_compat[] = { { .compatible = "mediatek,mt7988-fixed-plls" }, + { .compatible = "mediatek,mt7988-apmixedsys" }, {} }; -- cgit v1.2.3 From 4b45082bf710097c8aa6f3ec25c3f34c54c7398c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 24 Jun 2024 23:03:40 +0200 Subject: clk: mediatek: mt7986: support alternative compatible for fixed-plls Support alternative compatible for fixed-plls clocks used upstream with the compatible mediatek,mt7986-apmixedsys. Signed-off-by: Christian Marangi --- drivers/clk/mediatek/clk-mt7986.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/clk-mt7986.c b/drivers/clk/mediatek/clk-mt7986.c index b3fa63fc0ab..efc3d4120b7 100644 --- a/drivers/clk/mediatek/clk-mt7986.c +++ b/drivers/clk/mediatek/clk-mt7986.c @@ -533,6 +533,7 @@ static const struct mtk_clk_tree mt7986_infracfg_clk_tree = { static const struct udevice_id mt7986_fixed_pll_compat[] = { { .compatible = "mediatek,mt7986-fixed-plls" }, + { .compatible = "mediatek,mt7986-apmixedsys" }, {} }; -- cgit v1.2.3