Merge patch series "mediatek: cumulative trivial fix for OF_UPSTREAM support"

Christian Marangi <ansuelsmth@gmail.com> says:

This is an initial series that have all the initial trivial
fixes required for usage of OF_UPSTREAM for the mediatek SoC

This also contains the pcie-gen3 driver and the required tphy
support driver to make it work.

Subsequent series will follow with conversion of the mtk-clk
to permit usage of OF_UPSTREAM and upstream clk ID.

MT7981, MT7986 and MT7988 migration to upstream clock ID
is complete and working on MT7623.

Series CI tested with PR: https://github.com/u-boot/u-boot/pull/590
This commit is contained in:
Tom Rini 2024-07-08 11:56:59 -06:00
commit 475aa8345a
15 changed files with 614 additions and 8 deletions

View file

@ -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" },
{}
};

View file

@ -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" },
{}
};

View file

@ -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" },
{}
};

View file

@ -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;
}

View file

@ -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);
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);
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 = {

View file

@ -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",

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,384 @@
// SPDX-License-Identifier: GPL-2.0
/*
* MediaTek PCIe host controller driver.
*
* Copyright (c) 2023 John Crispin <john@phrozen.org>
* Driver is based on u-boot gen1/2 and upstream linux gen3 code
*/
#include <clk.h>
#include <dm.h>
#include <generic-phy.h>
#include <log.h>
#include <malloc.h>
#include <pci.h>
#include <reset.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/bitops.h>
#include <linux/iopoll.h>
#include <linux/list.h>
#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;
/* 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
* 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;
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 = 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:
if (pcie->phy.dev)
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),
};

View file

@ -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

View file

@ -10,6 +10,8 @@
#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>
@ -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;

View file

@ -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,
};

View file

@ -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);

View file

@ -10,6 +10,7 @@
#include <config.h>
#include <div64.h>
#include <dm.h>
#include <dm/device.h>
#include <dm/device_compat.h>
#include <errno.h>
#include <log.h>
@ -76,15 +77,19 @@ 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
* @upstream_highspeed_logic: Apply upstream high-speed logic
*/
struct mtk_serial_priv {
struct mtk_serial_regs __iomem *regs;
struct clk clk;
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,
@ -111,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) {
@ -220,6 +230,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,7 +264,11 @@ 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;
}

View file

@ -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;
/*
* 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", },
{}
};