diff options
Diffstat (limited to 'drivers')
148 files changed, 11999 insertions, 724 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 4453c62ad33..55de10926ef 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -2,14 +2,19 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk/ obj-$(CONFIG_$(SPL_TPL_)DM) += core/ +obj-$(CONFIG_$(SPL_TPL_)GPIO_SUPPORT) += gpio/ obj-$(CONFIG_$(SPL_TPL_)DRIVERS_MISC_SUPPORT) += misc/ sysreset/ firmware/ obj-$(CONFIG_$(SPL_TPL_)I2C_SUPPORT) += i2c/ +obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/ obj-$(CONFIG_$(SPL_TPL_)LED) += led/ obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/ obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/ +obj-$(CONFIG_$(SPL_TPL_)PCH_SUPPORT) += pch/ +obj-$(CONFIG_$(SPL_TPL_)PCI_SUPPORT) += pci/ obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/ obj-$(CONFIG_$(SPL_TPL_)PINCTRL) += pinctrl/ obj-$(CONFIG_$(SPL_TPL_)RAM) += ram/ +obj-$(CONFIG_$(SPL_TPL_)RTC_SUPPORT) += rtc/ obj-$(CONFIG_$(SPL_TPL_)SERIAL_SUPPORT) += serial/ obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += mtd/spi/ obj-$(CONFIG_$(SPL_TPL_)SPI_SUPPORT) += spi/ @@ -17,6 +22,7 @@ obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/ obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ +obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ ifndef CONFIG_TPL_BUILD ifdef CONFIG_SPL_BUILD @@ -24,7 +30,6 @@ ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_BOOTCOUNT_LIMIT) += bootcount/ obj-$(CONFIG_SPL_CPU_SUPPORT) += cpu/ obj-$(CONFIG_SPL_CRYPTO_SUPPORT) += crypto/ -obj-$(CONFIG_SPL_GPIO_SUPPORT) += gpio/ obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/ obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/ @@ -40,9 +45,6 @@ obj-$(CONFIG_SPL_DMA_SUPPORT) += dma/ obj-$(CONFIG_SPL_ETH_SUPPORT) += net/ obj-$(CONFIG_SPL_ETH_SUPPORT) += net/phy/ obj-$(CONFIG_SPL_USB_ETHER) += net/phy/ -obj-$(CONFIG_SPL_PCI_SUPPORT) += pci/ -obj-$(CONFIG_SPL_PCH_SUPPORT) += pch/ -obj-$(CONFIG_SPL_RTC_SUPPORT) += rtc/ obj-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += usb/musb-new/ obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += usb/gadget/ obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += usb/gadget/udc/ @@ -92,7 +94,6 @@ obj-y += scsi/ obj-y += sound/ obj-y += spmi/ obj-y += sysreset/ -obj-y += tpm/ obj-y += video/ obj-y += watchdog/ obj-$(CONFIG_QE) += qe/ diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 821b5867e87..9acbb1a6500 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,7 +9,8 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o clk_fixed_rate.o obj-y += imx/ obj-y += tegra/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ -obj-$(CONFIG_ARCH_MESON) += clk_meson.o +obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ +obj-$(CONFIG_ARCH_MESON) += clk_meson.o clk_meson_axg.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_SOCFPGA) += altera/ obj-$(CONFIG_CLK_AT91) += at91/ diff --git a/drivers/clk/clk_meson.c b/drivers/clk/clk_meson.c index c44858822d1..2cb53fb92d2 100644 --- a/drivers/clk/clk_meson.c +++ b/drivers/clk/clk_meson.c @@ -6,11 +6,13 @@ */ #include <common.h> -#include <asm/arch/clock.h> +#include <asm/arch/clock-gx.h> #include <asm/io.h> #include <clk-uclass.h> #include <div64.h> #include <dm.h> +#include <regmap.h> +#include <syscon.h> #include <dt-bindings/clock/gxbb-clkc.h> #include "clk_meson.h" @@ -65,7 +67,7 @@ #define XTAL_RATE 24000000 struct meson_clk { - void __iomem *addr; + struct regmap *map; }; static ulong meson_div_get_rate(struct clk *clk, unsigned long id); @@ -79,7 +81,7 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, static ulong meson_mux_get_parent(struct clk *clk, unsigned long id); static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); -struct meson_gate gates[] = { +static struct meson_gate gates[] = { /* Everything Else (EE) domain gates */ MESON_GATE(CLKID_DDR, HHI_GCLK_MPEG0, 0), MESON_GATE(CLKID_DOS, HHI_GCLK_MPEG0, 1), @@ -217,8 +219,8 @@ static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id); - clrsetbits_le32(priv->addr + gate->reg, - BIT(gate->bit), on ? BIT(gate->bit) : 0); + regmap_update_bits(priv->map, gate->reg, + BIT(gate->bit), on ? BIT(gate->bit) : 0); /* Propagate to next gate(s) */ switch (id) { @@ -269,7 +271,7 @@ static ulong meson_div_get_rate(struct clk *clk, unsigned long id) unsigned int rate, parent_rate; struct parm *parm; int parent; - u32 reg; + uint reg; switch (id) { case CLKID_VPU_0_DIV: @@ -292,7 +294,7 @@ static ulong meson_div_get_rate(struct clk *clk, unsigned long id) return -ENOENT; } - reg = readl(priv->addr + parm->reg_off); + regmap_read(priv->map, parm->reg_off, ®); reg = PARM_GET(parm->width, parm->shift, reg); debug("%s: div of %ld is %d\n", __func__, id, reg + 1); @@ -318,7 +320,6 @@ static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, unsigned long parent_rate; struct parm *parm; int parent; - u32 reg; int ret; if (current_rate == rate) @@ -383,9 +384,8 @@ static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, debug("%s: setting div of %ld to %d\n", __func__, id, new_div); - reg = readl(priv->addr + parm->reg_off); - writel(PARM_SET(parm->width, parm->shift, reg, new_div - 1), - priv->addr + parm->reg_off); + regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), + (new_div - 1) << parm->shift); debug("%s: new rate of %ld is %ld\n", __func__, id, meson_div_get_rate(clk, id)); @@ -446,7 +446,7 @@ static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) struct meson_clk *priv = dev_get_priv(clk->dev); struct parm *parm; int *parents; - u32 reg; + uint reg; switch (id) { case CLKID_VPU: @@ -477,7 +477,7 @@ static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) return -ENOENT; } - reg = readl(priv->addr + parm->reg_off); + regmap_read(priv->map, parm->reg_off, ®); reg = PARM_GET(parm->width, parm->shift, reg); debug("%s: parent of %ld is %d (%d)\n", @@ -494,7 +494,6 @@ static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, unsigned int new_index = -EINVAL; struct parm *parm; int *parents; - u32 reg; int i; if (IS_ERR_VALUE(cur_parent)) @@ -546,9 +545,8 @@ static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, debug("%s: new index of %ld is %d\n", __func__, id, new_index); - reg = readl(priv->addr + parm->reg_off); - writel(PARM_SET(parm->width, parm->shift, reg, new_index), - priv->addr + parm->reg_off); + regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), + new_index << parm->shift); debug("%s: new parent of %ld is %ld\n", __func__, id, meson_mux_get_parent(clk, id)); @@ -570,7 +568,7 @@ static unsigned long meson_clk81_get_rate(struct clk *clk) { struct meson_clk *priv = dev_get_priv(clk->dev); unsigned long parent_rate; - u32 reg; + uint reg; int parents[] = { -1, -1, @@ -583,7 +581,7 @@ static unsigned long meson_clk81_get_rate(struct clk *clk) }; /* mux */ - reg = readl(priv->addr + HHI_MPEG_CLK_CNTL); + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); reg = (reg >> 12) & 7; switch (reg) { @@ -597,7 +595,7 @@ static unsigned long meson_clk81_get_rate(struct clk *clk) } /* divider */ - reg = readl(priv->addr + HHI_MPEG_CLK_CNTL); + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); reg = reg & ((1 << 7) - 1); /* clk81 divider is zero based */ @@ -641,8 +639,9 @@ static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) { struct meson_clk *priv = dev_get_priv(clk->dev); struct parm *psdm, *pn2; - unsigned long reg, sdm, n2; + unsigned long sdm, n2; unsigned long parent_rate; + uint reg; switch (id) { case CLKID_MPLL0: @@ -665,10 +664,10 @@ static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) if (IS_ERR_VALUE(parent_rate)) return parent_rate; - reg = readl(priv->addr + psdm->reg_off); + regmap_read(priv->map, psdm->reg_off, ®); sdm = PARM_GET(psdm->width, psdm->shift, reg); - reg = readl(priv->addr + pn2->reg_off); + regmap_read(priv->map, pn2->reg_off, ®); n2 = PARM_GET(pn2->width, pn2->shift, reg); return mpll_rate_from_params(parent_rate, sdm, n2); @@ -692,7 +691,7 @@ static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) struct parm *pm, *pn, *pod; unsigned long parent_rate_mhz = XTAL_RATE / 1000000; u16 n, m, od; - u32 reg; + uint reg; switch (id) { case CLKID_FIXED_PLL: @@ -709,13 +708,13 @@ static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) return -ENOENT; } - reg = readl(priv->addr + pn->reg_off); + regmap_read(priv->map, pn->reg_off, ®); n = PARM_GET(pn->width, pn->shift, reg); - reg = readl(priv->addr + pm->reg_off); + regmap_read(priv->map, pm->reg_off, ®); m = PARM_GET(pm->width, pm->shift, reg); - reg = readl(priv->addr + pod->reg_off); + regmap_read(priv->map, pod->reg_off, ®); od = PARM_GET(pod->width, pod->shift, reg); return ((parent_rate_mhz * m / n) >> od) * 1000000; @@ -791,7 +790,7 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) return -ENOENT; } - printf("clock %lu has rate %lu\n", id, rate); + debug("clock %lu has rate %lu\n", id, rate); return rate; } @@ -876,8 +875,8 @@ static ulong meson_clk_set_rate(struct clk *clk, ulong rate) if (IS_ERR_VALUE(ret)) return ret; - printf("clock %lu has new rate %lu\n", clk->id, - meson_clk_get_rate_by_id(clk, clk->id)); + debug("clock %lu has new rate %lu\n", clk->id, + meson_clk_get_rate_by_id(clk, clk->id)); return 0; } @@ -886,9 +885,11 @@ static int meson_clk_probe(struct udevice *dev) { struct meson_clk *priv = dev_get_priv(dev); - priv->addr = dev_read_addr_ptr(dev); + priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); - debug("meson-clk: probed at addr %p\n", priv->addr); + debug("meson-clk: probed\n"); return 0; } diff --git a/drivers/clk/clk_meson_axg.c b/drivers/clk/clk_meson_axg.c new file mode 100644 index 00000000000..32cbf752aed --- /dev/null +++ b/drivers/clk/clk_meson_axg.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com> + * (C) Copyright 2018 - BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#include <common.h> +#include <asm/arch/clock-axg.h> +#include <asm/io.h> +#include <clk-uclass.h> +#include <dm.h> +#include <regmap.h> +#include <syscon.h> +#include <div64.h> +#include <dt-bindings/clock/axg-clkc.h> +#include "clk_meson.h" + +#define XTAL_RATE 24000000 + +struct meson_clk { + struct regmap *map; +}; + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); + +static struct meson_gate gates[] = { + /* Everything Else (EE) domain gates */ + MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8), + MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), + MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), + MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 15), + MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), + MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), + MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), + MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), + + /* Always On (AO) domain gates */ + MESON_GATE(CLKID_AO_I2C, HHI_GCLK_AO, 4), + + /* PLL Gates */ + /* CLKID_FCLK_DIV2 is critical for the SCPI Processor */ + MESON_GATE(CLKID_MPLL2, HHI_MPLL_CNTL9, 14), + /* CLKID_CLK81 is critical for the system */ + + /* Peripheral Gates */ + MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), + MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), +}; + +static int meson_set_gate(struct clk *clk, bool on) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct meson_gate *gate; + + if (clk->id >= ARRAY_SIZE(gates)) + return -ENOENT; + + gate = &gates[clk->id]; + + if (gate->reg == 0) + return 0; + + regmap_update_bits(priv->map, gate->reg, + BIT(gate->bit), on ? BIT(gate->bit) : 0); + + return 0; +} + +static int meson_clk_enable(struct clk *clk) +{ + return meson_set_gate(clk, true); +} + +static int meson_clk_disable(struct clk *clk) +{ + return meson_set_gate(clk, false); +} + +static unsigned long meson_clk81_get_rate(struct clk *clk) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + unsigned long parent_rate; + uint reg; + int parents[] = { + -1, + -1, + CLKID_FCLK_DIV7, + CLKID_MPLL1, + CLKID_MPLL2, + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5 + }; + + /* mux */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = (reg >> 12) & 7; + + switch (reg) { + case 0: + parent_rate = XTAL_RATE; + break; + case 1: + return -ENOENT; + default: + parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); + } + + /* divider */ + regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); + reg = reg & ((1 << 7) - 1); + + return parent_rate / reg; +} + +static long mpll_rate_from_params(unsigned long parent_rate, + unsigned long sdm, + unsigned long n2) +{ + unsigned long divisor = (SDM_DEN * n2) + sdm; + + if (n2 < N2_MIN) + return -EINVAL; + + return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); +} + +static struct parm meson_mpll0_parm[3] = { + {HHI_MPLL_CNTL7, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL7, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll1_parm[3] = { + {HHI_MPLL_CNTL8, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL8, 16, 9}, /* pn2 */ +}; + +static struct parm meson_mpll2_parm[3] = { + {HHI_MPLL_CNTL9, 0, 14}, /* psdm */ + {HHI_MPLL_CNTL9, 16, 9}, /* pn2 */ +}; + +/* + * MultiPhase Locked Loops are outputs from a PLL with additional frequency + * scaling capabilities. MPLL rates are calculated as: + * + * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) + */ +static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *psdm, *pn2; + unsigned long sdm, n2; + unsigned long parent_rate; + uint reg; + + switch (id) { + case CLKID_MPLL0: + psdm = &meson_mpll0_parm[0]; + pn2 = &meson_mpll0_parm[1]; + break; + case CLKID_MPLL1: + psdm = &meson_mpll1_parm[0]; + pn2 = &meson_mpll1_parm[1]; + break; + case CLKID_MPLL2: + psdm = &meson_mpll2_parm[0]; + pn2 = &meson_mpll2_parm[1]; + break; + default: + return -ENOENT; + } + + parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; + + regmap_read(priv->map, psdm->reg_off, ®); + sdm = PARM_GET(psdm->width, psdm->shift, reg); + + regmap_read(priv->map, pn2->reg_off, ®); + n2 = PARM_GET(pn2->width, pn2->shift, reg); + + return mpll_rate_from_params(parent_rate, sdm, n2); +} + +static struct parm meson_fixed_pll_parm[3] = { + {HHI_MPLL_CNTL, 0, 9}, /* pm */ + {HHI_MPLL_CNTL, 9, 5}, /* pn */ + {HHI_MPLL_CNTL, 16, 2}, /* pod */ +}; + +static struct parm meson_sys_pll_parm[3] = { + {HHI_SYS_PLL_CNTL, 0, 9}, /* pm */ + {HHI_SYS_PLL_CNTL, 9, 5}, /* pn */ + {HHI_SYS_PLL_CNTL, 16, 2}, /* pod */ +}; + +static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) +{ + struct meson_clk *priv = dev_get_priv(clk->dev); + struct parm *pm, *pn, *pod; + unsigned long parent_rate_mhz = XTAL_RATE / 1000000; + u16 n, m, od; + uint reg; + + switch (id) { + case CLKID_FIXED_PLL: + pm = &meson_fixed_pll_parm[0]; + pn = &meson_fixed_pll_parm[1]; + pod = &meson_fixed_pll_parm[2]; + break; + case CLKID_SYS_PLL: + pm = &meson_sys_pll_parm[0]; + pn = &meson_sys_pll_parm[1]; + pod = &meson_sys_pll_parm[2]; + break; + default: + return -ENOENT; + } + + regmap_read(priv->map, pn->reg_off, ®); + n = PARM_GET(pn->width, pn->shift, reg); + + regmap_read(priv->map, pm->reg_off, ®); + m = PARM_GET(pm->width, pm->shift, reg); + + regmap_read(priv->map, pod->reg_off, ®); + od = PARM_GET(pod->width, pod->shift, reg); + + return ((parent_rate_mhz * m / n) >> od) * 1000000; +} + +static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) +{ + ulong rate; + + switch (id) { + case CLKID_FIXED_PLL: + case CLKID_SYS_PLL: + rate = meson_pll_get_rate(clk, id); + break; + case CLKID_FCLK_DIV2: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; + break; + case CLKID_FCLK_DIV3: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; + break; + case CLKID_FCLK_DIV4: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; + break; + case CLKID_FCLK_DIV5: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; + break; + case CLKID_FCLK_DIV7: + rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; + break; + case CLKID_MPLL0: + case CLKID_MPLL1: + case CLKID_MPLL2: + rate = meson_mpll_get_rate(clk, id); + break; + case CLKID_CLK81: + rate = meson_clk81_get_rate(clk); + break; + default: + if (gates[id].reg != 0) { + /* a clock gate */ + rate = meson_clk81_get_rate(clk); + break; + } + return -ENOENT; + } + + debug("clock %lu has rate %lu\n", id, rate); + return rate; +} + +static ulong meson_clk_get_rate(struct clk *clk) +{ + return meson_clk_get_rate_by_id(clk, clk->id); +} + +static int meson_clk_probe(struct udevice *dev) +{ + struct meson_clk *priv = dev_get_priv(dev); + + priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); + + debug("meson-clk-axg: probed\n"); + + return 0; +} + +static struct clk_ops meson_clk_ops = { + .disable = meson_clk_disable, + .enable = meson_clk_enable, + .get_rate = meson_clk_get_rate, +}; + +static const struct udevice_id meson_clk_ids[] = { + { .compatible = "amlogic,axg-clkc" }, + { } +}; + +U_BOOT_DRIVER(meson_clk_axg) = { + .name = "meson_clk_axg", + .id = UCLASS_CLK, + .of_match = meson_clk_ids, + .priv_auto_alloc_size = sizeof(struct meson_clk), + .ops = &meson_clk_ops, + .probe = meson_clk_probe, +}; diff --git a/drivers/clk/clk_vexpress_osc.c b/drivers/clk/clk_vexpress_osc.c index 7fef4b2e312..c692a6d0b89 100644 --- a/drivers/clk/clk_vexpress_osc.c +++ b/drivers/clk/clk_vexpress_osc.c @@ -29,7 +29,7 @@ static ulong vexpress_osc_clk_get_rate(struct clk *clk) data = CLK_FUNCTION | priv->osc; err = misc_read(vexpress_cfg, 0, &data, sizeof(data)); - if (err) + if (err < 0) return err; return data; @@ -53,7 +53,7 @@ static ulong vexpress_osc_clk_set_rate(struct clk *clk, ulong rate) buffer[0] = CLK_FUNCTION | priv->osc; buffer[1] = rate; err = misc_write(vexpress_cfg, 0, buffer, 2 * sizeof(u32)); - if (err) + if (err < 0) return err; return rate; diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile new file mode 100644 index 00000000000..0632dc87b6d --- /dev/null +++ b/drivers/clk/mediatek/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Core +obj-$(CONFIG_ARCH_MEDIATEK) += clk-mtk.o + +# SoC Drivers +obj-$(CONFIG_TARGET_MT7623) += clk-mt7623.o +obj-$(CONFIG_TARGET_MT7629) += clk-mt7629.o diff --git a/drivers/clk/mediatek/clk-mt7623.c b/drivers/clk/mediatek/clk-mt7623.c new file mode 100644 index 00000000000..c6b09d8e18d --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7623.c @@ -0,0 +1,870 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek clock driver for MT7623 SoC + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <dt-bindings/clock/mt7623-clk.h> + +#include "clk-mtk.h" + +#define MT7623_CLKSQ_STB_CON0 0x18 +#define MT7623_PLL_ISO_CON0 0x24 +#define MT7623_PLL_FMAX (2000UL * MHZ) +#define MT7623_CON0_RST_BAR BIT(27) + +#define MCU_AXI_DIV 0x60 +#define AXI_DIV_MSK GENMASK(4, 0) +#define AXI_DIV_SEL(x) (x) + +/* apmixedsys */ +#define PLL(_id, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ + _pd_shift, _pcw_reg, _pcw_shift) { \ + .id = _id, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .rst_bar_mask = MT7623_CON0_RST_BAR, \ + .fmax = MT7623_PLL_FMAX, \ + .flags = _flags, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + } + +static const struct mtk_pll_data apmixed_plls[] = { + PLL(CLK_APMIXED_ARMPLL, 0x200, 0x20c, 0x80000001, 0, + 21, 0x204, 24, 0x204, 0), + PLL(CLK_APMIXED_MAINPLL, 0x210, 0x21c, 0xf0000001, HAVE_RST_BAR, + 21, 0x210, 4, 0x214, 0), + PLL(CLK_APMIXED_UNIVPLL, 0x220, 0x22c, 0xf3000001, HAVE_RST_BAR, + 7, 0x220, 4, 0x224, 14), + PLL(CLK_APMIXED_MMPLL, 0x230, 0x23c, 0x00000001, 0, + 21, 0x230, 4, 0x234, 0), + PLL(CLK_APMIXED_MSDCPLL, 0x240, 0x24c, 0x00000001, 0, + 21, 0x240, 4, 0x244, 0), + PLL(CLK_APMIXED_TVDPLL, 0x250, 0x25c, 0x00000001, 0, + 21, 0x250, 4, 0x254, 0), + PLL(CLK_APMIXED_AUD1PLL, 0x270, 0x27c, 0x00000001, 0, + 31, 0x270, 4, 0x274, 0), + PLL(CLK_APMIXED_TRGPLL, 0x280, 0x28c, 0x00000001, 0, + 31, 0x280, 4, 0x284, 0), + PLL(CLK_APMIXED_ETHPLL, 0x290, 0x29c, 0x00000001, 0, + 31, 0x290, 4, 0x294, 0), + PLL(CLK_APMIXED_VDECPLL, 0x2a0, 0x2ac, 0x00000001, 0, + 31, 0x2a0, 4, 0x2a4, 0), + PLL(CLK_APMIXED_HADDS2PLL, 0x2b0, 0x2bc, 0x00000001, 0, + 31, 0x2b0, 4, 0x2b4, 0), + PLL(CLK_APMIXED_AUD2PLL, 0x2c0, 0x2cc, 0x00000001, 0, + 31, 0x2c0, 4, 0x2c4, 0), + PLL(CLK_APMIXED_TVD2PLL, 0x2d0, 0x2dc, 0x00000001, 0, + 21, 0x2d0, 4, 0x2d4, 0), +}; + +/* topckgen */ +#define FACTOR0(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED) + +#define FACTOR1(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN) + +#define FACTOR2(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, 0) + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_DPI, CLK_XTAL, 108 * MHZ), + FIXED_CLK(CLK_TOP_DMPLL, CLK_XTAL, 400 * MHZ), + FIXED_CLK(CLK_TOP_VENCPLL, CLK_XTAL, 295.75 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, CLK_XTAL, 340 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, CLK_XTAL, 340 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, CLK_XTAL, 340 * MHZ), + FIXED_CLK(CLK_TOP_HADDS2_FB, CLK_XTAL, 27 * MHZ), + FIXED_CLK(CLK_TOP_WBG_DIG_416M, CLK_XTAL, 416 * MHZ), + FIXED_CLK(CLK_TOP_DSI0_LNTC_DSI, CLK_XTAL, 143 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_SCL_RX, CLK_XTAL, 27 * MHZ), + FIXED_CLK(CLK_TOP_32K_EXTERNAL, CLK_XTAL, 32000), + FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, CLK_XTAL, 300 * MHZ), + FIXED_CLK(CLK_TOP_AUD_EXT1, CLK_XTAL, 0), + FIXED_CLK(CLK_TOP_AUD_EXT2, CLK_XTAL, 0), + FIXED_CLK(CLK_TOP_NFI1X_PAD, CLK_XTAL, 0), +}; + +static const struct mtk_fixed_factor top_fixed_divs[] = { + FACTOR0(CLK_TOP_SYSPLL, CLK_APMIXED_MAINPLL, 1, 1), + FACTOR0(CLK_TOP_SYSPLL_D2, CLK_APMIXED_MAINPLL, 1, 2), + FACTOR0(CLK_TOP_SYSPLL_D3, CLK_APMIXED_MAINPLL, 1, 3), + FACTOR0(CLK_TOP_SYSPLL_D5, CLK_APMIXED_MAINPLL, 1, 5), + FACTOR0(CLK_TOP_SYSPLL_D7, CLK_APMIXED_MAINPLL, 1, 7), + FACTOR1(CLK_TOP_SYSPLL1_D2, CLK_TOP_SYSPLL_D2, 1, 2), + FACTOR1(CLK_TOP_SYSPLL1_D4, CLK_TOP_SYSPLL_D2, 1, 4), + FACTOR1(CLK_TOP_SYSPLL1_D8, CLK_TOP_SYSPLL_D2, 1, 8), + FACTOR1(CLK_TOP_SYSPLL1_D16, CLK_TOP_SYSPLL_D2, 1, 16), + FACTOR1(CLK_TOP_SYSPLL2_D2, CLK_TOP_SYSPLL_D3, 1, 2), + FACTOR1(CLK_TOP_SYSPLL2_D4, CLK_TOP_SYSPLL_D3, 1, 4), + FACTOR1(CLK_TOP_SYSPLL2_D8, CLK_TOP_SYSPLL_D3, 1, 8), + FACTOR1(CLK_TOP_SYSPLL3_D2, CLK_TOP_SYSPLL_D5, 1, 2), + FACTOR1(CLK_TOP_SYSPLL3_D4, CLK_TOP_SYSPLL_D5, 1, 4), + FACTOR1(CLK_TOP_SYSPLL4_D2, CLK_TOP_SYSPLL_D7, 1, 2), + FACTOR1(CLK_TOP_SYSPLL4_D4, CLK_TOP_SYSPLL_D7, 1, 4), + + FACTOR0(CLK_TOP_UNIVPLL, CLK_APMIXED_UNIVPLL, 1, 1), + FACTOR0(CLK_TOP_UNIVPLL_D2, CLK_APMIXED_UNIVPLL, 1, 2), + FACTOR0(CLK_TOP_UNIVPLL_D3, CLK_APMIXED_UNIVPLL, 1, 3), + FACTOR0(CLK_TOP_UNIVPLL_D5, CLK_APMIXED_UNIVPLL, 1, 5), + FACTOR0(CLK_TOP_UNIVPLL_D7, CLK_APMIXED_UNIVPLL, 1, 7), + FACTOR0(CLK_TOP_UNIVPLL_D26, CLK_APMIXED_UNIVPLL, 1, 26), + FACTOR0(CLK_TOP_UNIVPLL_D52, CLK_APMIXED_UNIVPLL, 1, 52), + FACTOR0(CLK_TOP_UNIVPLL_D108, CLK_APMIXED_UNIVPLL, 1, 108), + FACTOR0(CLK_TOP_USB_PHY48M, CLK_APMIXED_UNIVPLL, 1, 26), + FACTOR1(CLK_TOP_UNIVPLL1_D2, CLK_TOP_UNIVPLL_D2, 1, 2), + FACTOR1(CLK_TOP_UNIVPLL1_D4, CLK_TOP_UNIVPLL_D2, 1, 4), + FACTOR1(CLK_TOP_UNIVPLL1_D8, CLK_TOP_UNIVPLL_D2, 1, 8), + FACTOR1(CLK_TOP_UNIVPLL2_D2, CLK_TOP_UNIVPLL_D3, 1, 2), + FACTOR1(CLK_TOP_UNIVPLL2_D4, CLK_TOP_UNIVPLL_D3, 1, 4), + FACTOR1(CLK_TOP_UNIVPLL2_D8, CLK_TOP_UNIVPLL_D3, 1, 8), + FACTOR1(CLK_TOP_UNIVPLL2_D16, CLK_TOP_UNIVPLL_D3, 1, 16), + FACTOR1(CLK_TOP_UNIVPLL2_D32, CLK_TOP_UNIVPLL_D3, 1, 32), + FACTOR1(CLK_TOP_UNIVPLL3_D2, CLK_TOP_UNIVPLL_D5, 1, 2), + FACTOR1(CLK_TOP_UNIVPLL3_D4, CLK_TOP_UNIVPLL_D5, 1, 4), + FACTOR1(CLK_TOP_UNIVPLL3_D8, CLK_TOP_UNIVPLL_D5, 1, 8), + + FACTOR0(CLK_TOP_MSDCPLL, CLK_APMIXED_MSDCPLL, 1, 1), + FACTOR0(CLK_TOP_MSDCPLL_D2, CLK_APMIXED_MSDCPLL, 1, 2), + FACTOR0(CLK_TOP_MSDCPLL_D4, CLK_APMIXED_MSDCPLL, 1, 4), + FACTOR0(CLK_TOP_MSDCPLL_D8, CLK_APMIXED_MSDCPLL, 1, 8), + + FACTOR0(CLK_TOP_MMPLL, CLK_APMIXED_MMPLL, 1, 1), + FACTOR0(CLK_TOP_MMPLL_D2, CLK_APMIXED_MMPLL, 1, 2), + + FACTOR1(CLK_TOP_DMPLL_D2, CLK_TOP_DMPLL, 1, 2), + FACTOR1(CLK_TOP_DMPLL_D4, CLK_TOP_DMPLL, 1, 4), + FACTOR1(CLK_TOP_DMPLL_X2, CLK_TOP_DMPLL, 1, 1), + + FACTOR0(CLK_TOP_TVDPLL, CLK_APMIXED_TVDPLL, 1, 1), + FACTOR0(CLK_TOP_TVDPLL_D2, CLK_APMIXED_TVDPLL, 1, 2), + FACTOR0(CLK_TOP_TVDPLL_D4, CLK_APMIXED_TVDPLL, 1, 4), + + FACTOR0(CLK_TOP_VDECPLL, CLK_APMIXED_VDECPLL, 1, 1), + FACTOR0(CLK_TOP_TVD2PLL, CLK_APMIXED_TVD2PLL, 1, 1), + FACTOR0(CLK_TOP_TVD2PLL_D2, CLK_APMIXED_TVD2PLL, 1, 2), + + FACTOR1(CLK_TOP_MIPIPLL, CLK_TOP_DPI, 1, 1), + FACTOR1(CLK_TOP_MIPIPLL_D2, CLK_TOP_DPI, 1, 2), + FACTOR1(CLK_TOP_MIPIPLL_D4, CLK_TOP_DPI, 1, 4), + + FACTOR1(CLK_TOP_HDMIPLL, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 1), + FACTOR1(CLK_TOP_HDMIPLL_D2, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 2), + FACTOR1(CLK_TOP_HDMIPLL_D3, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 3), + + FACTOR0(CLK_TOP_ARMPLL_1P3G, CLK_APMIXED_ARMPLL, 1, 1), + + FACTOR1(CLK_TOP_AUDPLL, CLK_TOP_AUDPLL_MUX_SEL, 1, 1), + FACTOR1(CLK_TOP_AUDPLL_D4, CLK_TOP_AUDPLL_MUX_SEL, 1, 4), + FACTOR1(CLK_TOP_AUDPLL_D8, CLK_TOP_AUDPLL_MUX_SEL, 1, 8), + FACTOR1(CLK_TOP_AUDPLL_D16, CLK_TOP_AUDPLL_MUX_SEL, 1, 16), + FACTOR1(CLK_TOP_AUDPLL_D24, CLK_TOP_AUDPLL_MUX_SEL, 1, 24), + + FACTOR0(CLK_TOP_AUD1PLL_98M, CLK_APMIXED_AUD1PLL, 1, 3), + FACTOR0(CLK_TOP_AUD2PLL_90M, CLK_APMIXED_AUD2PLL, 1, 3), + FACTOR0(CLK_TOP_HADDS2PLL_98M, CLK_APMIXED_HADDS2PLL, 1, 3), + FACTOR0(CLK_TOP_HADDS2PLL_294M, CLK_APMIXED_HADDS2PLL, 1, 1), + FACTOR0(CLK_TOP_ETHPLL_500M, CLK_APMIXED_ETHPLL, 1, 1), + FACTOR2(CLK_TOP_CLK26M_D8, CLK_XTAL, 1, 8), + FACTOR2(CLK_TOP_32K_INTERNAL, CLK_XTAL, 1, 793), + FACTOR1(CLK_TOP_AXISEL_D4, CLK_TOP_AXI_SEL, 1, 4), + FACTOR1(CLK_TOP_8BDAC, CLK_TOP_UNIVPLL_D2, 1, 1), +}; + +static const int axi_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL_D5, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_MMPLL_D2, + CLK_TOP_DMPLL_D2 +}; + +static const int mem_parents[] = { + CLK_XTAL, + CLK_TOP_DMPLL +}; + +static const int ddrphycfg_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8 +}; + +static const int mm_parents[] = { + CLK_XTAL, + CLK_TOP_VENCPLL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_DMPLL +}; + +static const int pwm_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL3_D2, + CLK_TOP_UNIVPLL1_D4 +}; + +static const int vdec_parents[] = { + CLK_XTAL, + CLK_TOP_VDECPLL, + CLK_TOP_SYSPLL_D5, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_VENCPLL, + CLK_TOP_MSDCPLL_D2, + CLK_TOP_MMPLL_D2 +}; + +static const int mfg_parents[] = { + CLK_XTAL, + CLK_TOP_MMPLL, + CLK_TOP_DMPLL_X2, + CLK_TOP_MSDCPLL, + CLK_XTAL, + CLK_TOP_SYSPLL_D3, + CLK_TOP_UNIVPLL_D3, + CLK_TOP_UNIVPLL1_D2 +}; + +static const int camtg_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL_D26, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_SYSPLL3_D2, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_MSDCPLL_D2, + CLK_TOP_MMPLL_D2 +}; + +static const int uart_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D8 +}; + +static const int spi_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL3_D2, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL1_D8 +}; + +static const int usb20_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL1_D8, + CLK_TOP_UNIVPLL3_D4 +}; + +static const int msdc30_parents[] = { + CLK_XTAL, + CLK_TOP_MSDCPLL_D2, + CLK_TOP_SYSPLL2_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL1_D4, + CLK_TOP_UNIVPLL2_D4, +}; + +static const int aud_intbus_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_SYSPLL3_D2, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_UNIVPLL3_D2, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int pmicspi_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_SYSPLL2_D8, + CLK_TOP_SYSPLL1_D16, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_UNIVPLL_D26, + CLK_TOP_DMPLL_D2, + CLK_TOP_DMPLL_D4 +}; + +static const int scp_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_DMPLL_D2, + CLK_TOP_DMPLL_D4 +}; + +static const int dpi0_tve_parents[] = { + CLK_XTAL, + CLK_TOP_MIPIPLL, + CLK_TOP_MIPIPLL_D2, + CLK_TOP_MIPIPLL_D4, + CLK_XTAL, + CLK_TOP_TVDPLL, + CLK_TOP_TVDPLL_D2, + CLK_TOP_TVDPLL_D4 +}; + +static const int dpi1_parents[] = { + CLK_XTAL, + CLK_TOP_TVDPLL, + CLK_TOP_TVDPLL_D2, + CLK_TOP_TVDPLL_D4 +}; + +static const int hdmi_parents[] = { + CLK_XTAL, + CLK_TOP_HDMIPLL, + CLK_TOP_HDMIPLL_D2, + CLK_TOP_HDMIPLL_D3 +}; + +static const int apll_parents[] = { + CLK_XTAL, + CLK_TOP_AUDPLL, + CLK_TOP_AUDPLL_D4, + CLK_TOP_AUDPLL_D8, + CLK_TOP_AUDPLL_D16, + CLK_TOP_AUDPLL_D24, + CLK_XTAL, + CLK_XTAL +}; + +static const int rtc_parents[] = { + CLK_TOP_32K_INTERNAL, + CLK_TOP_32K_EXTERNAL, + CLK_XTAL, + CLK_TOP_UNIVPLL3_D8 +}; + +static const int nfi2x_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL2_D2, + CLK_TOP_SYSPLL_D7, + CLK_TOP_UNIVPLL3_D2, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_SYSPLL4_D4, + CLK_XTAL +}; + +static const int emmc_hclk_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_SYSPLL2_D2 +}; + +static const int flash_parents[] = { + CLK_TOP_CLK26M_D8, + CLK_XTAL, + CLK_TOP_SYSPLL2_D8, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int di_parents[] = { + CLK_XTAL, + CLK_TOP_TVD2PLL, + CLK_TOP_TVD2PLL_D2, + CLK_XTAL +}; + +static const int nr_osd_parents[] = { + CLK_XTAL, + CLK_TOP_VENCPLL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_DMPLL +}; + +static const int hdmirx_bist_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL_D3, + CLK_XTAL, + CLK_TOP_SYSPLL1_D16, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_VENCPLL, + CLK_XTAL +}; + +static const int intdir_parents[] = { + CLK_XTAL, + CLK_TOP_MMPLL, + CLK_TOP_SYSPLL_D2, + CLK_TOP_UNIVPLL_D2 +}; + +static const int asm_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_SYSPLL_D5 +}; + +static const int ms_card_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL3_D8, + CLK_TOP_SYSPLL4_D4 +}; + +static const int ethif_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL_D5, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_DMPLL, + CLK_TOP_DMPLL_D2 +}; + +static const int hdmirx_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL_D52 +}; + +static const int cmsys_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_SYSPLL_D5, + CLK_TOP_SYSPLL2_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_SYSPLL3_D2, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_SYSPLL1_D8, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL +}; + +static const int clk_8bdac_parents[] = { + CLK_TOP_32K_INTERNAL, + CLK_TOP_8BDAC, + CLK_XTAL, + CLK_XTAL +}; + +static const int aud2dvd_parents[] = { + CLK_TOP_AUD_48K_TIMING, + CLK_TOP_AUD_44K_TIMING +}; + +static const int padmclk_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL_D26, + CLK_TOP_UNIVPLL_D52, + CLK_TOP_UNIVPLL_D108, + CLK_TOP_UNIVPLL2_D8, + CLK_TOP_UNIVPLL2_D16, + CLK_TOP_UNIVPLL2_D32 +}; + +static const int aud_mux_parents[] = { + CLK_XTAL, + CLK_TOP_AUD1PLL_98M, + CLK_TOP_AUD2PLL_90M, + CLK_TOP_HADDS2PLL_98M, + CLK_TOP_AUD_EXTCK1_DIV, + CLK_TOP_AUD_EXTCK2_DIV +}; + +static const int aud_src_parents[] = { + CLK_TOP_AUD_MUX1_SEL, + CLK_TOP_AUD_MUX2_SEL +}; + +static const struct mtk_composite top_muxes[] = { + MUX_GATE(CLK_TOP_AXI_SEL, axi_parents, 0x40, 0, 3, 7), + MUX_GATE(CLK_TOP_MEM_SEL, mem_parents, 0x40, 8, 1, 15), + MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, ddrphycfg_parents, 0x40, 16, 1, 23), + MUX_GATE_FLAGS(CLK_TOP_MM_SEL, mm_parents, 0x40, 24, 3, 31, + CLK_DOMAIN_SCPSYS), + + MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7), + MUX_GATE(CLK_TOP_VDEC_SEL, vdec_parents, 0x50, 8, 4, 15), + MUX_GATE_FLAGS(CLK_TOP_MFG_SEL, mfg_parents, 0x50, 16, 3, 23, + CLK_DOMAIN_SCPSYS), + MUX_GATE(CLK_TOP_CAMTG_SEL, camtg_parents, 0x50, 24, 3, 31), + + MUX_GATE(CLK_TOP_UART_SEL, uart_parents, 0x60, 0, 1, 7), + MUX_GATE(CLK_TOP_SPI0_SEL, spi_parents, 0x60, 8, 3, 15), + MUX_GATE(CLK_TOP_USB20_SEL, usb20_parents, 0x60, 16, 2, 23), + MUX_GATE(CLK_TOP_MSDC30_0_SEL, msdc30_parents, 0x60, 24, 3, 31), + + MUX_GATE(CLK_TOP_MSDC30_1_SEL, msdc30_parents, 0x70, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_2_SEL, msdc30_parents, 0x70, 8, 3, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, msdc30_parents, 0x70, 16, 1, 23), + MUX_GATE(CLK_TOP_AUDINTBUS_SEL, aud_intbus_parents, 0x70, 24, 3, 31), + + MUX_GATE(CLK_TOP_PMICSPI_SEL, pmicspi_parents, 0x80, 0, 4, 7), + MUX_GATE(CLK_TOP_SCP_SEL, scp_parents, 0x80, 8, 2, 15), + MUX_GATE(CLK_TOP_DPI0_SEL, dpi0_tve_parents, 0x80, 16, 3, 23), + MUX_GATE(CLK_TOP_DPI1_SEL, dpi1_parents, 0x80, 24, 2, 31), + + MUX_GATE(CLK_TOP_TVE_SEL, dpi0_tve_parents, 0x90, 0, 3, 7), + MUX_GATE(CLK_TOP_HDMI_SEL, hdmi_parents, 0x90, 8, 2, 15), + MUX_GATE(CLK_TOP_APLL_SEL, apll_parents, 0x90, 16, 3, 23), + + MUX_GATE(CLK_TOP_RTC_SEL, rtc_parents, 0xA0, 0, 2, 7), + MUX_GATE(CLK_TOP_NFI2X_SEL, nfi2x_parents, 0xA0, 8, 3, 15), + MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, emmc_hclk_parents, 0xA0, 24, 2, 31), + + MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0xB0, 0, 3, 7), + MUX_GATE(CLK_TOP_DI_SEL, di_parents, 0xB0, 8, 2, 15), + MUX_GATE(CLK_TOP_NR_SEL, nr_osd_parents, 0xB0, 16, 3, 23), + MUX_GATE(CLK_TOP_OSD_SEL, nr_osd_parents, 0xB0, 24, 3, 31), + + MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, hdmirx_bist_parents, 0xC0, 0, 3, 7), + MUX_GATE(CLK_TOP_INTDIR_SEL, intdir_parents, 0xC0, 8, 2, 15), + MUX_GATE(CLK_TOP_ASM_I_SEL, asm_parents, 0xC0, 16, 2, 23), + MUX_GATE(CLK_TOP_ASM_M_SEL, asm_parents, 0xC0, 24, 3, 31), + + MUX_GATE(CLK_TOP_ASM_H_SEL, asm_parents, 0xD0, 0, 2, 7), + MUX_GATE(CLK_TOP_MS_CARD_SEL, ms_card_parents, 0xD0, 16, 2, 23), + MUX_GATE_FLAGS(CLK_TOP_ETHIF_SEL, ethif_parents, 0xD0, 24, 3, 31, + CLK_DOMAIN_SCPSYS), + + MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, hdmirx_parents, 0xE0, 0, 1, 7), + MUX_GATE(CLK_TOP_MSDC30_3_SEL, msdc30_parents, 0xE0, 8, 3, 15), + MUX_GATE(CLK_TOP_CMSYS_SEL, cmsys_parents, 0xE0, 16, 4, 23), + + MUX_GATE(CLK_TOP_SPI1_SEL, spi_parents, 0xE0, 24, 3, 31), + MUX_GATE(CLK_TOP_SPI2_SEL, spi_parents, 0xF0, 0, 3, 7), + MUX_GATE(CLK_TOP_8BDAC_SEL, clk_8bdac_parents, 0xF0, 8, 2, 15), + MUX_GATE(CLK_TOP_AUD2DVD_SEL, aud2dvd_parents, 0xF0, 16, 1, 23), + + MUX(CLK_TOP_PADMCLK_SEL, padmclk_parents, 0x100, 0, 3), + + MUX(CLK_TOP_AUD_MUX1_SEL, aud_mux_parents, 0x12c, 0, 3), + MUX(CLK_TOP_AUD_MUX2_SEL, aud_mux_parents, 0x12c, 3, 3), + MUX(CLK_TOP_AUDPLL_MUX_SEL, aud_mux_parents, 0x12c, 6, 3), + + MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, aud_src_parents, 0x12c, 15, 1, 23), + MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, aud_src_parents, 0x12c, 16, 1, 24), + MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, aud_src_parents, 0x12c, 17, 1, 25), + MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, aud_src_parents, 0x12c, 18, 1, 26), + MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, aud_src_parents, 0x12c, 19, 1, 27), + MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, aud_src_parents, 0x12c, 20, 1, 28), +}; + +/* infracfg */ +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +#define GATE_INFRA(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +static const struct mtk_gate infra_cgs[] = { + GATE_INFRA(CLK_INFRA_DBG, CLK_TOP_AXI_SEL, 0), + GATE_INFRA(CLK_INFRA_SMI, CLK_TOP_MM_SEL, 1), + GATE_INFRA(CLK_INFRA_QAXI_CM4, CLK_TOP_AXI_SEL, 2), + GATE_INFRA(CLK_INFRA_AUD_SPLIN_B, CLK_TOP_HADDS2PLL_294M, 4), + GATE_INFRA(CLK_INFRA_AUDIO, CLK_XTAL, 5), + GATE_INFRA(CLK_INFRA_EFUSE, CLK_XTAL, 6), + GATE_INFRA(CLK_INFRA_L2C_SRAM, CLK_TOP_MM_SEL, 7), + GATE_INFRA(CLK_INFRA_M4U, CLK_TOP_MEM_SEL, 8), + GATE_INFRA(CLK_INFRA_CONNMCU, CLK_TOP_WBG_DIG_416M, 12), + GATE_INFRA(CLK_INFRA_TRNG, CLK_TOP_AXI_SEL, 13), + GATE_INFRA(CLK_INFRA_RAMBUFIF, CLK_TOP_MEM_SEL, 14), + GATE_INFRA(CLK_INFRA_CPUM, CLK_TOP_MEM_SEL, 15), + GATE_INFRA(CLK_INFRA_KP, CLK_TOP_AXI_SEL, 16), + GATE_INFRA(CLK_INFRA_CEC, CLK_TOP_RTC_SEL, 18), + GATE_INFRA(CLK_INFRA_IRRX, CLK_TOP_AXI_SEL, 19), + GATE_INFRA(CLK_INFRA_PMICSPI, CLK_TOP_PMICSPI_SEL, 22), + GATE_INFRA(CLK_INFRA_PMICWRAP, CLK_TOP_AXI_SEL, 23), + GATE_INFRA(CLK_INFRA_DDCCI, CLK_TOP_AXI_SEL, 24), +}; + +/* pericfg */ +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x10, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0xC, + .clr_ofs = 0x14, + .sta_ofs = 0x1C, +}; + +#define GATE_PERI0(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +#define GATE_PERI1(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +static const struct mtk_gate peri_cgs[] = { + GATE_PERI0(CLK_PERI_NFI, CLK_TOP_NFI2X_SEL, 0), + GATE_PERI0(CLK_PERI_THERM, CLK_TOP_AXI_SEL, 1), + GATE_PERI0(CLK_PERI_PWM1, CLK_TOP_AXISEL_D4, 2), + GATE_PERI0(CLK_PERI_PWM2, CLK_TOP_AXISEL_D4, 3), + GATE_PERI0(CLK_PERI_PWM3, CLK_TOP_AXISEL_D4, 4), + GATE_PERI0(CLK_PERI_PWM4, CLK_TOP_AXISEL_D4, 5), + GATE_PERI0(CLK_PERI_PWM5, CLK_TOP_AXISEL_D4, 6), + GATE_PERI0(CLK_PERI_PWM6, CLK_TOP_AXISEL_D4, 7), + GATE_PERI0(CLK_PERI_PWM7, CLK_TOP_AXISEL_D4, 8), + GATE_PERI0(CLK_PERI_PWM, CLK_TOP_AXI_SEL, 9), + GATE_PERI0(CLK_PERI_USB0, CLK_TOP_USB20_SEL, 10), + GATE_PERI0(CLK_PERI_USB1, CLK_TOP_USB20_SEL, 11), + GATE_PERI0(CLK_PERI_AP_DMA, CLK_TOP_AXI_SEL, 12), + GATE_PERI0(CLK_PERI_MSDC30_0, CLK_TOP_MSDC30_0_SEL, 13), + GATE_PERI0(CLK_PERI_MSDC30_1, CLK_TOP_MSDC30_1_SEL, 14), + GATE_PERI0(CLK_PERI_MSDC30_2, CLK_TOP_MSDC30_2_SEL, 15), + GATE_PERI0(CLK_PERI_MSDC30_3, CLK_TOP_MSDC30_3_SEL, 16), + GATE_PERI0(CLK_PERI_MSDC50_3, CLK_TOP_EMMC_HCLK_SEL, 17), + GATE_PERI0(CLK_PERI_NLI, CLK_TOP_AXI_SEL, 18), + GATE_PERI0(CLK_PERI_UART0, CLK_TOP_AXI_SEL, 19), + GATE_PERI0(CLK_PERI_UART1, CLK_TOP_AXI_SEL, 20), + GATE_PERI0(CLK_PERI_UART2, CLK_TOP_AXI_SEL, 21), + GATE_PERI0(CLK_PERI_UART3, CLK_TOP_AXI_SEL, 22), + GATE_PERI0(CLK_PERI_BTIF, CLK_TOP_AXI_SEL, 23), + GATE_PERI0(CLK_PERI_I2C0, CLK_TOP_AXI_SEL, 24), + GATE_PERI0(CLK_PERI_I2C1, CLK_TOP_AXI_SEL, 25), + GATE_PERI0(CLK_PERI_I2C2, CLK_TOP_AXI_SEL, 26), + GATE_PERI0(CLK_PERI_I2C3, CLK_XTAL, 27), + GATE_PERI0(CLK_PERI_AUXADC, CLK_XTAL, 28), + GATE_PERI0(CLK_PERI_SPI0, CLK_TOP_SPI0_SEL, 29), + GATE_PERI0(CLK_PERI_ETH, CLK_XTAL, 30), + GATE_PERI0(CLK_PERI_USB0_MCU, CLK_TOP_AXI_SEL, 31), + + GATE_PERI1(CLK_PERI_USB1_MCU, CLK_TOP_AXI_SEL, 0), + GATE_PERI1(CLK_PERI_USB_SLV, CLK_TOP_AXI_SEL, 1), + GATE_PERI1(CLK_PERI_GCPU, CLK_TOP_AXI_SEL, 2), + GATE_PERI1(CLK_PERI_NFI_ECC, CLK_TOP_NFI1X_PAD, 3), + GATE_PERI1(CLK_PERI_NFI_PAD, CLK_TOP_NFI1X_PAD, 4), + GATE_PERI1(CLK_PERI_FLASH, CLK_TOP_NFI2X_SEL, 5), + GATE_PERI1(CLK_PERI_HOST89_INT, CLK_TOP_AXI_SEL, 6), + GATE_PERI1(CLK_PERI_HOST89_SPI, CLK_TOP_SPI0_SEL, 7), + GATE_PERI1(CLK_PERI_HOST89_DVD, CLK_TOP_AUD2DVD_SEL, 8), + GATE_PERI1(CLK_PERI_SPI1, CLK_TOP_SPI1_SEL, 9), + GATE_PERI1(CLK_PERI_SPI2, CLK_TOP_SPI2_SEL, 10), + GATE_PERI1(CLK_PERI_FCI, CLK_TOP_MS_CARD_SEL, 11), +}; + +/* ethsys */ +static const struct mtk_gate_regs eth_cg_regs = { + .sta_ofs = 0x30, +}; + +#define GATE_ETH(_id, _parent, _shift, _flag) { \ + .id = _id, \ + .parent = _parent, \ + .regs = ð_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_NO_SETCLR_INV | (_flag), \ + } + +#define GATE_ETH0(_id, _parent, _shift) \ + GATE_ETH(_id, _parent, _shift, CLK_PARENT_APMIXED) + +#define GATE_ETH1(_id, _parent, _shift) \ + GATE_ETH(_id, _parent, _shift, CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate eth_cgs[] = { + GATE_ETH1(CLK_ETHSYS_HSDMA, CLK_TOP_ETHIF_SEL, 5), + GATE_ETH1(CLK_ETHSYS_ESW, CLK_TOP_ETHPLL_500M, 6), + GATE_ETH0(CLK_ETHSYS_GP2, CLK_APMIXED_TRGPLL, 7), + GATE_ETH1(CLK_ETHSYS_GP1, CLK_TOP_ETHPLL_500M, 8), + GATE_ETH1(CLK_ETHSYS_PCM, CLK_TOP_ETHIF_SEL, 11), + GATE_ETH1(CLK_ETHSYS_GDMA, CLK_TOP_ETHIF_SEL, 14), + GATE_ETH1(CLK_ETHSYS_I2S, CLK_TOP_ETHIF_SEL, 17), + GATE_ETH1(CLK_ETHSYS_CRYPTO, CLK_TOP_ETHIF_SEL, 29), +}; + +static const struct mtk_clk_tree mt7623_clk_tree = { + .xtal_rate = 26 * MHZ, + .xtal2_rate = 26 * MHZ, + .fdivs_offs = CLK_TOP_SYSPLL, + .muxes_offs = CLK_TOP_AXI_SEL, + .plls = apmixed_plls, + .fclks = top_fixed_clks, + .fdivs = top_fixed_divs, + .muxes = top_muxes, +}; + +static int mt7623_mcucfg_probe(struct udevice *dev) +{ + void __iomem *base; + + base = dev_read_addr_ptr(dev); + if (!base) + return -ENOENT; + + clrsetbits_le32(base + MCU_AXI_DIV, AXI_DIV_MSK, + AXI_DIV_SEL(0x12)); + + return 0; +} + +static int mt7623_apmixedsys_probe(struct udevice *dev) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + int ret; + + ret = mtk_common_clk_init(dev, &mt7623_clk_tree); + if (ret) + return ret; + + /* reduce clock square disable time */ + writel(0x50001, priv->base + MT7623_CLKSQ_STB_CON0); + /* extend control timing to 1us */ + writel(0x888, priv->base + MT7623_PLL_ISO_CON0); + + return 0; +} + +static int mt7623_topckgen_probe(struct udevice *dev) +{ + return mtk_common_clk_init(dev, &mt7623_clk_tree); +} + +static int mt7623_infracfg_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, infra_cgs); +} + +static int mt7623_pericfg_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, peri_cgs); +} + +static int mt7623_ethsys_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, eth_cgs); +} + +static const struct udevice_id mt7623_apmixed_compat[] = { + { .compatible = "mediatek,mt7623-apmixedsys" }, + { } +}; + +static const struct udevice_id mt7623_topckgen_compat[] = { + { .compatible = "mediatek,mt7623-topckgen" }, + { } +}; + +static const struct udevice_id mt7623_infracfg_compat[] = { + { .compatible = "mediatek,mt7623-infracfg", }, + { } +}; + +static const struct udevice_id mt7623_pericfg_compat[] = { + { .compatible = "mediatek,mt7623-pericfg", }, + { } +}; + +static const struct udevice_id mt7623_ethsys_compat[] = { + { .compatible = "mediatek,mt7623-ethsys" }, + { } +}; + +static const struct udevice_id mt7623_mcucfg_compat[] = { + { .compatible = "mediatek,mt7623-mcucfg" }, + { } +}; + +U_BOOT_DRIVER(mtk_mcucfg) = { + .name = "mt7623-mcucfg", + .id = UCLASS_SYSCON, + .of_match = mt7623_mcucfg_compat, + .probe = mt7623_mcucfg_probe, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_apmixedsys) = { + .name = "mt7623-clock-apmixedsys", + .id = UCLASS_CLK, + .of_match = mt7623_apmixed_compat, + .probe = mt7623_apmixedsys_probe, + .priv_auto_alloc_size = sizeof(struct mtk_clk_priv), + .ops = &mtk_clk_apmixedsys_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_topckgen) = { + .name = "mt7623-clock-topckgen", + .id = UCLASS_CLK, + .of_match = mt7623_topckgen_compat, + .probe = mt7623_topckgen_probe, + .priv_auto_alloc_size = sizeof(struct mtk_clk_priv), + .ops = &mtk_clk_topckgen_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_infracfg) = { + .name = "mt7623-infracfg", + .id = UCLASS_CLK, + .of_match = mt7623_infracfg_compat, + .probe = mt7623_infracfg_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_pericfg) = { + .name = "mt7623-pericfg", + .id = UCLASS_CLK, + .of_match = mt7623_pericfg_compat, + .probe = mt7623_pericfg_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_ethsys) = { + .name = "mt7623-clock-ethsys", + .id = UCLASS_CLK, + .of_match = mt7623_ethsys_compat, + .probe = mt7623_ethsys_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, +}; diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c new file mode 100644 index 00000000000..2601b6cf30d --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -0,0 +1,709 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek clock driver for MT7629 SoC + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <dt-bindings/clock/mt7629-clk.h> + +#include "clk-mtk.h" + +#define MT7629_CLKSQ_STB_CON0 0x20 +#define MT7629_PLL_ISO_CON0 0x2c +#define MT7629_PLL_FMAX (2500UL * MHZ) +#define MT7629_CON0_RST_BAR BIT(24) + +#define MCU_AXI_DIV 0x640 +#define AXI_DIV_MSK GENMASK(4, 0) +#define AXI_DIV_SEL(x) (x) + +#define MCU_BUS_MUX 0x7c0 +#define MCU_BUS_MSK GENMASK(10, 9) +#define MCU_BUS_SEL(x) ((x) << 9) + +/* apmixedsys */ +#define PLL(_id, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ + _pd_shift, _pcw_reg, _pcw_shift) { \ + .id = _id, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .rst_bar_mask = MT7629_CON0_RST_BAR, \ + .fmax = MT7629_PLL_FMAX, \ + .flags = _flags, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + } + +static const struct mtk_pll_data apmixed_plls[] = { + PLL(CLK_APMIXED_ARMPLL, 0x200, 0x20c, 0x1, 0, + 21, 0x204, 24, 0x204, 0), + PLL(CLK_APMIXED_MAINPLL, 0x210, 0x21c, 0x1, HAVE_RST_BAR, + 21, 0x214, 24, 0x214, 0), + PLL(CLK_APMIXED_UNIV2PLL, 0x220, 0x22c, 0x1, HAVE_RST_BAR, + 7, 0x224, 24, 0x224, 14), + PLL(CLK_APMIXED_ETH1PLL, 0x300, 0x310, 0x1, 0, + 21, 0x300, 1, 0x304, 0), + PLL(CLK_APMIXED_ETH2PLL, 0x314, 0x320, 0x1, 0, + 21, 0x314, 1, 0x318, 0), + PLL(CLK_APMIXED_SGMIPLL, 0x358, 0x368, 0x1, 0, + 21, 0x358, 1, 0x35c, 0), +}; + +/* topckgen */ +#define FACTOR0(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED) + +#define FACTOR1(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN) + +#define FACTOR2(_id, _parent, _mult, _div) \ + FACTOR(_id, _parent, _mult, _div, 0) + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_TO_U2_PHY, CLK_XTAL, 31250000), + FIXED_CLK(CLK_TOP_TO_U2_PHY_1P, CLK_XTAL, 31250000), + FIXED_CLK(CLK_TOP_PCIE0_PIPE_EN, CLK_XTAL, 125000000), + FIXED_CLK(CLK_TOP_PCIE1_PIPE_EN, CLK_XTAL, 125000000), + FIXED_CLK(CLK_TOP_SSUSB_TX250M, CLK_XTAL, 250000000), + FIXED_CLK(CLK_TOP_SSUSB_EQ_RX250M, CLK_XTAL, 250000000), + FIXED_CLK(CLK_TOP_SSUSB_CDR_REF, CLK_XTAL, 33333333), + FIXED_CLK(CLK_TOP_SSUSB_CDR_FB, CLK_XTAL, 50000000), + FIXED_CLK(CLK_TOP_SATA_ASIC, CLK_XTAL, 50000000), + FIXED_CLK(CLK_TOP_SATA_RBC, CLK_XTAL, 50000000), +}; + +static const struct mtk_fixed_factor top_fixed_divs[] = { + FACTOR0(CLK_TOP_TO_USB3_SYS, CLK_APMIXED_ETH1PLL, 1, 4), + FACTOR0(CLK_TOP_P1_1MHZ, CLK_APMIXED_ETH1PLL, 1, 500), + FACTOR0(CLK_TOP_4MHZ, CLK_APMIXED_ETH1PLL, 1, 125), + FACTOR0(CLK_TOP_P0_1MHZ, CLK_APMIXED_ETH1PLL, 1, 500), + FACTOR0(CLK_TOP_ETH_500M, CLK_APMIXED_ETH1PLL, 1, 1), + FACTOR1(CLK_TOP_TXCLK_SRC_PRE, CLK_TOP_SGMIIPLL_D2, 1, 1), + FACTOR2(CLK_TOP_RTC, CLK_XTAL, 1, 1024), + FACTOR2(CLK_TOP_PWM_QTR_26M, CLK_XTAL, 1, 1), + FACTOR2(CLK_TOP_CPUM_TCK_IN, CLK_XTAL, 1, 1), + FACTOR2(CLK_TOP_TO_USB3_DA_TOP, CLK_XTAL, 1, 1), + FACTOR2(CLK_TOP_MEMPLL, CLK_XTAL, 32, 1), + FACTOR1(CLK_TOP_DMPLL, CLK_TOP_MEMPLL, 1, 1), + FACTOR1(CLK_TOP_DMPLL_D4, CLK_TOP_MEMPLL, 1, 4), + FACTOR1(CLK_TOP_DMPLL_D8, CLK_TOP_MEMPLL, 1, 8), + FACTOR0(CLK_TOP_SYSPLL_D2, CLK_APMIXED_MAINPLL, 1, 2), + FACTOR0(CLK_TOP_SYSPLL1_D2, CLK_APMIXED_MAINPLL, 1, 4), + FACTOR0(CLK_TOP_SYSPLL1_D4, CLK_APMIXED_MAINPLL, 1, 8), + FACTOR0(CLK_TOP_SYSPLL1_D8, CLK_APMIXED_MAINPLL, 1, 16), + FACTOR0(CLK_TOP_SYSPLL1_D16, CLK_APMIXED_MAINPLL, 1, 32), + FACTOR0(CLK_TOP_SYSPLL2_D2, CLK_APMIXED_MAINPLL, 1, 6), + FACTOR0(CLK_TOP_SYSPLL2_D4, CLK_APMIXED_MAINPLL, 1, 12), + FACTOR0(CLK_TOP_SYSPLL2_D8, CLK_APMIXED_MAINPLL, 1, 24), + FACTOR0(CLK_TOP_SYSPLL_D5, CLK_APMIXED_MAINPLL, 1, 5), + FACTOR0(CLK_TOP_SYSPLL3_D2, CLK_APMIXED_MAINPLL, 1, 10), + FACTOR0(CLK_TOP_SYSPLL3_D4, CLK_APMIXED_MAINPLL, 1, 20), + FACTOR0(CLK_TOP_SYSPLL_D7, CLK_APMIXED_MAINPLL, 1, 7), + FACTOR0(CLK_TOP_SYSPLL4_D2, CLK_APMIXED_MAINPLL, 1, 14), + FACTOR0(CLK_TOP_SYSPLL4_D4, CLK_APMIXED_MAINPLL, 1, 28), + FACTOR0(CLK_TOP_SYSPLL4_D16, CLK_APMIXED_MAINPLL, 1, 112), + FACTOR0(CLK_TOP_UNIVPLL, CLK_APMIXED_UNIV2PLL, 1, 2), + FACTOR1(CLK_TOP_UNIVPLL1_D2, CLK_TOP_UNIVPLL, 1, 4), + FACTOR1(CLK_TOP_UNIVPLL1_D4, CLK_TOP_UNIVPLL, 1, 8), + FACTOR1(CLK_TOP_UNIVPLL1_D8, CLK_TOP_UNIVPLL, 1, 16), + FACTOR1(CLK_TOP_UNIVPLL_D3, CLK_TOP_UNIVPLL, 1, 3), + FACTOR1(CLK_TOP_UNIVPLL2_D2, CLK_TOP_UNIVPLL, 1, 6), + FACTOR1(CLK_TOP_UNIVPLL2_D4, CLK_TOP_UNIVPLL, 1, 12), + FACTOR1(CLK_TOP_UNIVPLL2_D8, CLK_TOP_UNIVPLL, 1, 24), + FACTOR1(CLK_TOP_UNIVPLL2_D16, CLK_TOP_UNIVPLL, 1, 48), + FACTOR1(CLK_TOP_UNIVPLL_D5, CLK_TOP_UNIVPLL, 1, 5), + FACTOR1(CLK_TOP_UNIVPLL3_D2, CLK_TOP_UNIVPLL, 1, 10), + FACTOR1(CLK_TOP_UNIVPLL3_D4, CLK_TOP_UNIVPLL, 1, 20), + FACTOR1(CLK_TOP_UNIVPLL3_D16, CLK_TOP_UNIVPLL, 1, 80), + FACTOR1(CLK_TOP_UNIVPLL_D7, CLK_TOP_UNIVPLL, 1, 7), + FACTOR1(CLK_TOP_UNIVPLL_D80_D4, CLK_TOP_UNIVPLL, 1, 320), + FACTOR1(CLK_TOP_UNIV48M, CLK_TOP_UNIVPLL, 1, 25), + FACTOR0(CLK_TOP_SGMIIPLL_D2, CLK_APMIXED_SGMIPLL, 1, 2), + FACTOR2(CLK_TOP_CLKXTAL_D4, CLK_XTAL, 1, 4), + FACTOR1(CLK_TOP_HD_FAXI, CLK_TOP_AXI_SEL, 1, 1), + FACTOR1(CLK_TOP_FAXI, CLK_TOP_AXI_SEL, 1, 1), + FACTOR1(CLK_TOP_F_FAUD_INTBUS, CLK_TOP_AUD_INTBUS_SEL, 1, 1), + FACTOR1(CLK_TOP_AP2WBHIF_HCLK, CLK_TOP_SYSPLL1_D8, 1, 1), + FACTOR1(CLK_TOP_10M_INFRAO, CLK_TOP_10M_SEL, 1, 1), + FACTOR1(CLK_TOP_MSDC30_1, CLK_TOP_MSDC30_1, 1, 1), + FACTOR1(CLK_TOP_SPI, CLK_TOP_SPI0_SEL, 1, 1), + FACTOR1(CLK_TOP_SF, CLK_TOP_NFI_INFRA_SEL, 1, 1), + FACTOR1(CLK_TOP_FLASH, CLK_TOP_FLASH_SEL, 1, 1), + FACTOR1(CLK_TOP_TO_USB3_REF, CLK_TOP_SATA_SEL, 1, 4), + FACTOR1(CLK_TOP_TO_USB3_MCU, CLK_TOP_AXI_SEL, 1, 1), + FACTOR1(CLK_TOP_TO_USB3_DMA, CLK_TOP_HIF_SEL, 1, 1), + FACTOR1(CLK_TOP_FROM_TOP_AHB, CLK_TOP_AXI_SEL, 1, 1), + FACTOR1(CLK_TOP_FROM_TOP_AXI, CLK_TOP_HIF_SEL, 1, 1), + FACTOR1(CLK_TOP_PCIE1_MAC_EN, CLK_TOP_UNIVPLL1_D4, 1, 1), + FACTOR1(CLK_TOP_PCIE0_MAC_EN, CLK_TOP_UNIVPLL1_D4, 1, 1), +}; + +static const int axi_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL_D5, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_UNIVPLL_D7, + CLK_TOP_DMPLL +}; + +static const int mem_parents[] = { + CLK_XTAL, + CLK_TOP_DMPLL +}; + +static const int ddrphycfg_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8 +}; + +static const int eth_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_SGMIIPLL_D2, + CLK_TOP_UNIVPLL_D7, + CLK_TOP_DMPLL +}; + +static const int pwm_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int f10m_ref_parents[] = { + CLK_XTAL, + CLK_TOP_SGMIIPLL_D2 +}; + +static const int nfi_infra_parents[] = { + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_XTAL, + CLK_TOP_UNIVPLL2_D8, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_UNIVPLL1_D8, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL3_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_SYSPLL_D7 +}; + +static const int flash_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL_D80_D4, + CLK_TOP_SYSPLL2_D8, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_UNIVPLL1_D8, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int uart_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D8 +}; + +static const int spi0_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL3_D2, + CLK_XTAL, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL1_D8, + CLK_XTAL +}; + +static const int spi1_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL3_D2, + CLK_XTAL, + CLK_TOP_SYSPLL4_D4, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_UNIVPLL1_D8, + CLK_XTAL +}; + +static const int msdc30_0_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D16, + CLK_TOP_UNIV48M +}; + +static const int msdc30_1_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D16, + CLK_TOP_UNIV48M, + CLK_TOP_SYSPLL2_D4, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_SYSPLL_D7, + CLK_TOP_SYSPLL2_D2, + CLK_TOP_UNIVPLL2_D2 +}; + +static const int ap2wbmcu_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_UNIV48M, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_SYSPLL_D7, + CLK_TOP_SYSPLL2_D2, + CLK_TOP_UNIVPLL2_D2 +}; + +static const int audio_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_SYSPLL4_D4, + CLK_TOP_SYSPLL1_D16 +}; + +static const int aud_intbus_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_SYSPLL4_D2, + CLK_TOP_DMPLL_D4 +}; + +static const int pmicspi_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_SYSPLL3_D4, + CLK_TOP_SYSPLL1_D16, + CLK_TOP_UNIVPLL3_D4, + CLK_XTAL, + CLK_TOP_UNIVPLL2_D4, + CLK_TOP_DMPLL_D8 +}; + +static const int scp_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D8, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int atb_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_SYSPLL_D5 +}; + +static const int hif_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_SYSPLL1_D4, + CLK_TOP_UNIVPLL_D5, + -1, + CLK_TOP_UNIVPLL_D7 +}; + +static const int sata_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL2_D4 +}; + +static const int usb20_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL3_D4, + CLK_TOP_SYSPLL1_D8 +}; + +static const int aud1_parents[] = { + CLK_XTAL +}; + +static const int irrx_parents[] = { + CLK_XTAL, + CLK_TOP_SYSPLL4_D16 +}; + +static const int crypto_parents[] = { + CLK_XTAL, + CLK_TOP_UNIVPLL_D3, + CLK_TOP_UNIVPLL1_D2, + CLK_TOP_SYSPLL1_D2, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_SYSPLL_D5, + CLK_TOP_UNIVPLL2_D2, + CLK_TOP_SYSPLL_D2 +}; + +static const int gpt10m_parents[] = { + CLK_XTAL, + CLK_TOP_CLKXTAL_D4 +}; + +static const struct mtk_composite top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE(CLK_TOP_AXI_SEL, axi_parents, 0x40, 0, 3, 7), + MUX_GATE(CLK_TOP_MEM_SEL, mem_parents, 0x40, 8, 1, 15), + MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, ddrphycfg_parents, 0x40, 16, 1, 23), + MUX_GATE(CLK_TOP_ETH_SEL, eth_parents, 0x40, 24, 3, 31), + + /* CLK_CFG_1 */ + MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7), + MUX_GATE(CLK_TOP_F10M_REF_SEL, f10m_ref_parents, 0x50, 8, 1, 15), + MUX_GATE(CLK_TOP_NFI_INFRA_SEL, nfi_infra_parents, 0x50, 16, 4, 23), + MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0x50, 24, 3, 31), + + /* CLK_CFG_2 */ + MUX_GATE(CLK_TOP_UART_SEL, uart_parents, 0x60, 0, 1, 7), + MUX_GATE(CLK_TOP_SPI0_SEL, spi0_parents, 0x60, 8, 3, 15), + MUX_GATE(CLK_TOP_SPI1_SEL, spi1_parents, 0x60, 16, 3, 23), + MUX_GATE(CLK_TOP_MSDC50_0_SEL, uart_parents, 0x60, 24, 3, 31), + + /* CLK_CFG_3 */ + MUX_GATE(CLK_TOP_MSDC30_0_SEL, msdc30_0_parents, 0x70, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_1_SEL, msdc30_1_parents, 0x70, 8, 3, 15), + MUX_GATE(CLK_TOP_AP2WBMCU_SEL, ap2wbmcu_parents, 0x70, 16, 3, 23), + MUX_GATE(CLK_TOP_AP2WBHIF_SEL, ap2wbmcu_parents, 0x70, 24, 3, 31), + + /* CLK_CFG_4 */ + MUX_GATE(CLK_TOP_AUDIO_SEL, audio_parents, 0x80, 0, 2, 7), + MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, aud_intbus_parents, 0x80, 8, 2, 15), + MUX_GATE(CLK_TOP_PMICSPI_SEL, pmicspi_parents, 0x80, 16, 3, 23), + MUX_GATE(CLK_TOP_SCP_SEL, scp_parents, 0x80, 24, 2, 31), + + /* CLK_CFG_5 */ + MUX_GATE(CLK_TOP_ATB_SEL, atb_parents, 0x90, 0, 2, 7), + MUX_GATE_FLAGS(CLK_TOP_HIF_SEL, hif_parents, 0x90, 8, 3, 15, + CLK_DOMAIN_SCPSYS), + MUX_GATE(CLK_TOP_SATA_SEL, sata_parents, 0x90, 16, 1, 23), + MUX_GATE(CLK_TOP_U2_SEL, usb20_parents, 0x90, 24, 2, 31), + + /* CLK_CFG_6 */ + MUX_GATE(CLK_TOP_AUD1_SEL, aud1_parents, 0xA0, 0, 1, 7), + MUX_GATE(CLK_TOP_AUD2_SEL, aud1_parents, 0xA0, 8, 1, 15), + MUX_GATE(CLK_TOP_IRRX_SEL, irrx_parents, 0xA0, 16, 1, 23), + MUX_GATE(CLK_TOP_IRTX_SEL, irrx_parents, 0xA0, 24, 1, 31), + + /* CLK_CFG_7 */ + MUX_GATE(CLK_TOP_SATA_MCU_SEL, scp_parents, 0xB0, 0, 2, 7), + MUX_GATE(CLK_TOP_PCIE0_MCU_SEL, scp_parents, 0xB0, 8, 2, 15), + MUX_GATE(CLK_TOP_PCIE1_MCU_SEL, scp_parents, 0xB0, 16, 2, 23), + MUX_GATE(CLK_TOP_SSUSB_MCU_SEL, scp_parents, 0xB0, 24, 2, 31), + + /* CLK_CFG_8 */ + MUX_GATE(CLK_TOP_CRYPTO_SEL, crypto_parents, 0xC0, 0, 3, 7), + MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, f10m_ref_parents, 0xC0, 8, 1, 15), + MUX_GATE(CLK_TOP_10M_SEL, gpt10m_parents, 0xC0, 16, 1, 23), +}; + +/* infracfg */ +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +#define GATE_INFRA(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +static const struct mtk_gate infra_cgs[] = { + GATE_INFRA(CLK_INFRA_DBGCLK_PD, CLK_TOP_HD_FAXI, 0), + GATE_INFRA(CLK_INFRA_TRNG_PD, CLK_TOP_HD_FAXI, 2), + GATE_INFRA(CLK_INFRA_DEVAPC_PD, CLK_TOP_HD_FAXI, 4), + GATE_INFRA(CLK_INFRA_APXGPT_PD, CLK_TOP_10M_INFRAO, 18), + GATE_INFRA(CLK_INFRA_SEJ_PD, CLK_TOP_10M_INFRAO, 19), +}; + +/* pericfg */ +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x10, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0xC, + .clr_ofs = 0x14, + .sta_ofs = 0x1C, +}; + +#define GATE_PERI0(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +#define GATE_PERI1(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN, \ + } + +static const struct mtk_gate peri_cgs[] = { + GATE_PERI0(CLK_PERI_PWM1_PD, CLK_TOP_PWM_QTR_26M, 2), + GATE_PERI0(CLK_PERI_PWM2_PD, CLK_TOP_PWM_QTR_26M, 3), + GATE_PERI0(CLK_PERI_PWM3_PD, CLK_TOP_PWM_QTR_26M, 4), + GATE_PERI0(CLK_PERI_PWM4_PD, CLK_TOP_PWM_QTR_26M, 5), + GATE_PERI0(CLK_PERI_PWM5_PD, CLK_TOP_PWM_QTR_26M, 6), + GATE_PERI0(CLK_PERI_PWM6_PD, CLK_TOP_PWM_QTR_26M, 7), + GATE_PERI0(CLK_PERI_PWM7_PD, CLK_TOP_PWM_QTR_26M, 8), + GATE_PERI0(CLK_PERI_PWM_PD, CLK_TOP_PWM_QTR_26M, 9), + GATE_PERI0(CLK_PERI_AP_DMA_PD, CLK_TOP_FAXI, 12), + GATE_PERI0(CLK_PERI_MSDC30_1_PD, CLK_TOP_MSDC30_1, 14), + GATE_PERI0(CLK_PERI_UART0_PD, CLK_TOP_FAXI, 17), + GATE_PERI0(CLK_PERI_UART1_PD, CLK_TOP_FAXI, 18), + GATE_PERI0(CLK_PERI_UART2_PD, CLK_TOP_FAXI, 19), + GATE_PERI0(CLK_PERI_UART3_PD, CLK_TOP_FAXI, 20), + GATE_PERI0(CLK_PERI_BTIF_PD, CLK_TOP_FAXI, 22), + GATE_PERI0(CLK_PERI_I2C0_PD, CLK_TOP_FAXI, 23), + GATE_PERI0(CLK_PERI_SPI0_PD, CLK_TOP_SPI, 28), + GATE_PERI0(CLK_PERI_SNFI_PD, CLK_TOP_SF, 29), + GATE_PERI0(CLK_PERI_NFI_PD, CLK_TOP_FAXI, 30), + GATE_PERI0(CLK_PERI_NFIECC_PD, CLK_TOP_FAXI, 31), + GATE_PERI1(CLK_PERI_FLASH_PD, CLK_TOP_FLASH, 1), +}; + +/* ethsys */ +static const struct mtk_gate_regs eth_cg_regs = { + .sta_ofs = 0x30, +}; + +#define GATE_ETH(_id, _parent, _shift, _flag) { \ + .id = _id, \ + .parent = _parent, \ + .regs = ð_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_NO_SETCLR_INV | (_flag), \ + } + +#define GATE_ETH0(_id, _parent, _shift) \ + GATE_ETH(_id, _parent, _shift, CLK_PARENT_APMIXED) + +#define GATE_ETH1(_id, _parent, _shift) \ + GATE_ETH(_id, _parent, _shift, CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate eth_cgs[] = { + GATE_ETH0(CLK_ETH_FE_EN, CLK_APMIXED_ETH2PLL, 6), + GATE_ETH1(CLK_ETH_GP2_EN, CLK_TOP_TXCLK_SRC_PRE, 7), + GATE_ETH1(CLK_ETH_GP1_EN, CLK_TOP_TXCLK_SRC_PRE, 8), + GATE_ETH1(CLK_ETH_GP0_EN, CLK_TOP_TXCLK_SRC_PRE, 9), + GATE_ETH1(CLK_ETH_ESW_EN, CLK_TOP_ETH_500M, 16), +}; + +static const struct mtk_gate_regs sgmii_cg_regs = { + .set_ofs = 0xE4, + .clr_ofs = 0xE4, + .sta_ofs = 0xE4, +}; + +#define GATE_SGMII(_id, _parent, _shift) { \ + .id = _id, \ + .parent = _parent, \ + .regs = &sgmii_cg_regs, \ + .shift = _shift, \ + .flags = CLK_GATE_NO_SETCLR_INV | CLK_PARENT_TOPCKGEN, \ +} + +static const struct mtk_gate sgmii_cgs[] = { + GATE_SGMII(CLK_SGMII_TX_EN, CLK_TOP_SSUSB_TX250M, 2), + GATE_SGMII(CLK_SGMII_RX_EN, CLK_TOP_SSUSB_EQ_RX250M, 3), + GATE_SGMII(CLK_SGMII_CDR_REF, CLK_TOP_SSUSB_CDR_REF, 4), + GATE_SGMII(CLK_SGMII_CDR_FB, CLK_TOP_SSUSB_CDR_FB, 5), +}; + +static const struct mtk_clk_tree mt7629_clk_tree = { + .xtal_rate = 40 * MHZ, + .xtal2_rate = 20 * MHZ, + .fdivs_offs = CLK_TOP_TO_USB3_SYS, + .muxes_offs = CLK_TOP_AXI_SEL, + .plls = apmixed_plls, + .fclks = top_fixed_clks, + .fdivs = top_fixed_divs, + .muxes = top_muxes, +}; + +static int mt7629_mcucfg_probe(struct udevice *dev) +{ + void __iomem *base; + + base = dev_read_addr_ptr(dev); + if (!base) + return -ENOENT; + + clrsetbits_le32(base + MCU_AXI_DIV, AXI_DIV_MSK, + AXI_DIV_SEL(0x12)); + clrsetbits_le32(base + MCU_BUS_MUX, MCU_BUS_MSK, + MCU_BUS_SEL(0x1)); + + return 0; +} + +static int mt7629_apmixedsys_probe(struct udevice *dev) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + int ret; + + ret = mtk_common_clk_init(dev, &mt7629_clk_tree); + if (ret) + return ret; + + /* reduce clock square disable time */ + writel(0x501, priv->base + MT7629_CLKSQ_STB_CON0); + /* extend pwr/iso control timing to 1us */ + writel(0x80008, priv->base + MT7629_PLL_ISO_CON0); + + return 0; +} + +static int mt7629_topckgen_probe(struct udevice *dev) +{ + return mtk_common_clk_init(dev, &mt7629_clk_tree); +} + +static int mt7629_infracfg_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, infra_cgs); +} + +static int mt7629_pericfg_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, peri_cgs); +} + +static int mt7629_ethsys_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs); +} + +static int mt7629_sgmiisys_probe(struct udevice *dev) +{ + return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs); +} + +static const struct udevice_id mt7629_apmixed_compat[] = { + { .compatible = "mediatek,mt7629-apmixedsys" }, + { } +}; + +static const struct udevice_id mt7629_topckgen_compat[] = { + { .compatible = "mediatek,mt7629-topckgen" }, + { } +}; + +static const struct udevice_id mt7629_infracfg_compat[] = { + { .compatible = "mediatek,mt7629-infracfg", }, + { } +}; + +static const struct udevice_id mt7629_pericfg_compat[] = { + { .compatible = "mediatek,mt7629-pericfg", }, + { } +}; + +static const struct udevice_id mt7629_ethsys_compat[] = { + { .compatible = "mediatek,mt7629-ethsys", }, + { } +}; + +static const struct udevice_id mt7629_sgmiisys_compat[] = { + { .compatible = "mediatek,mt7629-sgmiisys", }, + { } +}; + +static const struct udevice_id mt7629_mcucfg_compat[] = { + { .compatible = "mediatek,mt7629-mcucfg" }, + { } +}; + +U_BOOT_DRIVER(mtk_mcucfg) = { + .name = "mt7629-mcucfg", + .id = UCLASS_SYSCON, + .of_match = mt7629_mcucfg_compat, + .probe = mt7629_mcucfg_probe, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_apmixedsys) = { + .name = "mt7629-clock-apmixedsys", + .id = UCLASS_CLK, + .of_match = mt7629_apmixed_compat, + .probe = mt7629_apmixedsys_probe, + .priv_auto_alloc_size = sizeof(struct mtk_clk_priv), + .ops = &mtk_clk_apmixedsys_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_topckgen) = { + .name = "mt7629-clock-topckgen", + .id = UCLASS_CLK, + .of_match = mt7629_topckgen_compat, + .probe = mt7629_topckgen_probe, + .priv_auto_alloc_size = sizeof(struct mtk_clk_priv), + .ops = &mtk_clk_topckgen_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_infracfg) = { + .name = "mt7629-clock-infracfg", + .id = UCLASS_CLK, + .of_match = mt7629_infracfg_compat, + .probe = mt7629_infracfg_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_pericfg) = { + .name = "mt7629-clock-pericfg", + .id = UCLASS_CLK, + .of_match = mt7629_pericfg_compat, + .probe = mt7629_pericfg_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +U_BOOT_DRIVER(mtk_clk_ethsys) = { + .name = "mt7629-clock-ethsys", + .id = UCLASS_CLK, + .of_match = mt7629_ethsys_compat, + .probe = mt7629_ethsys_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, +}; + +U_BOOT_DRIVER(mtk_clk_sgmiisys) = { + .name = "mt7629-clock-sgmiisys", + .id = UCLASS_CLK, + .of_match = mt7629_sgmiisys_compat, + .probe = mt7629_sgmiisys_probe, + .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), + .ops = &mtk_clk_gate_ops, +}; diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c new file mode 100644 index 00000000000..870b14ed8b2 --- /dev/null +++ b/drivers/clk/mediatek/clk-mtk.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek common clock driver + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <clk-uclass.h> +#include <div64.h> +#include <dm.h> +#include <asm/io.h> + +#include "clk-mtk.h" + +#define REG_CON0 0 +#define REG_CON1 4 + +#define CON0_BASE_EN BIT(0) +#define CON0_PWR_ON BIT(0) +#define CON0_ISO_EN BIT(1) +#define CON1_PCW_CHG BIT(31) + +#define POSTDIV_MASK 0x7 +#define INTEGER_BITS 7 + +/* scpsys clock off control */ +#define CLK_SCP_CFG0 0x200 +#define CLK_SCP_CFG1 0x204 +#define SCP_ARMCK_OFF_EN GENMASK(9, 0) +#define SCP_AXICK_DCM_DIS_EN BIT(0) +#define SCP_AXICK_26M_SEL_EN BIT(4) + +/* shared functions */ + +/* + * In case the rate change propagation to parent clocks is undesirable, + * this function is recursively called to find the parent to calculate + * the accurate frequency. + */ +static int mtk_clk_find_parent_rate(struct clk *clk, int id, + const struct driver *drv) +{ + struct clk parent = { .id = id, }; + + if (drv) { + struct udevice *dev; + + if (uclass_get_device_by_driver(UCLASS_CLK, drv, &dev)) + return -ENODEV; + + parent.dev = dev; + } else { + parent.dev = clk->dev; + } + + return clk_get_rate(&parent); +} + +static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent, + const struct mtk_composite *mux) +{ + u32 val, index = 0; + + while (mux->parent[index] != parent) + if (++index == mux->num_parents) + return -EINVAL; + + /* switch mux to a select parent */ + val = readl(base + mux->mux_reg); + val &= ~(mux->mux_mask << mux->mux_shift); + + val |= index << mux->mux_shift; + writel(val, base + mux->mux_reg); + + return 0; +} + +/* apmixedsys functions */ + +static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll, + u32 fin, u32 pcw, int postdiv) +{ + int pcwbits = pll->pcwbits; + int pcwfbits; + u64 vco; + u8 c = 0; + + /* The fractional part of the PLL divider. */ + pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0; + + vco = (u64)fin * pcw; + + if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0))) + c = 1; + + vco >>= pcwfbits; + + if (c) + vco++; + + return ((unsigned long)vco + postdiv - 1) / postdiv; +} + +/** + * MediaTek PLLs are configured through their pcw value. The pcw value + * describes a divider in the PLL feedback loop which consists of 7 bits + * for the integer part and the remaining bits (if present) for the + * fractional part. Also they have a 3 bit power-of-two post divider. + */ +static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_pll_data *pll = &priv->tree->plls[clk->id]; + u32 val; + + /* set postdiv */ + val = readl(priv->base + pll->pd_reg); + val &= ~(POSTDIV_MASK << pll->pd_shift); + val |= (ffs(postdiv) - 1) << pll->pd_shift; + + /* postdiv and pcw need to set at the same time if on same register */ + if (pll->pd_reg != pll->pcw_reg) { + writel(val, priv->base + pll->pd_reg); + val = readl(priv->base + pll->pcw_reg); + } + + /* set pcw */ + val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift); + val |= pcw << pll->pcw_shift; + val &= ~CON1_PCW_CHG; + writel(val, priv->base + pll->pcw_reg); + + val |= CON1_PCW_CHG; + writel(val, priv->base + pll->pcw_reg); + + udelay(20); +} + +/** + * mtk_pll_calc_values - calculate good values for a given input frequency. + * @clk: The clk + * @pcw: The pcw value (output) + * @postdiv: The post divider (output) + * @freq: The desired target frequency + */ +static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv, + u32 freq) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_pll_data *pll = &priv->tree->plls[clk->id]; + unsigned long fmin = 1000 * MHZ; + u64 _pcw; + u32 val; + + if (freq > pll->fmax) + freq = pll->fmax; + + for (val = 0; val < 5; val++) { + *postdiv = 1 << val; + if ((u64)freq * *postdiv >= fmin) + break; + } + + /* _pcw = freq * postdiv / xtal_rate * 2^pcwfbits */ + _pcw = ((u64)freq << val) << (pll->pcwbits - INTEGER_BITS); + do_div(_pcw, priv->tree->xtal2_rate); + + *pcw = (u32)_pcw; +} + +static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate) +{ + u32 pcw = 0; + u32 postdiv; + + mtk_pll_calc_values(clk, &pcw, &postdiv, rate); + mtk_pll_set_rate_regs(clk, pcw, postdiv); + + return 0; +} + +static ulong mtk_apmixedsys_get_rate(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_pll_data *pll = &priv->tree->plls[clk->id]; + u32 postdiv; + u32 pcw; + + postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) & + POSTDIV_MASK; + postdiv = 1 << postdiv; + + pcw = readl(priv->base + pll->pcw_reg) >> pll->pcw_shift; + pcw &= GENMASK(pll->pcwbits - 1, 0); + + return __mtk_pll_recalc_rate(pll, priv->tree->xtal2_rate, + pcw, postdiv); +} + +static int mtk_apmixedsys_enable(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_pll_data *pll = &priv->tree->plls[clk->id]; + u32 r; + + r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON; + writel(r, priv->base + pll->pwr_reg); + udelay(1); + + r = readl(priv->base + pll->pwr_reg) & ~CON0_ISO_EN; + writel(r, priv->base + pll->pwr_reg); + udelay(1); + + r = readl(priv->base + pll->reg + REG_CON0); + r |= pll->en_mask; + writel(r, priv->base + pll->reg + REG_CON0); + + udelay(20); + + if (pll->flags & HAVE_RST_BAR) { + r = readl(priv->base + pll->reg + REG_CON0); + r |= pll->rst_bar_mask; + writel(r, priv->base + pll->reg + REG_CON0); + } + + return 0; +} + +static int mtk_apmixedsys_disable(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_pll_data *pll = &priv->tree->plls[clk->id]; + u32 r; + + if (pll->flags & HAVE_RST_BAR) { + r = readl(priv->base + pll->reg + REG_CON0); + r &= ~pll->rst_bar_mask; + writel(r, priv->base + pll->reg + REG_CON0); + } + + r = readl(priv->base + pll->reg + REG_CON0); + r &= ~CON0_BASE_EN; + writel(r, priv->base + pll->reg + REG_CON0); + + r = readl(priv->base + pll->pwr_reg) | CON0_ISO_EN; + writel(r, priv->base + pll->pwr_reg); + + r = readl(priv->base + pll->pwr_reg) & ~CON0_PWR_ON; + writel(r, priv->base + pll->pwr_reg); + + return 0; +} + +/* topckgen functions */ + +static ulong mtk_factor_recalc_rate(const struct mtk_fixed_factor *fdiv, + ulong parent_rate) +{ + u64 rate = parent_rate * fdiv->mult; + + do_div(rate, fdiv->div); + + return rate; +} + +static int mtk_topckgen_get_factor_rate(struct clk *clk, u32 off) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off]; + ulong rate; + + switch (fdiv->flags & CLK_PARENT_MASK) { + case CLK_PARENT_APMIXED: + rate = mtk_clk_find_parent_rate(clk, fdiv->parent, + DM_GET_DRIVER(mtk_clk_apmixedsys)); + break; + case CLK_PARENT_TOPCKGEN: + rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL); + break; + + default: + rate = priv->tree->xtal_rate; + } + + return mtk_factor_recalc_rate(fdiv, rate); +} + +static int mtk_topckgen_get_mux_rate(struct clk *clk, u32 off) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_composite *mux = &priv->tree->muxes[off]; + u32 index; + + index = readl(priv->base + mux->mux_reg); + index &= mux->mux_mask << mux->mux_shift; + index = index >> mux->mux_shift; + + if (mux->parent[index]) + return mtk_clk_find_parent_rate(clk, mux->parent[index], + NULL); + + return priv->tree->xtal_rate; +} + +static ulong mtk_topckgen_get_rate(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->tree->fdivs_offs) + return priv->tree->fclks[clk->id].rate; + else if (clk->id < priv->tree->muxes_offs) + return mtk_topckgen_get_factor_rate(clk, clk->id - + priv->tree->fdivs_offs); + else + return mtk_topckgen_get_mux_rate(clk, clk->id - + priv->tree->muxes_offs); +} + +static int mtk_topckgen_enable(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_composite *mux; + u32 val; + + if (clk->id < priv->tree->muxes_offs) + return 0; + + mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs]; + if (mux->gate_shift < 0) + return 0; + + /* enable clock gate */ + val = readl(priv->base + mux->gate_reg); + val &= ~BIT(mux->gate_shift); + writel(val, priv->base + mux->gate_reg); + + if (mux->flags & CLK_DOMAIN_SCPSYS) { + /* enable scpsys clock off control */ + writel(SCP_ARMCK_OFF_EN, priv->base + CLK_SCP_CFG0); + writel(SCP_AXICK_DCM_DIS_EN | SCP_AXICK_26M_SEL_EN, + priv->base + CLK_SCP_CFG1); + } + + return 0; +} + +static int mtk_topckgen_disable(struct clk *clk) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + const struct mtk_composite *mux; + u32 val; + + if (clk->id < priv->tree->muxes_offs) + return 0; + + mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs]; + if (mux->gate_shift < 0) + return 0; + + /* disable clock gate */ + val = readl(priv->base + mux->gate_reg); + val |= BIT(mux->gate_shift); + writel(val, priv->base + mux->gate_reg); + + return 0; +} + +static int mtk_topckgen_set_parent(struct clk *clk, struct clk *parent) +{ + struct mtk_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->tree->muxes_offs) + return 0; + + return mtk_clk_mux_set_parent(priv->base, parent->id, + &priv->tree->muxes[clk->id - priv->tree->muxes_offs]); +} + +/* CG functions */ + +static int mtk_clk_gate_enable(struct clk *clk) +{ + struct mtk_cg_priv *priv = dev_get_priv(clk->dev); + const struct mtk_gate *gate = &priv->gates[clk->id]; + u32 bit = BIT(gate->shift); + + switch (gate->flags & CLK_GATE_MASK) { + case CLK_GATE_SETCLR: + writel(bit, priv->base + gate->regs->clr_ofs); + break; + case CLK_GATE_NO_SETCLR_INV: + clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mtk_clk_gate_disable(struct clk *clk) +{ + struct mtk_cg_priv *priv = dev_get_priv(clk->dev); + const struct mtk_gate *gate = &priv->gates[clk->id]; + u32 bit = BIT(gate->shift); + + switch (gate->flags & CLK_GATE_MASK) { + case CLK_GATE_SETCLR: + writel(bit, priv->base + gate->regs->set_ofs); + break; + case CLK_GATE_NO_SETCLR_INV: + clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static ulong mtk_clk_gate_get_rate(struct clk *clk) +{ + struct mtk_cg_priv *priv = dev_get_priv(clk->dev); + const struct mtk_gate *gate = &priv->gates[clk->id]; + + switch (gate->flags & CLK_PARENT_MASK) { + case CLK_PARENT_APMIXED: + return mtk_clk_find_parent_rate(clk, gate->parent, + DM_GET_DRIVER(mtk_clk_apmixedsys)); + break; + case CLK_PARENT_TOPCKGEN: + return mtk_clk_find_parent_rate(clk, gate->parent, + DM_GET_DRIVER(mtk_clk_topckgen)); + break; + + default: + return priv->tree->xtal_rate; + } +} + +const struct clk_ops mtk_clk_apmixedsys_ops = { + .enable = mtk_apmixedsys_enable, + .disable = mtk_apmixedsys_disable, + .set_rate = mtk_apmixedsys_set_rate, + .get_rate = mtk_apmixedsys_get_rate, +}; + +const struct clk_ops mtk_clk_topckgen_ops = { + .enable = mtk_topckgen_enable, + .disable = mtk_topckgen_disable, + .get_rate = mtk_topckgen_get_rate, + .set_parent = mtk_topckgen_set_parent, +}; + +const struct clk_ops mtk_clk_gate_ops = { + .enable = mtk_clk_gate_enable, + .disable = mtk_clk_gate_disable, + .get_rate = mtk_clk_gate_get_rate, +}; + +int mtk_common_clk_init(struct udevice *dev, + const struct mtk_clk_tree *tree) +{ + struct mtk_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + priv->tree = tree; + + return 0; +} + +int mtk_common_clk_gate_init(struct udevice *dev, + const struct mtk_clk_tree *tree, + const struct mtk_gate *gates) +{ + struct mtk_cg_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + priv->tree = tree; + priv->gates = gates; + + return 0; +} diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h new file mode 100644 index 00000000000..74152ed9c6e --- /dev/null +++ b/drivers/clk/mediatek/clk-mtk.h @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#ifndef __DRV_CLK_MTK_H +#define __DRV_CLK_MTK_H + +#define CLK_XTAL 0 +#define MHZ (1000 * 1000) + +#define HAVE_RST_BAR BIT(0) +#define CLK_DOMAIN_SCPSYS BIT(0) + +#define CLK_GATE_SETCLR BIT(0) +#define CLK_GATE_SETCLR_INV BIT(1) +#define CLK_GATE_NO_SETCLR BIT(2) +#define CLK_GATE_NO_SETCLR_INV BIT(3) +#define CLK_GATE_MASK GENMASK(3, 0) + +#define CLK_PARENT_APMIXED BIT(4) +#define CLK_PARENT_TOPCKGEN BIT(5) +#define CLK_PARENT_MASK GENMASK(5, 4) + +/* struct mtk_pll_data - hardware-specific PLLs data */ +struct mtk_pll_data { + const int id; + u32 reg; + u32 pwr_reg; + u32 en_mask; + u32 pd_reg; + int pd_shift; + u32 flags; + u32 rst_bar_mask; + u64 fmax; + int pcwbits; + u32 pcw_reg; + int pcw_shift; +}; + +/** + * struct mtk_fixed_clk - fixed clocks + * + * @id: index of clocks + * @parent: index of parnet clocks + * @rate: fixed rate + */ +struct mtk_fixed_clk { + const int id; + const int parent; + unsigned long rate; +}; + +#define FIXED_CLK(_id, _parent, _rate) { \ + .id = _id, \ + .parent = _parent, \ + .rate = _rate, \ + } + +/** + * struct mtk_fixed_factor - fixed multiplier and divider clocks + * + * @id: index of clocks + * @parent: index of parnet clocks + * @mult: multiplier + * @div: divider + * @flag: hardware-specific flags + */ +struct mtk_fixed_factor { + const int id; + const int parent; + u32 mult; + u32 div; + u32 flags; +}; + +#define FACTOR(_id, _parent, _mult, _div, _flags) { \ + .id = _id, \ + .parent = _parent, \ + .mult = _mult, \ + .div = _div, \ + .flags = _flags, \ + } + +/** + * struct mtk_composite - aggregate clock of mux, divider and gate clocks + * + * @id: index of clocks + * @parent: index of parnet clocks + * @mux_reg: hardware-specific mux register + * @gate_reg: hardware-specific gate register + * @mux_mask: mask to the mux bit field + * @mux_shift: shift to the mux bit field + * @gate_shift: shift to the gate bit field + * @num_parents: number of parent clocks + * @flags: hardware-specific flags + */ +struct mtk_composite { + const int id; + const int *parent; + u32 mux_reg; + u32 gate_reg; + u32 mux_mask; + signed char mux_shift; + signed char gate_shift; + signed char num_parents; + u16 flags; +}; + +#define MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate, \ + _flags) { \ + .id = _id, \ + .mux_reg = _reg, \ + .mux_shift = _shift, \ + .mux_mask = BIT(_width) - 1, \ + .gate_reg = _reg, \ + .gate_shift = _gate, \ + .parent = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = _flags, \ + } + +#define MUX_GATE(_id, _parents, _reg, _shift, _width, _gate) \ + MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate, 0) + +#define MUX(_id, _parents, _reg, _shift, _width) { \ + .id = _id, \ + .mux_reg = _reg, \ + .mux_shift = _shift, \ + .mux_mask = BIT(_width) - 1, \ + .gate_shift = -1, \ + .parent = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = 0, \ + } + +struct mtk_gate_regs { + u32 sta_ofs; + u32 clr_ofs; + u32 set_ofs; +}; + +/** + * struct mtk_gate - gate clocks + * + * @id: index of gate clocks + * @parent: index of parnet clocks + * @regs: hardware-specific mux register + * @shift: shift to the gate bit field + * @flags: hardware-specific flags + */ +struct mtk_gate { + const int id; + const int parent; + const struct mtk_gate_regs *regs; + int shift; + u32 flags; +}; + +/* struct mtk_clk_tree - clock tree */ +struct mtk_clk_tree { + unsigned long xtal_rate; + unsigned long xtal2_rate; + const int fdivs_offs; + const int muxes_offs; + const struct mtk_pll_data *plls; + const struct mtk_fixed_clk *fclks; + const struct mtk_fixed_factor *fdivs; + const struct mtk_composite *muxes; +}; + +struct mtk_clk_priv { + void __iomem *base; + const struct mtk_clk_tree *tree; +}; + +struct mtk_cg_priv { + void __iomem *base; + const struct mtk_clk_tree *tree; + const struct mtk_gate *gates; +}; + +extern const struct clk_ops mtk_clk_apmixedsys_ops; +extern const struct clk_ops mtk_clk_topckgen_ops; +extern const struct clk_ops mtk_clk_gate_ops; + +int mtk_common_clk_init(struct udevice *dev, + const struct mtk_clk_tree *tree); +int mtk_common_clk_gate_init(struct udevice *dev, + const struct mtk_clk_tree *tree, + const struct mtk_gate *gates); + +#endif /* __DRV_CLK_MTK_H */ diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 99698b1f46c..0529fc8763c 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -107,7 +107,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return renesas_clk_get_parent(clk, info, parent); } -static int gen3_clk_setup_sdif_div(struct clk *clk) +static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); struct cpg_mssr_info *info = priv->info; @@ -133,7 +133,7 @@ static int gen3_clk_setup_sdif_div(struct clk *clk) debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset); - writel(1, priv->base + core->offset); + writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset); return 0; } @@ -141,10 +141,6 @@ static int gen3_clk_setup_sdif_div(struct clk *clk) static int gen3_clk_enable(struct clk *clk) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - int ret = gen3_clk_setup_sdif_div(clk); - - if (ret) - return ret; return renesas_clk_endisable(clk, priv->base, true); } @@ -328,7 +324,7 @@ static ulong gen3_clk_get_rate(struct clk *clk) static ulong gen3_clk_set_rate(struct clk *clk, ulong rate) { /* Force correct SD-IF divider configuration if applicable */ - gen3_clk_setup_sdif_div(clk); + gen3_clk_setup_sdif_div(clk, rate); return gen3_clk_get_rate64(clk); } diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 26faf88116b..198914b0676 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -61,6 +61,11 @@ static const struct pll_div *apll_l_cfgs[] = { [APLL_L_600_MHZ] = &apll_l_600_cfg, }; +static const struct pll_div apll_b_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1); +static const struct pll_div *apll_b_cfgs[] = { + [APLL_B_600_MHZ] = &apll_b_600_cfg, +}; + enum { /* PLL_CON0 */ PLL_FBDIV_MASK = 0xfff, @@ -128,6 +133,24 @@ enum { ATCLK_CORE_L_DIV_SHIFT = 0, ATCLK_CORE_L_DIV_MASK = 0x1f << ATCLK_CORE_L_DIV_SHIFT, + /* CLKSEL_CON2 */ + ACLKM_CORE_B_DIV_CON_SHIFT = 8, + ACLKM_CORE_B_DIV_CON_MASK = 0x1f << ACLKM_CORE_B_DIV_CON_SHIFT, + CLK_CORE_B_PLL_SEL_SHIFT = 6, + CLK_CORE_B_PLL_SEL_MASK = 3 << CLK_CORE_B_PLL_SEL_SHIFT, + CLK_CORE_B_PLL_SEL_ALPLL = 0x0, + CLK_CORE_B_PLL_SEL_ABPLL = 0x1, + CLK_CORE_B_PLL_SEL_DPLL = 0x10, + CLK_CORE_B_PLL_SEL_GPLL = 0x11, + CLK_CORE_B_DIV_MASK = 0x1f, + CLK_CORE_B_DIV_SHIFT = 0, + + /* CLKSEL_CON3 */ + PCLK_DBG_B_DIV_SHIFT = 0x8, + PCLK_DBG_B_DIV_MASK = 0x1f << PCLK_DBG_B_DIV_SHIFT, + ATCLK_CORE_B_DIV_SHIFT = 0, + ATCLK_CORE_B_DIV_MASK = 0x1f << ATCLK_CORE_B_DIV_SHIFT, + /* CLKSEL_CON14 */ PCLK_PERIHP_DIV_CON_SHIFT = 12, PCLK_PERIHP_DIV_CON_MASK = 0x7 << PCLK_PERIHP_DIV_CON_SHIFT, @@ -395,25 +418,26 @@ static int pll_para_config(u32 freq_hz, struct pll_div *div) return 0; } -void rk3399_configure_cpu(struct rk3399_cru *cru, - enum apll_l_frequencies apll_l_freq) +void rk3399_configure_cpu_l(struct rk3399_cru *cru, + enum apll_l_frequencies apll_l_freq) { u32 aclkm_div; u32 pclk_dbg_div; u32 atclk_div; + /* Setup cluster L */ rkclk_set_pll(&cru->apll_l_con[0], apll_l_cfgs[apll_l_freq]); - aclkm_div = APLL_HZ / ACLKM_CORE_HZ - 1; - assert((aclkm_div + 1) * ACLKM_CORE_HZ == APLL_HZ && + aclkm_div = LPLL_HZ / ACLKM_CORE_L_HZ - 1; + assert((aclkm_div + 1) * ACLKM_CORE_L_HZ == LPLL_HZ && aclkm_div < 0x1f); - pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ - 1; - assert((pclk_dbg_div + 1) * PCLK_DBG_HZ == APLL_HZ && + pclk_dbg_div = LPLL_HZ / PCLK_DBG_L_HZ - 1; + assert((pclk_dbg_div + 1) * PCLK_DBG_L_HZ == LPLL_HZ && pclk_dbg_div < 0x1f); - atclk_div = APLL_HZ / ATCLK_CORE_HZ - 1; - assert((atclk_div + 1) * ATCLK_CORE_HZ == APLL_HZ && + atclk_div = LPLL_HZ / ATCLK_CORE_L_HZ - 1; + assert((atclk_div + 1) * ATCLK_CORE_L_HZ == LPLL_HZ && atclk_div < 0x1f); rk_clrsetreg(&cru->clksel_con[0], @@ -428,6 +452,42 @@ void rk3399_configure_cpu(struct rk3399_cru *cru, pclk_dbg_div << PCLK_DBG_L_DIV_SHIFT | atclk_div << ATCLK_CORE_L_DIV_SHIFT); } + +void rk3399_configure_cpu_b(struct rk3399_cru *cru, + enum apll_b_frequencies apll_b_freq) +{ + u32 aclkm_div; + u32 pclk_dbg_div; + u32 atclk_div; + + /* Setup cluster B */ + rkclk_set_pll(&cru->apll_b_con[0], apll_b_cfgs[apll_b_freq]); + + aclkm_div = BPLL_HZ / ACLKM_CORE_B_HZ - 1; + assert((aclkm_div + 1) * ACLKM_CORE_B_HZ == BPLL_HZ && + aclkm_div < 0x1f); + + pclk_dbg_div = BPLL_HZ / PCLK_DBG_B_HZ - 1; + assert((pclk_dbg_div + 1) * PCLK_DBG_B_HZ == BPLL_HZ && + pclk_dbg_div < 0x1f); + + atclk_div = BPLL_HZ / ATCLK_CORE_B_HZ - 1; + assert((atclk_div + 1) * ATCLK_CORE_B_HZ == BPLL_HZ && + atclk_div < 0x1f); + + rk_clrsetreg(&cru->clksel_con[2], + ACLKM_CORE_B_DIV_CON_MASK | CLK_CORE_B_PLL_SEL_MASK | + CLK_CORE_B_DIV_MASK, + aclkm_div << ACLKM_CORE_B_DIV_CON_SHIFT | + CLK_CORE_B_PLL_SEL_ABPLL << CLK_CORE_B_PLL_SEL_SHIFT | + 0 << CLK_CORE_B_DIV_SHIFT); + + rk_clrsetreg(&cru->clksel_con[3], + PCLK_DBG_B_DIV_MASK | ATCLK_CORE_B_DIV_MASK, + pclk_dbg_div << PCLK_DBG_B_DIV_SHIFT | + atclk_div << ATCLK_CORE_B_DIV_SHIFT); +} + #define I2C_CLK_REG_MASK(bus) \ (I2C_DIV_CON_MASK << \ CLK_I2C ##bus## _DIV_CON_SHIFT | \ @@ -1026,7 +1086,8 @@ static void rkclk_init(struct rk3399_cru *cru) u32 hclk_div; u32 pclk_div; - rk3399_configure_cpu(cru, APLL_L_600_MHZ); + rk3399_configure_cpu_l(cru, APLL_L_600_MHZ); + rk3399_configure_cpu_b(cru, APLL_B_600_MHZ); /* * some cru registers changed by bootrom, we'd better reset them to * reset/default values described in TRM to avoid confusion in kernel. diff --git a/drivers/clk/rockchip/clk_rv1108.c b/drivers/clk/rockchip/clk_rv1108.c index 1f9f534b285..914e2f4b214 100644 --- a/drivers/clk/rockchip/clk_rv1108.c +++ b/drivers/clk/rockchip/clk_rv1108.c @@ -17,6 +17,8 @@ #include <dm/lists.h> #include <dt-bindings/clock/rv1108-cru.h> +DECLARE_GLOBAL_DATA_PTR; + enum { VCO_MAX_HZ = 2400U * 1000000, VCO_MIN_HZ = 600 * 1000000, @@ -35,6 +37,9 @@ enum { #hz "Hz cannot be hit with PLL "\ "divisors on line " __stringify(__LINE__)); +static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1); +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); + /* use integer mode */ static inline int rv1108_pll_id(enum rk_clk_id clk_id) { @@ -57,6 +62,58 @@ static inline int rv1108_pll_id(enum rk_clk_id clk_id) return id; } +static int rkclk_set_pll(struct rv1108_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rv1108_pll_id(clk_id); + struct rv1108_pll *pll = &cru->pll[pll_id]; + + /* All PLLs have same VCO and output frequency range restrictions. */ + uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000; + uint output_hz = vco_hz / div->postdiv1 / div->postdiv2; + + debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n", + pll, div->fbdiv, div->refdiv, div->postdiv1, + div->postdiv2, vco_hz, output_hz); + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ); + + /* + * When power on or changing PLL setting, + * we must force PLL into slow mode to ensure output stable clock. + */ + rk_clrsetreg(&pll->con3, WORK_MODE_MASK, + WORK_MODE_SLOW << WORK_MODE_SHIFT); + + /* use integer mode */ + rk_setreg(&pll->con3, 1 << DSMPD_SHIFT); + /* Power down */ + rk_setreg(&pll->con3, 1 << GLOBAL_POWER_DOWN_SHIFT); + + rk_clrsetreg(&pll->con0, FBDIV_MASK, div->fbdiv << FBDIV_SHIFT); + rk_clrsetreg(&pll->con1, POSTDIV1_MASK | POSTDIV2_MASK | REFDIV_MASK, + (div->postdiv1 << POSTDIV1_SHIFT | + div->postdiv2 << POSTDIV2_SHIFT | + div->refdiv << REFDIV_SHIFT)); + rk_clrsetreg(&pll->con2, FRACDIV_MASK, + (div->refdiv << REFDIV_SHIFT)); + + /* Power Up */ + rk_clrreg(&pll->con3, 1 << GLOBAL_POWER_DOWN_SHIFT); + + /* waiting for pll lock */ + while (readl(&pll->con2) & (1 << LOCK_STA_SHIFT)) + udelay(1); + + /* + * set PLL into normal mode. + */ + rk_clrsetreg(&pll->con3, WORK_MODE_MASK, + WORK_MODE_NORMAL << WORK_MODE_SHIFT); + + return 0; +} + static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru, enum rk_clk_id clk_id) { @@ -74,7 +131,7 @@ static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru, fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK; postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT; postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT; - refdiv = (con1 & REFDIV_MASK) >> REFDIV_SHIFT; + refdiv = (con1 >> REFDIV_SHIFT) & REFDIV_MASK; freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; } else { freq = OSC_HZ; @@ -154,6 +211,326 @@ static ulong rv1108_saradc_set_clk(struct rv1108_cru *cru, uint hz) return rv1108_saradc_get_clk(cru); } +static ulong rv1108_aclk_vio1_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[28]); + div = bitfield_extract(val, ACLK_VIO1_CLK_DIV_SHIFT, + CLK_VIO_DIV_CON_WIDTH); + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rv1108_aclk_vio1_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[28], + ACLK_VIO1_CLK_DIV_MASK | ACLK_VIO1_PLL_SEL_MASK, + (src_clk_div << ACLK_VIO1_CLK_DIV_SHIFT) | + (VIO_PLL_SEL_GPLL << ACLK_VIO1_PLL_SEL_SHIFT)); + + return rv1108_aclk_vio1_get_clk(cru); +} + +static ulong rv1108_aclk_vio0_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[28]); + div = bitfield_extract(val, ACLK_VIO0_CLK_DIV_SHIFT, + CLK_VIO_DIV_CON_WIDTH); + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rv1108_aclk_vio0_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[28], + ACLK_VIO0_CLK_DIV_MASK | ACLK_VIO0_PLL_SEL_MASK, + (src_clk_div << ACLK_VIO0_CLK_DIV_SHIFT) | + (VIO_PLL_SEL_GPLL << ACLK_VIO0_PLL_SEL_SHIFT)); + + /*HCLK_VIO default div = 4*/ + rk_clrsetreg(&cru->clksel_con[29], + HCLK_VIO_CLK_DIV_MASK, + 3 << HCLK_VIO_CLK_DIV_SHIFT); + /*PCLK_VIO default div = 4*/ + rk_clrsetreg(&cru->clksel_con[29], + PCLK_VIO_CLK_DIV_MASK, + 3 << PCLK_VIO_CLK_DIV_SHIFT); + + return rv1108_aclk_vio0_get_clk(cru); +} + +static ulong rv1108_dclk_vop_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + + val = readl(&cru->clksel_con[32]); + div = bitfield_extract(val, DCLK_VOP_CLK_DIV_SHIFT, + DCLK_VOP_DIV_CON_WIDTH); + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rv1108_dclk_vop_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(GPLL_HZ, hz) - 1; + assert(src_clk_div < 64); + + rk_clrsetreg(&cru->clksel_con[32], + DCLK_VOP_CLK_DIV_MASK | DCLK_VOP_PLL_SEL_MASK | + DCLK_VOP_SEL_SHIFT, + (src_clk_div << DCLK_VOP_CLK_DIV_SHIFT) | + (DCLK_VOP_PLL_SEL_GPLL << DCLK_VOP_PLL_SEL_SHIFT) | + (DCLK_VOP_SEL_PLL << DCLK_VOP_SEL_SHIFT)); + + return rv1108_dclk_vop_get_clk(cru); +} + +static ulong rv1108_aclk_bus_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + val = readl(&cru->clksel_con[2]); + div = bitfield_extract(val, ACLK_BUS_DIV_CON_SHIFT, + ACLK_BUS_DIV_CON_WIDTH); + + return DIV_TO_RATE(parent_rate, div); +} + +static ulong rv1108_aclk_bus_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[2], + ACLK_BUS_DIV_CON_MASK | ACLK_BUS_PLL_SEL_MASK, + (src_clk_div << ACLK_BUS_DIV_CON_SHIFT) | + (ACLK_BUS_PLL_SEL_GPLL << ACLK_BUS_PLL_SEL_SHIFT)); + + return rv1108_aclk_bus_get_clk(cru); +} + +static ulong rv1108_aclk_peri_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + val = readl(&cru->clksel_con[23]); + div = bitfield_extract(val, ACLK_PERI_DIV_CON_SHIFT, + PERI_DIV_CON_WIDTH); + + return DIV_TO_RATE(parent_rate, div); +} + +static ulong rv1108_hclk_peri_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + val = readl(&cru->clksel_con[23]); + div = bitfield_extract(val, HCLK_PERI_DIV_CON_SHIFT, + PERI_DIV_CON_WIDTH); + + return DIV_TO_RATE(parent_rate, div); +} + +static ulong rv1108_pclk_peri_get_clk(struct rv1108_cru *cru) +{ + u32 div, val; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + val = readl(&cru->clksel_con[23]); + div = bitfield_extract(val, PCLK_PERI_DIV_CON_SHIFT, + PERI_DIV_CON_WIDTH); + + return DIV_TO_RATE(parent_rate, div); +} + +static ulong rv1108_aclk_peri_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[23], + ACLK_PERI_DIV_CON_MASK | ACLK_PERI_PLL_SEL_MASK, + (src_clk_div << ACLK_PERI_DIV_CON_SHIFT) | + (ACLK_PERI_PLL_SEL_GPLL << ACLK_PERI_PLL_SEL_SHIFT)); + + return rv1108_aclk_peri_get_clk(cru); +} + +static ulong rv1108_hclk_peri_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[23], + HCLK_PERI_DIV_CON_MASK, + (src_clk_div << HCLK_PERI_DIV_CON_SHIFT)); + + return rv1108_hclk_peri_get_clk(cru); +} + +static ulong rv1108_pclk_peri_set_clk(struct rv1108_cru *cru, uint hz) +{ + int src_clk_div; + ulong parent_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + + src_clk_div = DIV_ROUND_UP(parent_rate, hz) - 1; + assert(src_clk_div < 32); + + rk_clrsetreg(&cru->clksel_con[23], + PCLK_PERI_DIV_CON_MASK, + (src_clk_div << PCLK_PERI_DIV_CON_SHIFT)); + + return rv1108_pclk_peri_get_clk(cru); +} + +static ulong rv1108_i2c_get_clk(struct rv1108_cru *cru, ulong clk_id) +{ + u32 div, con; + + switch (clk_id) { + case SCLK_I2C0_PMU: + con = readl(&cru->clksel_con[19]); + div = bitfield_extract(con, CLK_I2C0_DIV_CON_SHIFT, + I2C_DIV_CON_WIDTH); + break; + case SCLK_I2C1: + con = readl(&cru->clksel_con[19]); + div = bitfield_extract(con, CLK_I2C1_DIV_CON_SHIFT, + I2C_DIV_CON_WIDTH); + break; + case SCLK_I2C2: + con = readl(&cru->clksel_con[20]); + div = bitfield_extract(con, CLK_I2C2_DIV_CON_SHIFT, + I2C_DIV_CON_WIDTH); + break; + case SCLK_I2C3: + con = readl(&cru->clksel_con[20]); + div = bitfield_extract(con, CLK_I2C3_DIV_CON_SHIFT, + I2C_DIV_CON_WIDTH); + break; + default: + printf("do not support this i2c bus\n"); + return -EINVAL; + } + + return DIV_TO_RATE(GPLL_HZ, div); +} + +static ulong rv1108_i2c_set_clk(struct rv1108_cru *cru, ulong clk_id, uint hz) +{ + int src_clk_div; + + /* i2c0,4,8 src clock from ppll, i2c1,2,3,5,6,7 src clock from gpll*/ + src_clk_div = GPLL_HZ / hz; + assert(src_clk_div - 1 <= 127); + + switch (clk_id) { + case SCLK_I2C0_PMU: + rk_clrsetreg(&cru->clksel_con[19], + CLK_I2C0_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK, + (src_clk_div << CLK_I2C0_DIV_CON_SHIFT) | + (CLK_I2C1_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT)); + break; + case SCLK_I2C1: + rk_clrsetreg(&cru->clksel_con[19], + CLK_I2C1_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK, + (src_clk_div << CLK_I2C1_DIV_CON_SHIFT) | + (CLK_I2C1_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT)); + break; + case SCLK_I2C2: + rk_clrsetreg(&cru->clksel_con[20], + CLK_I2C2_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK, + (src_clk_div << CLK_I2C2_DIV_CON_SHIFT) | + (CLK_I2C3_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT)); + break; + case SCLK_I2C3: + rk_clrsetreg(&cru->clksel_con[20], + CLK_I2C3_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK, + (src_clk_div << CLK_I2C3_DIV_CON_SHIFT) | + (CLK_I2C3_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT)); + break; + default: + printf("do not support this i2c bus\n"); + return -EINVAL; + } + + return rv1108_i2c_get_clk(cru, clk_id); +} + +static ulong rv1108_mmc_get_clk(struct rv1108_cru *cru) +{ + u32 div, con; + ulong mmc_clk; + + con = readl(&cru->clksel_con[26]); + div = bitfield_extract(con, EMMC_CLK_DIV_SHIFT, 8); + + con = readl(&cru->clksel_con[25]); + + if ((con & EMMC_PLL_SEL_MASK) >> EMMC_PLL_SEL_SHIFT == EMMC_PLL_SEL_OSC) + mmc_clk = DIV_TO_RATE(OSC_HZ, div) / 2; + else + mmc_clk = DIV_TO_RATE(GPLL_HZ, div) / 2; + + debug("%s div %d get_clk %ld\n", __func__, div, mmc_clk); + return mmc_clk; +} + +static ulong rv1108_mmc_set_clk(struct rv1108_cru *cru, ulong rate) +{ + int div; + u32 pll_rate; + + div = DIV_ROUND_UP(rkclk_pll_get_rate(cru, CLK_GENERAL), rate); + + if (div < 127) { + debug("%s source gpll\n", __func__); + rk_clrsetreg(&cru->clksel_con[25], EMMC_PLL_SEL_MASK, + (EMMC_PLL_SEL_GPLL << EMMC_PLL_SEL_SHIFT)); + pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL); + } else { + debug("%s source 24m\n", __func__); + rk_clrsetreg(&cru->clksel_con[25], EMMC_PLL_SEL_MASK, + (EMMC_PLL_SEL_OSC << EMMC_PLL_SEL_SHIFT)); + pll_rate = OSC_HZ; + } + + div = DIV_ROUND_UP(pll_rate / 2, rate); + rk_clrsetreg(&cru->clksel_con[26], EMMC_CLK_DIV_MASK, + ((div - 1) << EMMC_CLK_DIV_SHIFT)); + + debug("%s set_rate %ld div %d\n", __func__, rate, div); + + return DIV_TO_RATE(pll_rate, div); +} + static ulong rv1108_clk_get_rate(struct clk *clk) { struct rv1108_clk_priv *priv = dev_get_priv(clk->dev); @@ -163,6 +540,29 @@ static ulong rv1108_clk_get_rate(struct clk *clk) return rkclk_pll_get_rate(priv->cru, clk->id); case SCLK_SARADC: return rv1108_saradc_get_clk(priv->cru); + case ACLK_VIO0: + return rv1108_aclk_vio0_get_clk(priv->cru); + case ACLK_VIO1: + return rv1108_aclk_vio1_get_clk(priv->cru); + case DCLK_VOP: + return rv1108_dclk_vop_get_clk(priv->cru); + case ACLK_PRE: + return rv1108_aclk_bus_get_clk(priv->cru); + case ACLK_PERI: + return rv1108_aclk_peri_get_clk(priv->cru); + case HCLK_PERI: + return rv1108_hclk_peri_get_clk(priv->cru); + case PCLK_PERI: + return rv1108_pclk_peri_get_clk(priv->cru); + case SCLK_I2C0_PMU: + case SCLK_I2C1: + case SCLK_I2C2: + case SCLK_I2C3: + return rv1108_i2c_get_clk(priv->cru, clk->id); + case HCLK_EMMC: + case SCLK_EMMC: + case SCLK_EMMC_SAMPLE: + return rv1108_mmc_get_clk(priv->cru); default: return -ENOENT; } @@ -183,6 +583,37 @@ static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate) case SCLK_SARADC: new_rate = rv1108_saradc_set_clk(priv->cru, rate); break; + case ACLK_VIO0: + new_rate = rv1108_aclk_vio0_set_clk(priv->cru, rate); + break; + case ACLK_VIO1: + new_rate = rv1108_aclk_vio1_set_clk(priv->cru, rate); + break; + case DCLK_VOP: + new_rate = rv1108_dclk_vop_set_clk(priv->cru, rate); + break; + case ACLK_PRE: + new_rate = rv1108_aclk_bus_set_clk(priv->cru, rate); + break; + case ACLK_PERI: + new_rate = rv1108_aclk_peri_set_clk(priv->cru, rate); + break; + case HCLK_PERI: + new_rate = rv1108_hclk_peri_set_clk(priv->cru, rate); + break; + case PCLK_PERI: + new_rate = rv1108_pclk_peri_set_clk(priv->cru, rate); + break; + case SCLK_I2C0_PMU: + case SCLK_I2C1: + case SCLK_I2C2: + case SCLK_I2C3: + new_rate = rv1108_i2c_set_clk(priv->cru, clk->id, rate); + break; + case HCLK_EMMC: + case SCLK_EMMC: + new_rate = rv1108_mmc_set_clk(priv->cru, rate); + break; default: return -ENOENT; } @@ -197,14 +628,34 @@ static const struct clk_ops rv1108_clk_ops = { static void rkclk_init(struct rv1108_cru *cru) { - unsigned int apll = rkclk_pll_get_rate(cru, CLK_ARM); - unsigned int dpll = rkclk_pll_get_rate(cru, CLK_DDR); - unsigned int gpll = rkclk_pll_get_rate(cru, CLK_GENERAL); + unsigned int apll, dpll, gpll; + unsigned int aclk_bus, aclk_peri, hclk_peri, pclk_peri; + + aclk_bus = rv1108_aclk_bus_set_clk(cru, ACLK_BUS_HZ / 2); + aclk_peri = rv1108_aclk_peri_set_clk(cru, ACLK_PERI_HZ / 2); + hclk_peri = rv1108_hclk_peri_set_clk(cru, HCLK_PERI_HZ / 2); + pclk_peri = rv1108_pclk_peri_set_clk(cru, PCLK_PERI_HZ / 2); + rv1108_aclk_vio0_set_clk(cru, 297000000); + rv1108_aclk_vio1_set_clk(cru, 297000000); + + /* configure apll */ + rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg); + rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + aclk_bus = rv1108_aclk_bus_set_clk(cru, ACLK_BUS_HZ); + aclk_peri = rv1108_aclk_peri_set_clk(cru, ACLK_PERI_HZ); + hclk_peri = rv1108_hclk_peri_set_clk(cru, HCLK_PERI_HZ); + pclk_peri = rv1108_pclk_peri_set_clk(cru, PCLK_PERI_HZ); + + apll = rkclk_pll_get_rate(cru, CLK_ARM); + dpll = rkclk_pll_get_rate(cru, CLK_DDR); + gpll = rkclk_pll_get_rate(cru, CLK_GENERAL); rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK, 0 << MAC_CLK_DIV_SHIFT); printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll); + printf("ACLK_BUS: %d ACLK_PERI:%d HCLK_PERI:%d PCLK_PERI:%d\n", + aclk_bus, aclk_peri, hclk_peri, pclk_peri); } static int rv1108_clk_ofdata_to_platdata(struct udevice *dev) @@ -228,8 +679,9 @@ static int rv1108_clk_probe(struct udevice *dev) static int rv1108_clk_bind(struct udevice *dev) { int ret; - struct udevice *sys_child; + struct udevice *sys_child, *sf_child; struct sysreset_reg *priv; + struct softreset_reg *sf_priv; /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", @@ -251,6 +703,17 @@ static int rv1108_clk_bind(struct udevice *dev) if (ret) debug("Warning: software reset driver bind faile\n"); #endif + ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", + dev_ofnode(dev), &sf_child); + if (ret) { + debug("Warning: No rockchip reset driver: ret=%d\n", ret); + } else { + sf_priv = malloc(sizeof(struct softreset_reg)); + sf_priv->sf_reset_offset = offsetof(struct rv1108_cru, + softrst_con[0]); + sf_priv->sf_reset_num = 13; + sf_child->priv = sf_priv; + } return 0; } @@ -265,8 +728,8 @@ U_BOOT_DRIVER(clk_rv1108) = { .id = UCLASS_CLK, .of_match = rv1108_clk_ids, .priv_auto_alloc_size = sizeof(struct rv1108_clk_priv), - .ofdata_to_platdata = rv1108_clk_ofdata_to_platdata, .ops = &rv1108_clk_ops, .bind = rv1108_clk_bind, + .ofdata_to_platdata = rv1108_clk_ofdata_to_platdata, .probe = rv1108_clk_probe, }; diff --git a/drivers/core/device.c b/drivers/core/device.c index 47a697f3e5c..836bcadced5 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -699,6 +699,40 @@ int device_find_first_inactive_child(struct udevice *parent, return -ENODEV; } +int device_find_first_child_by_uclass(struct udevice *parent, + enum uclass_id uclass_id, + struct udevice **devp) +{ + struct udevice *dev; + + *devp = NULL; + list_for_each_entry(dev, &parent->child_head, sibling_node) { + if (device_get_uclass_id(dev) == uclass_id) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + +int device_find_child_by_name(struct udevice *parent, const char *name, + struct udevice **devp) +{ + struct udevice *dev; + + *devp = NULL; + + list_for_each_entry(dev, &parent->child_head, sibling_node) { + if (!strcmp(dev->name, name)) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + struct udevice *dev_get_parent(const struct udevice *child) { return child->parent; diff --git a/drivers/core/dump.c b/drivers/core/dump.c index 90680844043..04217cbde87 100644 --- a/drivers/core/dump.c +++ b/drivers/core/dump.c @@ -15,8 +15,8 @@ static void show_devices(struct udevice *dev, int depth, int last_flag) int i, is_last; struct udevice *child; - /* print the first 11 characters to not break the tree-format. */ - printf(" %-10.10s %d [ %c ] %-10.10s ", dev->uclass->uc_drv->name, + /* print the first 20 characters to not break the tree-format. */ + printf(" %-10.10s %d [ %c ] %-20.20s ", dev->uclass->uc_drv->name, dev_get_uclass_index(dev, NULL), dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name); @@ -49,8 +49,8 @@ void dm_dump_all(void) root = dm_root(); if (root) { - printf(" Class index Probed Driver Name\n"); - printf("-----------------------------------------\n"); + printf(" Class index Probed Driver Name\n"); + printf("-----------------------------------------------------------\n"); show_devices(root, -1, 0); } } diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index d9b5280b2d4..0e584c12dc8 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -253,15 +253,15 @@ int ofnode_read_size(ofnode node, const char *propname) fdt_addr_t ofnode_get_addr_index(ofnode node, int index) { + int na, ns; + fdt_size_t size; + if (ofnode_is_np(node)) { const __be32 *prop_val; uint flags; - u64 size; - int na; - int ns; - prop_val = of_get_address(ofnode_to_np(node), index, &size, - &flags); + prop_val = of_get_address(ofnode_to_np(node), index, + (u64 *)&size, &flags); if (!prop_val) return FDT_ADDR_T_NONE; @@ -274,8 +274,11 @@ fdt_addr_t ofnode_get_addr_index(ofnode node, int index) return of_read_number(prop_val, na); } } else { - return fdt_get_base_address(gd->fdt_blob, - ofnode_to_offset(node)); + na = ofnode_read_simple_addr_cells(ofnode_get_parent(node)); + ns = ofnode_read_simple_size_cells(ofnode_get_parent(node)); + return fdtdec_get_addr_size_fixed(gd->fdt_blob, + ofnode_to_offset(node), "reg", + index, na, ns, &size, true); } return FDT_ADDR_T_NONE; diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index d9c5719a878..9766aeabd19 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -354,10 +354,8 @@ done: } #if CONFIG_IS_ENABLED(OF_CONTROL) -static int uclass_find_device_by_phandle(enum uclass_id id, - struct udevice *parent, - const char *name, - struct udevice **devp) +int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, + const char *name, struct udevice **devp) { struct udevice *dev; struct uclass *uc; diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 2cb35f356f4..c8c47acfd34 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -9,31 +9,38 @@ #include <common.h> #include <dm.h> #include <dm/lists.h> +#include <efi_loader.h> #include <linux/libfdt.h> #include <linux/arm-smccc.h> #include <linux/errno.h> #include <linux/printk.h> #include <linux/psci.h> -psci_fn *invoke_psci_fn; +#define DRIVER_NAME "psci" -static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) -{ - struct arm_smccc_res res; +#define PSCI_METHOD_HVC 1 +#define PSCI_METHOD_SMC 2 - arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); - return res.a0; -} +int __efi_runtime_data psci_method; -static unsigned long __invoke_psci_fn_smc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) +unsigned long __efi_runtime invoke_psci_fn + (unsigned long function_id, unsigned long arg0, + unsigned long arg1, unsigned long arg2) { struct arm_smccc_res res; - arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + /* + * In the __efi_runtime we need to avoid the switch statement. In some + * cases the compiler creates lookup tables to implement switch. These + * tables are not correctly relocated when SetVirtualAddressMap is + * called. + */ + if (psci_method == PSCI_METHOD_SMC) + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + else if (psci_method == PSCI_METHOD_HVC) + arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + else + res.a0 = PSCI_RET_DISABLED; return res.a0; } @@ -67,9 +74,9 @@ static int psci_probe(struct udevice *dev) } if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; + psci_method = PSCI_METHOD_HVC; } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; + psci_method = PSCI_METHOD_SMC; } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -78,6 +85,67 @@ static int psci_probe(struct udevice *dev) return 0; } +/** + * void do_psci_probe() - probe PSCI firmware driver + * + * Ensure that psci_method is initialized. + */ +static void __maybe_unused do_psci_probe(void) +{ + struct udevice *dev; + + uclass_get_device_by_name(UCLASS_FIRMWARE, DRIVER_NAME, &dev); +} + +#if IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) +efi_status_t efi_reset_system_init(void) +{ + do_psci_probe(); + return EFI_SUCCESS; +} + +void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type reset_type, + efi_status_t reset_status, + unsigned long data_size, + void *reset_data) +{ + if (reset_type == EFI_RESET_COLD || + reset_type == EFI_RESET_WARM || + reset_type == EFI_RESET_PLATFORM_SPECIFIC) { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); + } else if (reset_type == EFI_RESET_SHUTDOWN) { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); + } + while (1) + ; +} +#endif /* IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) */ + +#ifdef CONFIG_PSCI_RESET +void reset_misc(void) +{ + do_psci_probe(); + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); +} +#endif /* CONFIG_PSCI_RESET */ + +#ifdef CONFIG_CMD_POWEROFF +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + do_psci_probe(); + + puts("poweroff ...\n"); + udelay(50000); /* wait 50 ms */ + + disable_interrupts(); + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); + enable_interrupts(); + + log_err("Power off not supported on this platform\n"); + return CMD_RET_FAILURE; +} +#endif + static const struct udevice_id psci_of_match[] = { { .compatible = "arm,psci" }, { .compatible = "arm,psci-0.2" }, @@ -86,7 +154,7 @@ static const struct udevice_id psci_of_match[] = { }; U_BOOT_DRIVER(psci) = { - .name = "psci", + .name = DRIVER_NAME, .id = UCLASS_FIRMWARE, .of_match = psci_of_match, .bind = psci_bind, diff --git a/drivers/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c index 68836a79021..e55fb4ac73d 100644 --- a/drivers/gpio/dwapb_gpio.c +++ b/drivers/gpio/dwapb_gpio.c @@ -180,6 +180,13 @@ static int gpio_dwapb_bind(struct udevice *dev) plat->pins = fdtdec_get_int(blob, node, "snps,nr-gpios", 0); plat->name = fdt_stringlist_get(blob, node, "bank-name", 0, NULL); + if (!plat->name) { + /* + * Fall back to node name. This means accessing pins + * via bank name won't work. + */ + plat->name = fdt_get_name(blob, node, NULL); + } ret = device_bind(dev, dev->driver, plat->name, plat, -1, &subdev); diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c index a2bdd5aa844..ae5aae03e72 100644 --- a/drivers/i2c/i2c-emul-uclass.c +++ b/drivers/i2c/i2c-emul-uclass.c @@ -6,8 +6,85 @@ #include <common.h> #include <dm.h> #include <i2c.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +/* + * i2c emulation works using an 'emul' node at the bus level. Each device in + * that node is in the UCLASS_I2C_EMUL uclass, and emulates one i2c device. A + * pointer to the device it emulates is in the 'dev' property of the emul device + * uclass platdata (struct i2c_emul_platdata), put there by i2c_emul_find(). + * When sandbox wants an emulator for a device, it calls i2c_emul_find() which + * searches for the emulator with the correct address. To find the device for an + * emulator, call i2c_emul_get_device(). + * + * The 'emul' node is in the UCLASS_I2C_EMUL_PARENT uclass. We use a separate + * uclass so avoid having strange devices on the I2C bus. + */ + +/** + * struct i2c_emul_uc_platdata - information about the emulator for this device + * + * This is used by devices in UCLASS_I2C_EMUL to record information about the + * device being emulated. It is accessible with dev_get_uclass_platdata() + * + * @dev: Device being emulated + */ +struct i2c_emul_uc_platdata { + struct udevice *dev; +}; + +struct udevice *i2c_emul_get_device(struct udevice *emul) +{ + struct i2c_emul_uc_platdata *uc_plat = dev_get_uclass_platdata(emul); + + return uc_plat->dev; +} + +int i2c_emul_find(struct udevice *dev, struct udevice **emulp) +{ + struct i2c_emul_uc_platdata *uc_plat; + struct udevice *emul; + int ret; + + ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, + "sandbox,emul", &emul); + if (ret) { + log_err("No emulators for device '%s'\n", dev->name); + return ret; + } + uc_plat = dev_get_uclass_platdata(emul); + uc_plat->dev = dev; + *emulp = emul; + + return device_probe(emul); +} UCLASS_DRIVER(i2c_emul) = { .id = UCLASS_I2C_EMUL, .name = "i2c_emul", + .per_device_platdata_auto_alloc_size = + sizeof(struct i2c_emul_uc_platdata), +}; + +/* + * This uclass is a child of the i2c bus. Its platdata is not defined here so + * is defined by its parent, UCLASS_I2C, which uses struct dm_i2c_chip. See + * per_child_platdata_auto_alloc_size in UCLASS_DRIVER(i2c). + */ +UCLASS_DRIVER(i2c_emul_parent) = { + .id = UCLASS_I2C_EMUL_PARENT, + .name = "i2c_emul_parent", + .post_bind = dm_scan_fdt_dev, +}; + +static const struct udevice_id i2c_emul_parent_ids[] = { + { .compatible = "sandbox,i2c-emul-parent" }, + { } +}; + +U_BOOT_DRIVER(i2c_emul_parent_drv) = { + .name = "i2c_emul_parent_drv", + .id = UCLASS_I2C_EMUL_PARENT, + .of_match = i2c_emul_parent_ids, }; diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index 66578510849..0dbbaa0c447 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -21,33 +21,15 @@ static int get_emul(struct udevice *dev, struct udevice **devp, struct dm_i2c_ops **opsp) { struct dm_i2c_chip *plat; - struct udevice *child; int ret; *devp = NULL; *opsp = NULL; plat = dev_get_parent_platdata(dev); if (!plat->emul) { - ret = dm_scan_fdt_dev(dev); + ret = i2c_emul_find(dev, &plat->emul); if (ret) return ret; - - for (device_find_first_child(dev, &child); child; - device_find_next_child(&child)) { - if (device_get_uclass_id(child) != UCLASS_I2C_EMUL) - continue; - - ret = device_probe(child); - if (ret) - return ret; - - break; - } - - if (child) - plat->emul = child; - else - return -ENODEV; } *devp = plat->emul; *opsp = i2c_get_ops(plat->emul); diff --git a/drivers/misc/altera_sysid.c b/drivers/misc/altera_sysid.c index 883b2a35e07..eff33f7343d 100644 --- a/drivers/misc/altera_sysid.c +++ b/drivers/misc/altera_sysid.c @@ -35,7 +35,7 @@ void display_sysid(void) if (ret) return; ret = misc_read(dev, 0, &sysid, sizeof(sysid)); - if (ret) + if (ret < 0) return; stamp = sysid[1]; diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 190505c11c7..2dcdb3d8d61 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -13,6 +13,8 @@ * is not reset. */ +#define LOG_CATEGORY UCLASS_CROS_EC + #include <common.h> #include <command.h> #include <dm.h> @@ -41,6 +43,54 @@ enum { CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, }; +#define INVALID_HCMD 0xFF + +/* + * Map UHEPI masks to non UHEPI commands in order to support old EC FW + * which does not support UHEPI command. + */ +static const struct { + u8 set_cmd; + u8 clear_cmd; + u8 get_cmd; +} event_map[] = { + [EC_HOST_EVENT_MAIN] = { + INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR, + INVALID_HCMD, + }, + [EC_HOST_EVENT_B] = { + INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR_B, + EC_CMD_HOST_EVENT_GET_B, + }, + [EC_HOST_EVENT_SCI_MASK] = { + EC_CMD_HOST_EVENT_SET_SCI_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_SCI_MASK, + }, + [EC_HOST_EVENT_SMI_MASK] = { + EC_CMD_HOST_EVENT_SET_SMI_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_SMI_MASK, + }, + [EC_HOST_EVENT_ALWAYS_REPORT_MASK] = { + INVALID_HCMD, INVALID_HCMD, INVALID_HCMD, + }, + [EC_HOST_EVENT_ACTIVE_WAKE_MASK] = { + EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_WAKE_MASK, + }, + [EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX] = { + EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_WAKE_MASK, + }, + [EC_HOST_EVENT_LAZY_WAKE_MASK_S3] = { + EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_WAKE_MASK, + }, + [EC_HOST_EVENT_LAZY_WAKE_MASK_S5] = { + EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD, + EC_CMD_HOST_EVENT_GET_WAKE_MASK, + }, +}; + void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len) { #ifdef DEBUG @@ -227,7 +277,7 @@ static int send_command_proto3(struct cros_ec_dev *cdev, return handle_proto3_response(cdev, dinp, din_len); } -static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, +static int send_command(struct cros_ec_dev *dev, uint cmd, int cmd_version, const void *dout, int dout_len, uint8_t **dinp, int din_len) { @@ -330,7 +380,7 @@ static int ec_command_inptr(struct udevice *dev, uint8_t cmd, * @param din_len Maximum size of response in bytes * @return number of bytes in response, or -ve on error */ -static int ec_command(struct udevice *dev, uint8_t cmd, int cmd_version, +static int ec_command(struct udevice *dev, uint cmd, int cmd_version, const void *dout, int dout_len, void *din, int din_len) { @@ -365,10 +415,14 @@ int cros_ec_scan_keyboard(struct udevice *dev, struct mbkp_keyscan *scan) int cros_ec_read_id(struct udevice *dev, char *id, int maxlen) { struct ec_response_get_version *r; + int ret; - if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, - (uint8_t **)&r, sizeof(*r)) != sizeof(*r)) + ret = ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, + (uint8_t **)&r, sizeof(*r)); + if (ret != sizeof(*r)) { + log_err("Got rc %d, expected %d\n", ret, sizeof(*r)); return -1; + } if (maxlen > (int)sizeof(r->version_string_ro)) maxlen = sizeof(r->version_string_ro); @@ -381,6 +435,7 @@ int cros_ec_read_id(struct udevice *dev, char *id, int maxlen) memcpy(id, r->version_string_rw, maxlen); break; default: + log_err("Invalid EC image %d\n", r->current_image); return -1; } @@ -563,6 +618,36 @@ int cros_ec_info(struct udevice *dev, struct ec_response_mkbp_info *info) return 0; } +int cros_ec_get_event_mask(struct udevice *dev, uint type, uint32_t *mask) +{ + struct ec_response_host_event_mask rsp; + int ret; + + ret = ec_command(dev, type, 0, NULL, 0, &rsp, sizeof(rsp)); + if (ret < 0) + return ret; + else if (ret != sizeof(rsp)) + return -EINVAL; + + *mask = rsp.mask; + + return 0; +} + +int cros_ec_set_event_mask(struct udevice *dev, uint type, uint32_t mask) +{ + struct ec_params_host_event_mask req; + int ret; + + req.mask = mask; + + ret = ec_command(dev, type, 0, &req, sizeof(req), NULL, 0); + if (ret < 0) + return ret; + + return 0; +} + int cros_ec_get_host_events(struct udevice *dev, uint32_t *events_ptr) { struct ec_response_host_event_mask *resp; @@ -616,6 +701,17 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask, return 0; } +int cros_ec_entering_mode(struct udevice *dev, int mode) +{ + int rc; + + rc = ec_command(dev, EC_CMD_ENTERING_MODE, 0, &mode, sizeof(mode), + NULL, 0); + if (rc) + return -1; + return 0; +} + static int cros_ec_check_version(struct udevice *dev) { struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); @@ -650,16 +746,14 @@ static int cros_ec_check_version(struct udevice *dev) cdev->protocol_version = 3; req.in_data = 0; if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), - (uint8_t **)&resp, sizeof(*resp)) > 0) { + (uint8_t **)&resp, sizeof(*resp)) > 0) return 0; - } /* Try sending a version 2 packet */ cdev->protocol_version = 2; if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), - (uint8_t **)&resp, sizeof(*resp)) > 0) { + (uint8_t **)&resp, sizeof(*resp)) > 0) return 0; - } /* * Fail if we're still here, since the EC doesn't understand any @@ -822,6 +916,9 @@ int cros_ec_flash_write(struct udevice *dev, const uint8_t *data, uint32_t end, off; int ret; + if (!burst) + return -EINVAL; + /* * TODO: round up to the nearest multiple of write size. Can get away * without that on link right now because its write size is 4 bytes. @@ -845,6 +942,35 @@ int cros_ec_flash_write(struct udevice *dev, const uint8_t *data, } /** + * Run verification on a slot + * + * @param me CrosEc instance + * @param region Region to run verification on + * @return 0 if success or not applicable. Non-zero if verification failed. + */ +int cros_ec_efs_verify(struct udevice *dev, enum ec_flash_region region) +{ + struct ec_params_efs_verify p; + int rv; + + log_info("EFS: EC is verifying updated image...\n"); + p.region = region; + + rv = ec_command(dev, EC_CMD_EFS_VERIFY, 0, &p, sizeof(p), NULL, 0); + if (rv >= 0) { + log_info("EFS: Verification success\n"); + return 0; + } + if (rv == -EC_RES_INVALID_COMMAND) { + log_info("EFS: EC doesn't support EFS_VERIFY command\n"); + return 0; + } + log_info("EFS: Verification failed\n"); + + return rv; +} + +/** * Read a single block from the flash * * Read a block of data from the EC flash. The size must not exceed the flash @@ -934,15 +1060,17 @@ int cros_ec_read_nvdata(struct udevice *dev, uint8_t *block, int size) struct ec_params_vbnvcontext p; int len; - if (size != EC_VBNV_BLOCK_SIZE) + if (size != EC_VBNV_BLOCK_SIZE && size != EC_VBNV_BLOCK_SIZE_V2) return -EINVAL; p.op = EC_VBNV_CONTEXT_OP_READ; len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, - &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE); - if (len < EC_VBNV_BLOCK_SIZE) + &p, sizeof(uint32_t) + size, block, size); + if (len != size) { + log_err("Expected %d bytes, got %d\n", size, len); return -EIO; + } return 0; } @@ -952,19 +1080,33 @@ int cros_ec_write_nvdata(struct udevice *dev, const uint8_t *block, int size) struct ec_params_vbnvcontext p; int len; - if (size != EC_VBNV_BLOCK_SIZE) + if (size != EC_VBNV_BLOCK_SIZE && size != EC_VBNV_BLOCK_SIZE_V2) return -EINVAL; p.op = EC_VBNV_CONTEXT_OP_WRITE; - memcpy(p.block, block, sizeof(p.block)); + memcpy(p.block, block, size); len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, - &p, sizeof(p), NULL, 0); + &p, sizeof(uint32_t) + size, NULL, 0); if (len < 0) return -1; return 0; } +int cros_ec_battery_cutoff(struct udevice *dev, uint8_t flags) +{ + struct ec_params_battery_cutoff p; + int len; + + p.flags = flags; + len = ec_command(dev, EC_CMD_BATTERY_CUT_OFF, 1, &p, sizeof(p), + NULL, 0); + + if (len < 0) + return -1; + return 0; +} + int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state) { struct ec_params_ldo_set params; @@ -1139,9 +1281,209 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in, return 0; } +int cros_ec_check_feature(struct udevice *dev, int feature) +{ + struct ec_response_get_features r; + int rv; + + rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, &r, sizeof(r), NULL, 0); + if (rv) + return rv; + + if (feature >= 8 * sizeof(r.flags)) + return -1; + + return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature); +} + +/* + * Query the EC for specified mask indicating enabled events. + * The EC maintains separate event masks for SMI, SCI and WAKE. + */ +static int cros_ec_uhepi_cmd(struct udevice *dev, uint mask, uint action, + uint64_t *value) +{ + int ret; + struct ec_params_host_event req; + struct ec_response_host_event rsp; + + req.action = action; + req.mask_type = mask; + if (action != EC_HOST_EVENT_GET) + req.value = *value; + else + *value = 0; + ret = ec_command(dev, EC_CMD_HOST_EVENT, 0, &req, sizeof(req), &rsp, + sizeof(rsp)); + + if (action != EC_HOST_EVENT_GET) + return ret; + if (ret == 0) + *value = rsp.value; + + return ret; +} + +static int cros_ec_handle_non_uhepi_cmd(struct udevice *dev, uint hcmd, + uint action, uint64_t *value) +{ + int ret = -1; + struct ec_params_host_event_mask req; + struct ec_response_host_event_mask rsp; + + if (hcmd == INVALID_HCMD) + return ret; + + if (action != EC_HOST_EVENT_GET) + req.mask = (uint32_t)*value; + else + *value = 0; + + ret = ec_command(dev, hcmd, 0, &req, sizeof(req), &rsp, sizeof(rsp)); + if (action != EC_HOST_EVENT_GET) + return ret; + if (ret == 0) + *value = rsp.mask; + + return ret; +} + +bool cros_ec_is_uhepi_supported(struct udevice *dev) +{ +#define UHEPI_SUPPORTED 1 +#define UHEPI_NOT_SUPPORTED 2 + static int uhepi_support; + + if (!uhepi_support) { + uhepi_support = cros_ec_check_feature(dev, + EC_FEATURE_UNIFIED_WAKE_MASKS) > 0 ? UHEPI_SUPPORTED : + UHEPI_NOT_SUPPORTED; + log_debug("Chrome EC: UHEPI %s\n", + uhepi_support == UHEPI_SUPPORTED ? "supported" : + "not supported"); + } + return uhepi_support == UHEPI_SUPPORTED; +} + +static int cros_ec_get_mask(struct udevice *dev, uint type) +{ + u64 value = 0; + + if (cros_ec_is_uhepi_supported(dev)) { + cros_ec_uhepi_cmd(dev, type, EC_HOST_EVENT_GET, &value); + } else { + assert(type < ARRAY_SIZE(event_map)); + cros_ec_handle_non_uhepi_cmd(dev, event_map[type].get_cmd, + EC_HOST_EVENT_GET, &value); + } + return value; +} + +static int cros_ec_clear_mask(struct udevice *dev, uint type, u64 mask) +{ + if (cros_ec_is_uhepi_supported(dev)) + return cros_ec_uhepi_cmd(dev, type, EC_HOST_EVENT_CLEAR, &mask); + + assert(type < ARRAY_SIZE(event_map)); + + return cros_ec_handle_non_uhepi_cmd(dev, event_map[type].clear_cmd, + EC_HOST_EVENT_CLEAR, &mask); +} + +uint64_t cros_ec_get_events_b(struct udevice *dev) +{ + return cros_ec_get_mask(dev, EC_HOST_EVENT_B); +} + +int cros_ec_clear_events_b(struct udevice *dev, uint64_t mask) +{ + log_debug("Chrome EC: clear events_b mask to 0x%016llx\n", mask); + + return cros_ec_clear_mask(dev, EC_HOST_EVENT_B, mask); +} + +int cros_ec_read_limit_power(struct udevice *dev, int *limit_powerp) +{ + struct ec_params_charge_state p; + struct ec_response_charge_state r; + int ret; + + p.cmd = CHARGE_STATE_CMD_GET_PARAM; + p.get_param.param = CS_PARAM_LIMIT_POWER; + ret = ec_command(dev, EC_CMD_CHARGE_STATE, 0, &p, sizeof(p), + &r, sizeof(r)); + + /* + * If our EC doesn't support the LIMIT_POWER parameter, assume that + * LIMIT_POWER is not requested. + */ + if (ret == -EC_RES_INVALID_PARAM || ret == -EC_RES_INVALID_COMMAND) { + log_warning("PARAM_LIMIT_POWER not supported by EC\n"); + return -ENOSYS; + } + + if (ret != sizeof(r.get_param)) + return -EINVAL; + + *limit_powerp = r.get_param.value; + return 0; +} + +int cros_ec_config_powerbtn(struct udevice *dev, uint32_t flags) +{ + struct ec_params_config_power_button params; + int ret; + + params.flags = flags; + ret = ec_command(dev, EC_CMD_CONFIG_POWER_BUTTON, 0, + ¶ms, sizeof(params), NULL, 0); + if (ret < 0) + return ret; + + return 0; +} + +int cros_ec_get_lid_shutdown_mask(struct udevice *dev) +{ + u32 mask; + int ret; + + ret = cros_ec_get_event_mask(dev, EC_CMD_HOST_EVENT_GET_SMI_MASK, + &mask); + if (ret < 0) + return ret; + + return !!(mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED)); +} + +int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) +{ + u32 mask; + int ret; + + ret = cros_ec_get_event_mask(dev, EC_CMD_HOST_EVENT_GET_SMI_MASK, + &mask); + if (ret < 0) + return ret; + + // Set lid close event state in the EC SMI event mask + if (enable) + mask |= EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED); + else + mask &= ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED); + + ret = cros_ec_set_event_mask(dev, EC_CMD_HOST_EVENT_SET_SMI_MASK, mask); + if (ret < 0) + return ret; + + printf("EC: %sabled lid close event\n", enable ? "en" : "dis"); + return 0; +} + UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros_ec", .per_device_auto_alloc_size = sizeof(struct cros_ec_dev), .post_bind = dm_scan_fdt_dev, + .flags = DM_UC_FLAG_ALLOC_PRIV_DMA, }; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index d741554d8a6..429f1a9b269 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -74,7 +74,7 @@ struct ec_keymatrix_entry { * @recovery_req: Keyboard recovery requested */ struct ec_state { - uint8_t vbnv_context[EC_VBNV_BLOCK_SIZE]; + u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; struct fdt_cros_ec ec_config; uint8_t *flash_data; int flash_data_len; diff --git a/drivers/misc/misc_sandbox.c b/drivers/misc/misc_sandbox.c index e4164f76fba..f7c5b2e25fa 100644 --- a/drivers/misc/misc_sandbox.c +++ b/drivers/misc/misc_sandbox.c @@ -20,7 +20,7 @@ int misc_sandbox_read(struct udevice *dev, int offset, void *buf, int size) memcpy(buf, priv->mem + offset, size); - return 0; + return size; } int misc_sandbox_write(struct udevice *dev, int offset, const void *buf, @@ -30,7 +30,7 @@ int misc_sandbox_write(struct udevice *dev, int offset, const void *buf, memcpy(priv->mem + offset, buf, size); - return 0; + return size; } int misc_sandbox_ioctl(struct udevice *dev, unsigned long request, void *buf) diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index 8a213c9e270..2520c6a38ed 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -65,7 +65,7 @@ static int dump_efuses(cmd_tbl_t *cmdtp, int flag, } ret = misc_read(dev, 0, &fuses, sizeof(fuses)); - if (ret) { + if (ret < 0) { printf("%s: misc_read failed\n", __func__); return 0; } diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 2d661351a17..33943a231b1 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -29,6 +29,9 @@ int fuse_read(u32 bank, u32 word, u32 *val) return ret; ret = misc_read(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, val, 4); + if (ret < 0) + return ret; + ret = 0; break; default: @@ -54,6 +57,9 @@ int fuse_prog(u32 bank, u32 word, u32 val) return ret; ret = misc_write(dev, word * 4 + STM32_BSEC_OTP_OFFSET, &val, 4); + if (ret < 0) + return ret; + ret = 0; break; default: @@ -78,6 +84,9 @@ int fuse_sense(u32 bank, u32 word, u32 *val) if (ret) return ret; ret = misc_read(dev, word * 4 + STM32_BSEC_OTP_OFFSET, val, 4); + if (ret < 0) + return ret; + ret = 0; break; default: @@ -103,6 +112,9 @@ int fuse_override(u32 bank, u32 word, u32 val) return ret; ret = misc_write(dev, word * 4 + STM32_BSEC_SHADOW_OFFSET, &val, 4); + if (ret < 0) + return ret; + ret = 0; break; default: diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 27246ee4658..fbd13964a08 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -569,6 +569,10 @@ config MMC_SUNXI_HAS_NEW_MODE bool depends on MMC_SUNXI +config MMC_SUNXI_HAS_MODE_SWITCH + bool + depends on MMC_SUNXI + config GENERIC_ATMEL_MCI bool "Atmel Multimedia Card Interface support" depends on DM_MMC && BLK && ARCH_AT91 @@ -598,6 +602,17 @@ config FTSDC010_SDIO help This can enable ftsdc010 sdio function. +config MMC_MTK + bool "MediaTek SD/MMC Card Interface support" + depends on ARCH_MEDIATEK + depends on BLK && DM_MMC + depends on OF_CONTROL + help + This selects the MediaTek(R) Secure digital and Multimedia card Interface. + If you have a machine with a integrated SD/MMC card reader, say Y or M here. + This is needed if support for any SD/SDIO/MMC devices is required. + If unsure, say N. + endif config TEGRA124_MMC_DISABLE_EXT_LOOPBACK diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 23c5b0daef6..801a26d8219 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -65,3 +65,4 @@ obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += tmio-common.o uniphier-sd.o obj-$(CONFIG_RENESAS_SDHI) += tmio-common.o renesas-sdhi.o obj-$(CONFIG_MMC_BCM2835) += bcm2835_sdhost.o +obj-$(CONFIG_MMC_MTK) += mtk-sd.o diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index 332f1e12a58..767dfff8055 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -278,6 +278,7 @@ int meson_mmc_bind(struct udevice *dev) static const struct udevice_id meson_mmc_match[] = { { .compatible = "amlogic,meson-gx-mmc" }, + { .compatible = "amlogic,meson-axg-mmc" }, { /* sentinel */ } }; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index f73f07254be..76225b7939b 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -166,6 +166,10 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) cfg->host_caps |= MMC_CAP(MMC_HS_200); if (dev_read_bool(dev, "mmc-hs200-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_200); + if (dev_read_bool(dev, "mmc-hs400-1_8v")) + cfg->host_caps |= MMC_CAP(MMC_HS_400); + if (dev_read_bool(dev, "mmc-hs400-1_2v")) + cfg->host_caps |= MMC_CAP(MMC_HS_400); return 0; } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d6b9cdc9922..f5c821e308c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1289,6 +1289,10 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); int speed; + /* SD version 1.00 and 1.01 does not support CMD 6 */ + if (mmc->version == SD_VERSION_1_0) + return 0; + switch (mode) { case SD_LEGACY: speed = UHS_SDR12_BUS_SPEED; diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c new file mode 100644 index 00000000000..0741a525c01 --- /dev/null +++ b/drivers/mmc/mtk-sd.c @@ -0,0 +1,1394 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek SD/MMC Card Interface driver + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <mmc.h> +#include <errno.h> +#include <malloc.h> +#include <stdbool.h> +#include <asm/gpio.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +/* MSDC_CFG */ +#define MSDC_CFG_HS400_CK_MODE_EXT BIT(22) +#define MSDC_CFG_CKMOD_EXT_M 0x300000 +#define MSDC_CFG_CKMOD_EXT_S 20 +#define MSDC_CFG_CKDIV_EXT_M 0xfff00 +#define MSDC_CFG_CKDIV_EXT_S 8 +#define MSDC_CFG_HS400_CK_MODE BIT(18) +#define MSDC_CFG_CKMOD_M 0x30000 +#define MSDC_CFG_CKMOD_S 16 +#define MSDC_CFG_CKDIV_M 0xff00 +#define MSDC_CFG_CKDIV_S 8 +#define MSDC_CFG_CKSTB BIT(7) +#define MSDC_CFG_PIO BIT(3) +#define MSDC_CFG_RST BIT(2) +#define MSDC_CFG_CKPDN BIT(1) +#define MSDC_CFG_MODE BIT(0) + +/* MSDC_IOCON */ +#define MSDC_IOCON_W_DSPL BIT(8) +#define MSDC_IOCON_DSPL BIT(2) +#define MSDC_IOCON_RSPL BIT(1) + +/* MSDC_PS */ +#define MSDC_PS_DAT0 BIT(16) +#define MSDC_PS_CDDBCE_M 0xf000 +#define MSDC_PS_CDDBCE_S 12 +#define MSDC_PS_CDSTS BIT(1) +#define MSDC_PS_CDEN BIT(0) + +/* #define MSDC_INT(EN) */ +#define MSDC_INT_ACMDRDY BIT(3) +#define MSDC_INT_ACMDTMO BIT(4) +#define MSDC_INT_ACMDCRCERR BIT(5) +#define MSDC_INT_CMDRDY BIT(8) +#define MSDC_INT_CMDTMO BIT(9) +#define MSDC_INT_RSPCRCERR BIT(10) +#define MSDC_INT_XFER_COMPL BIT(12) +#define MSDC_INT_DATTMO BIT(14) +#define MSDC_INT_DATCRCERR BIT(15) + +/* MSDC_FIFOCS */ +#define MSDC_FIFOCS_CLR BIT(31) +#define MSDC_FIFOCS_TXCNT_M 0xff0000 +#define MSDC_FIFOCS_TXCNT_S 16 +#define MSDC_FIFOCS_RXCNT_M 0xff +#define MSDC_FIFOCS_RXCNT_S 0 + +/* #define SDC_CFG */ +#define SDC_CFG_DTOC_M 0xff000000 +#define SDC_CFG_DTOC_S 24 +#define SDC_CFG_SDIOIDE BIT(20) +#define SDC_CFG_SDIO BIT(19) +#define SDC_CFG_BUSWIDTH_M 0x30000 +#define SDC_CFG_BUSWIDTH_S 16 + +/* SDC_CMD */ +#define SDC_CMD_BLK_LEN_M 0xfff0000 +#define SDC_CMD_BLK_LEN_S 16 +#define SDC_CMD_STOP BIT(14) +#define SDC_CMD_WR BIT(13) +#define SDC_CMD_DTYPE_M 0x1800 +#define SDC_CMD_DTYPE_S 11 +#define SDC_CMD_RSPTYP_M 0x380 +#define SDC_CMD_RSPTYP_S 7 +#define SDC_CMD_CMD_M 0x3f +#define SDC_CMD_CMD_S 0 + +/* SDC_STS */ +#define SDC_STS_CMDBUSY BIT(1) +#define SDC_STS_SDCBUSY BIT(0) + +/* SDC_ADV_CFG0 */ +#define SDC_RX_ENHANCE_EN BIT(20) + +/* PATCH_BIT0 */ +#define MSDC_INT_DAT_LATCH_CK_SEL_M 0x380 +#define MSDC_INT_DAT_LATCH_CK_SEL_S 7 + +/* PATCH_BIT1 */ +#define MSDC_PB1_STOP_DLY_M 0xf00 +#define MSDC_PB1_STOP_DLY_S 8 + +/* PATCH_BIT2 */ +#define MSDC_PB2_CRCSTSENSEL_M 0xe0000000 +#define MSDC_PB2_CRCSTSENSEL_S 29 +#define MSDC_PB2_CFGCRCSTS BIT(28) +#define MSDC_PB2_RESPSTSENSEL_M 0x70000 +#define MSDC_PB2_RESPSTSENSEL_S 16 +#define MSDC_PB2_CFGRESP BIT(15) +#define MSDC_PB2_RESPWAIT_M 0x0c +#define MSDC_PB2_RESPWAIT_S 2 + +/* PAD_TUNE */ +#define MSDC_PAD_TUNE_CMDRRDLY_M 0x7c00000 +#define MSDC_PAD_TUNE_CMDRRDLY_S 22 +#define MSDC_PAD_TUNE_CMD_SEL BIT(21) +#define MSDC_PAD_TUNE_CMDRDLY_M 0x1f0000 +#define MSDC_PAD_TUNE_CMDRDLY_S 16 +#define MSDC_PAD_TUNE_RXDLYSEL BIT(15) +#define MSDC_PAD_TUNE_RD_SEL BIT(13) +#define MSDC_PAD_TUNE_DATRRDLY_M 0x1f00 +#define MSDC_PAD_TUNE_DATRRDLY_S 8 +#define MSDC_PAD_TUNE_DATWRDLY_M 0x1f +#define MSDC_PAD_TUNE_DATWRDLY_S 0 + +/* EMMC50_CFG0 */ +#define EMMC50_CFG_CFCSTS_SEL BIT(4) + +/* SDC_FIFO_CFG */ +#define SDC_FIFO_CFG_WRVALIDSEL BIT(24) +#define SDC_FIFO_CFG_RDVALIDSEL BIT(25) + +/* SDC_CFG_BUSWIDTH */ +#define MSDC_BUS_1BITS 0x0 +#define MSDC_BUS_4BITS 0x1 +#define MSDC_BUS_8BITS 0x2 + +#define MSDC_FIFO_SIZE 128 + +#define PAD_DELAY_MAX 32 + +#define DEFAULT_CD_DEBOUNCE 8 + +#define CMD_INTS_MASK \ + (MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO) + +#define DATA_INTS_MASK \ + (MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR) + +/* Register offset */ +struct mtk_sd_regs { + u32 msdc_cfg; + u32 msdc_iocon; + u32 msdc_ps; + u32 msdc_int; + u32 msdc_inten; + u32 msdc_fifocs; + u32 msdc_txdata; + u32 msdc_rxdata; + u32 reserved0[4]; + u32 sdc_cfg; + u32 sdc_cmd; + u32 sdc_arg; + u32 sdc_sts; + u32 sdc_resp[4]; + u32 sdc_blk_num; + u32 sdc_vol_chg; + u32 sdc_csts; + u32 sdc_csts_en; + u32 sdc_datcrc_sts; + u32 sdc_adv_cfg0; + u32 reserved1[2]; + u32 emmc_cfg0; + u32 emmc_cfg1; + u32 emmc_sts; + u32 emmc_iocon; + u32 sd_acmd_resp; + u32 sd_acmd19_trg; + u32 sd_acmd19_sts; + u32 dma_sa_high4bit; + u32 dma_sa; + u32 dma_ca; + u32 dma_ctrl; + u32 dma_cfg; + u32 sw_dbg_sel; + u32 sw_dbg_out; + u32 dma_length; + u32 reserved2; + u32 patch_bit0; + u32 patch_bit1; + u32 patch_bit2; + u32 reserved3; + u32 dat0_tune_crc; + u32 dat1_tune_crc; + u32 dat2_tune_crc; + u32 dat3_tune_crc; + u32 cmd_tune_crc; + u32 sdio_tune_wind; + u32 reserved4[5]; + u32 pad_tune; + u32 pad_tune0; + u32 pad_tune1; + u32 dat_rd_dly[4]; + u32 reserved5[2]; + u32 hw_dbg_sel; + u32 main_ver; + u32 eco_ver; + u32 reserved6[27]; + u32 pad_ds_tune; + u32 reserved7[31]; + u32 emmc50_cfg0; + u32 reserved8[7]; + u32 sdc_fifo_cfg; +}; + +struct msdc_compatible { + u8 clk_div_bits; + bool pad_tune0; + bool async_fifo; + bool data_tune; + bool busy_check; + bool stop_clk_fix; + bool enhance_rx; +}; + +struct msdc_delay_phase { + u8 maxlen; + u8 start; + u8 final_phase; +}; + +struct msdc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct msdc_tune_para { + u32 iocon; + u32 pad_tune; +}; + +struct msdc_host { + struct mtk_sd_regs *base; + struct mmc *mmc; + + struct msdc_compatible *dev_comp; + + struct clk src_clk; /* for SD/MMC bus clock */ + struct clk h_clk; /* MSDC core clock */ + + u32 src_clk_freq; /* source clock */ + u32 mclk; /* mmc framework required bus clock */ + u32 sclk; /* actual calculated bus clock */ + + /* operation timeout clocks */ + u32 timeout_ns; + u32 timeout_clks; + + /* tuning options */ + u32 hs400_ds_delay; + u32 hs200_cmd_int_delay; + u32 hs200_write_int_delay; + u32 latch_ck; + u32 r_smpl; /* sample edge */ + bool hs400_mode; + + /* whether to use gpio detection or built-in hw detection */ + bool builtin_cd; + + /* card detection / write protection GPIOs */ +#ifdef CONFIG_DM_GPIO + struct gpio_desc gpio_wp; + struct gpio_desc gpio_cd; +#endif + + uint last_resp_type; + uint last_data_write; + + enum bus_mode timing; + + struct msdc_tune_para def_tune_para; + struct msdc_tune_para saved_tune_para; +}; + +static void msdc_reset_hw(struct msdc_host *host) +{ + u32 reg; + + setbits_le32(&host->base->msdc_cfg, MSDC_CFG_RST); + + readl_poll_timeout(&host->base->msdc_cfg, reg, + !(reg & MSDC_CFG_RST), 1000000); +} + +static void msdc_fifo_clr(struct msdc_host *host) +{ + u32 reg; + + setbits_le32(&host->base->msdc_fifocs, MSDC_FIFOCS_CLR); + + readl_poll_timeout(&host->base->msdc_fifocs, reg, + !(reg & MSDC_FIFOCS_CLR), 1000000); +} + +static u32 msdc_fifo_rx_bytes(struct msdc_host *host) +{ + return (readl(&host->base->msdc_fifocs) & + MSDC_FIFOCS_RXCNT_M) >> MSDC_FIFOCS_RXCNT_S; +} + +static u32 msdc_fifo_tx_bytes(struct msdc_host *host) +{ + return (readl(&host->base->msdc_fifocs) & + MSDC_FIFOCS_TXCNT_M) >> MSDC_FIFOCS_TXCNT_S; +} + +static u32 msdc_cmd_find_resp(struct msdc_host *host, struct mmc_cmd *cmd) +{ + u32 resp; + + switch (cmd->resp_type) { + /* Actually, R1, R5, R6, R7 are the same */ + case MMC_RSP_R1: + resp = 0x1; + break; + case MMC_RSP_R1b: + resp = 0x7; + break; + case MMC_RSP_R2: + resp = 0x2; + break; + case MMC_RSP_R3: + resp = 0x3; + break; + case MMC_RSP_NONE: + default: + resp = 0x0; + break; + } + + return resp; +} + +static u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, + struct mmc_cmd *cmd, + struct mmc_data *data) +{ + u32 opcode = cmd->cmdidx; + u32 resp_type = msdc_cmd_find_resp(host, cmd); + uint blocksize = 0; + u32 dtype = 0; + u32 rawcmd = 0; + + switch (opcode) { + case MMC_CMD_WRITE_MULTIPLE_BLOCK: + case MMC_CMD_READ_MULTIPLE_BLOCK: + dtype = 2; + break; + case MMC_CMD_WRITE_SINGLE_BLOCK: + case MMC_CMD_READ_SINGLE_BLOCK: + case SD_CMD_APP_SEND_SCR: + dtype = 1; + break; + case SD_CMD_SWITCH_FUNC: /* same as MMC_CMD_SWITCH */ + case SD_CMD_SEND_IF_COND: /* same as MMC_CMD_SEND_EXT_CSD */ + case SD_CMD_APP_SD_STATUS: /* same as MMC_CMD_SEND_STATUS */ + if (data) + dtype = 1; + } + + if (data) { + if (data->flags == MMC_DATA_WRITE) + rawcmd |= SDC_CMD_WR; + + if (data->blocks > 1) + dtype = 2; + + blocksize = data->blocksize; + } + + rawcmd |= ((opcode << SDC_CMD_CMD_S) & SDC_CMD_CMD_M) | + ((resp_type << SDC_CMD_RSPTYP_S) & SDC_CMD_RSPTYP_M) | + ((blocksize << SDC_CMD_BLK_LEN_S) & SDC_CMD_BLK_LEN_M) | + ((dtype << SDC_CMD_DTYPE_S) & SDC_CMD_DTYPE_M); + + if (opcode == MMC_CMD_STOP_TRANSMISSION) + rawcmd |= SDC_CMD_STOP; + + return rawcmd; +} + +static int msdc_cmd_done(struct msdc_host *host, int events, + struct mmc_cmd *cmd) +{ + u32 *rsp = cmd->response; + int ret = 0; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) { + rsp[0] = readl(&host->base->sdc_resp[3]); + rsp[1] = readl(&host->base->sdc_resp[2]); + rsp[2] = readl(&host->base->sdc_resp[1]); + rsp[3] = readl(&host->base->sdc_resp[0]); + } else { + rsp[0] = readl(&host->base->sdc_resp[0]); + } + } + + if (!(events & MSDC_INT_CMDRDY)) { + if (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK && + cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200) + /* + * should not clear fifo/interrupt as the tune data + * may have alreay come. + */ + msdc_reset_hw(host); + + if (events & MSDC_INT_CMDTMO) + ret = -ETIMEDOUT; + else + ret = -EIO; + } + + return ret; +} + +static bool msdc_cmd_is_ready(struct msdc_host *host) +{ + int ret; + u32 reg; + + /* The max busy time we can endure is 20ms */ + ret = readl_poll_timeout(&host->base->sdc_sts, reg, + !(reg & SDC_STS_CMDBUSY), 20000); + + if (ret) { + pr_err("CMD bus busy detected\n"); + msdc_reset_hw(host); + return false; + } + + if (host->last_resp_type == MMC_RSP_R1b && host->last_data_write) { + ret = readl_poll_timeout(&host->base->msdc_ps, reg, + reg & MSDC_PS_DAT0, 1000000); + + if (ret) { + pr_err("Card stuck in programming state!\n"); + msdc_reset_hw(host); + return false; + } + } + + return true; +} + +static int msdc_start_command(struct msdc_host *host, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + u32 rawcmd; + u32 status; + u32 blocks = 0; + int ret; + + if (!msdc_cmd_is_ready(host)) + return -EIO; + + msdc_fifo_clr(host); + + host->last_resp_type = cmd->resp_type; + host->last_data_write = 0; + + rawcmd = msdc_cmd_prepare_raw_cmd(host, cmd, data); + + if (data) + blocks = data->blocks; + + writel(CMD_INTS_MASK, &host->base->msdc_int); + writel(blocks, &host->base->sdc_blk_num); + writel(cmd->cmdarg, &host->base->sdc_arg); + writel(rawcmd, &host->base->sdc_cmd); + + ret = readl_poll_timeout(&host->base->msdc_int, status, + status & CMD_INTS_MASK, 1000000); + + if (ret) + status = MSDC_INT_CMDTMO; + + return msdc_cmd_done(host, status, cmd); +} + +static void msdc_fifo_read(struct msdc_host *host, u8 *buf, u32 size) +{ + u32 *wbuf; + + while ((size_t)buf % 4) { + *buf++ = readb(&host->base->msdc_rxdata); + size--; + } + + wbuf = (u32 *)buf; + while (size >= 4) { + *wbuf++ = readl(&host->base->msdc_rxdata); + size -= 4; + } + + buf = (u8 *)wbuf; + while (size) { + *buf++ = readb(&host->base->msdc_rxdata); + size--; + } +} + +static void msdc_fifo_write(struct msdc_host *host, const u8 *buf, u32 size) +{ + const u32 *wbuf; + + while ((size_t)buf % 4) { + writeb(*buf++, &host->base->msdc_txdata); + size--; + } + + wbuf = (const u32 *)buf; + while (size >= 4) { + writel(*wbuf++, &host->base->msdc_txdata); + size -= 4; + } + + buf = (const u8 *)wbuf; + while (size) { + writeb(*buf++, &host->base->msdc_txdata); + size--; + } +} + +static int msdc_pio_read(struct msdc_host *host, u8 *ptr, u32 size) +{ + u32 status; + u32 chksz; + int ret = 0; + + while (1) { + status = readl(&host->base->msdc_int); + writel(status, &host->base->msdc_int); + status &= DATA_INTS_MASK; + + if (status & MSDC_INT_DATCRCERR) { + ret = -EIO; + break; + } + + if (status & MSDC_INT_DATTMO) { + ret = -ETIMEDOUT; + break; + } + + if (status & MSDC_INT_XFER_COMPL) { + if (size) { + pr_err("data not fully read\n"); + ret = -EIO; + } + + break; + } + + chksz = min(size, (u32)MSDC_FIFO_SIZE); + + if (msdc_fifo_rx_bytes(host) >= chksz) { + msdc_fifo_read(host, ptr, chksz); + ptr += chksz; + size -= chksz; + } + } + + return ret; +} + +static int msdc_pio_write(struct msdc_host *host, const u8 *ptr, u32 size) +{ + u32 status; + u32 chksz; + int ret = 0; + + while (1) { + status = readl(&host->base->msdc_int); + writel(status, &host->base->msdc_int); + status &= DATA_INTS_MASK; + + if (status & MSDC_INT_DATCRCERR) { + ret = -EIO; + break; + } + + if (status & MSDC_INT_DATTMO) { + ret = -ETIMEDOUT; + break; + } + + if (status & MSDC_INT_XFER_COMPL) { + if (size) { + pr_err("data not fully written\n"); + ret = -EIO; + } + + break; + } + + chksz = min(size, (u32)MSDC_FIFO_SIZE); + + if (MSDC_FIFO_SIZE - msdc_fifo_tx_bytes(host) >= chksz) { + msdc_fifo_write(host, ptr, chksz); + ptr += chksz; + size -= chksz; + } + } + + return ret; +} + +static int msdc_start_data(struct msdc_host *host, struct mmc_data *data) +{ + u32 size; + int ret; + + if (data->flags == MMC_DATA_WRITE) + host->last_data_write = 1; + + writel(DATA_INTS_MASK, &host->base->msdc_int); + + size = data->blocks * data->blocksize; + + if (data->flags == MMC_DATA_WRITE) + ret = msdc_pio_write(host, (const u8 *)data->src, size); + else + ret = msdc_pio_read(host, (u8 *)data->dest, size); + + if (ret) { + msdc_reset_hw(host); + msdc_fifo_clr(host); + } + + return ret; +} + +static int msdc_ops_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct msdc_host *host = dev_get_priv(dev); + int ret; + + ret = msdc_start_command(host, cmd, data); + if (ret) + return ret; + + if (data) + return msdc_start_data(host, data); + + return 0; +} + +static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) +{ + u32 timeout, clk_ns; + u32 mode = 0; + + host->timeout_ns = ns; + host->timeout_clks = clks; + + if (host->sclk == 0) { + timeout = 0; + } else { + clk_ns = 1000000000UL / host->sclk; + timeout = (ns + clk_ns - 1) / clk_ns + clks; + /* unit is 1048576 sclk cycles */ + timeout = (timeout + (0x1 << 20) - 1) >> 20; + if (host->dev_comp->clk_div_bits == 8) + mode = (readl(&host->base->msdc_cfg) & + MSDC_CFG_CKMOD_M) >> MSDC_CFG_CKMOD_S; + else + mode = (readl(&host->base->msdc_cfg) & + MSDC_CFG_CKMOD_EXT_M) >> MSDC_CFG_CKMOD_EXT_S; + /* DDR mode will double the clk cycles for data timeout */ + timeout = mode >= 2 ? timeout * 2 : timeout; + timeout = timeout > 1 ? timeout - 1 : 0; + timeout = timeout > 255 ? 255 : timeout; + } + + clrsetbits_le32(&host->base->sdc_cfg, SDC_CFG_DTOC_M, + timeout << SDC_CFG_DTOC_S); +} + +static void msdc_set_buswidth(struct msdc_host *host, u32 width) +{ + u32 val = readl(&host->base->sdc_cfg); + + val &= ~SDC_CFG_BUSWIDTH_M; + + switch (width) { + default: + case 1: + val |= (MSDC_BUS_1BITS << SDC_CFG_BUSWIDTH_S); + break; + case 4: + val |= (MSDC_BUS_4BITS << SDC_CFG_BUSWIDTH_S); + break; + case 8: + val |= (MSDC_BUS_8BITS << SDC_CFG_BUSWIDTH_S); + break; + } + + writel(val, &host->base->sdc_cfg); +} + +static void msdc_set_mclk(struct msdc_host *host, enum bus_mode timing, u32 hz) +{ + u32 mode; + u32 div; + u32 sclk; + u32 reg; + + if (!hz) { + host->mclk = 0; + clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN); + return; + } + + if (host->dev_comp->clk_div_bits == 8) + clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_HS400_CK_MODE); + else + clrbits_le32(&host->base->msdc_cfg, + MSDC_CFG_HS400_CK_MODE_EXT); + + if (timing == UHS_DDR50 || timing == MMC_DDR_52 || + timing == MMC_HS_400) { + if (timing == MMC_HS_400) + mode = 0x3; + else + mode = 0x2; /* ddr mode and use divisor */ + + if (hz >= (host->src_clk_freq >> 2)) { + div = 0; /* mean div = 1/4 */ + sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */ + } else { + div = (host->src_clk_freq + ((hz << 2) - 1)) / + (hz << 2); + sclk = (host->src_clk_freq >> 2) / div; + div = (div >> 1); + } + + if (timing == MMC_HS_400 && hz >= (host->src_clk_freq >> 1)) { + if (host->dev_comp->clk_div_bits == 8) + setbits_le32(&host->base->msdc_cfg, + MSDC_CFG_HS400_CK_MODE); + else + setbits_le32(&host->base->msdc_cfg, + MSDC_CFG_HS400_CK_MODE_EXT); + + sclk = host->src_clk_freq >> 1; + div = 0; /* div is ignore when bit18 is set */ + } + } else if (hz >= host->src_clk_freq) { + mode = 0x1; /* no divisor */ + div = 0; + sclk = host->src_clk_freq; + } else { + mode = 0x0; /* use divisor */ + if (hz >= (host->src_clk_freq >> 1)) { + div = 0; /* mean div = 1/2 */ + sclk = host->src_clk_freq >> 1; /* sclk = clk / 2 */ + } else { + div = (host->src_clk_freq + ((hz << 2) - 1)) / + (hz << 2); + sclk = (host->src_clk_freq >> 2) / div; + } + } + + clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN); + + if (host->dev_comp->clk_div_bits == 8) { + div = min(div, (u32)(MSDC_CFG_CKDIV_M >> MSDC_CFG_CKDIV_S)); + clrsetbits_le32(&host->base->msdc_cfg, + MSDC_CFG_CKMOD_M | MSDC_CFG_CKDIV_M, + (mode << MSDC_CFG_CKMOD_S) | + (div << MSDC_CFG_CKDIV_S)); + } else { + div = min(div, (u32)(MSDC_CFG_CKDIV_EXT_M >> + MSDC_CFG_CKDIV_EXT_S)); + clrsetbits_le32(&host->base->msdc_cfg, + MSDC_CFG_CKMOD_EXT_M | MSDC_CFG_CKDIV_EXT_M, + (mode << MSDC_CFG_CKMOD_EXT_S) | + (div << MSDC_CFG_CKDIV_EXT_S)); + } + + readl_poll_timeout(&host->base->msdc_cfg, reg, + reg & MSDC_CFG_CKSTB, 1000000); + + setbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN); + host->sclk = sclk; + host->mclk = hz; + host->timing = timing; + + /* needed because clk changed. */ + msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); + + /* + * mmc_select_hs400() will drop to 50Mhz and High speed mode, + * tune result of hs200/200Mhz is not suitable for 50Mhz + */ + if (host->sclk <= 52000000) { + writel(host->def_tune_para.iocon, &host->base->msdc_iocon); + writel(host->def_tune_para.pad_tune, + &host->base->pad_tune); + } else { + writel(host->saved_tune_para.iocon, &host->base->msdc_iocon); + writel(host->saved_tune_para.pad_tune, + &host->base->pad_tune); + } + + dev_dbg(dev, "sclk: %d, timing: %d\n", host->sclk, timing); +} + +static int msdc_ops_set_ios(struct udevice *dev) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc *mmc = &plat->mmc; + uint clock = mmc->clock; + + msdc_set_buswidth(host, mmc->bus_width); + + if (mmc->clk_disable) + clock = 0; + else if (clock < mmc->cfg->f_min) + clock = mmc->cfg->f_min; + + if (host->mclk != clock || host->timing != mmc->selected_mode) + msdc_set_mclk(host, mmc->selected_mode, clock); + + return 0; +} + +static int msdc_ops_get_cd(struct udevice *dev) +{ + struct msdc_host *host = dev_get_priv(dev); + u32 val; + + if (host->builtin_cd) { + val = readl(&host->base->msdc_ps); + return !(val & MSDC_PS_CDSTS); + } + +#ifdef CONFIG_DM_GPIO + if (!host->gpio_cd.dev) + return 1; + + return dm_gpio_get_value(&host->gpio_cd); +#else + return 1; +#endif +} + +static int msdc_ops_get_wp(struct udevice *dev) +{ + struct msdc_host *host = dev_get_priv(dev); + +#ifdef CONFIG_DM_GPIO + if (!host->gpio_wp.dev) + return 0; + + return !dm_gpio_get_value(&host->gpio_wp); +#else + return 0; +#endif +} + +#ifdef MMC_SUPPORTS_TUNING +static u32 test_delay_bit(u32 delay, u32 bit) +{ + bit %= PAD_DELAY_MAX; + return delay & (1 << bit); +} + +static int get_delay_len(u32 delay, u32 start_bit) +{ + int i; + + for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) { + if (test_delay_bit(delay, start_bit + i) == 0) + return i; + } + + return PAD_DELAY_MAX - start_bit; +} + +static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay) +{ + int start = 0, len = 0; + int start_final = 0, len_final = 0; + u8 final_phase = 0xff; + struct msdc_delay_phase delay_phase = { 0, }; + + if (delay == 0) { + dev_err(dev, "phase error: [map:%x]\n", delay); + delay_phase.final_phase = final_phase; + return delay_phase; + } + + while (start < PAD_DELAY_MAX) { + len = get_delay_len(delay, start); + if (len_final < len) { + start_final = start; + len_final = len; + } + + start += len ? len : 1; + if (len >= 12 && start_final < 4) + break; + } + + /* The rule is to find the smallest delay cell */ + if (start_final == 0) + final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX; + else + final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX; + + dev_info(dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n", + delay, len_final, final_phase); + + delay_phase.maxlen = len_final; + delay_phase.start = start_final; + delay_phase.final_phase = final_phase; + return delay_phase; +} + +static int msdc_tune_response(struct udevice *dev, u32 opcode) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc *mmc = &plat->mmc; + u32 rise_delay = 0, fall_delay = 0; + struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, }; + struct msdc_delay_phase internal_delay_phase; + u8 final_delay, final_maxlen; + u32 internal_delay = 0; + void __iomem *tune_reg = &host->base->pad_tune; + int cmd_err; + int i, j; + + if (host->dev_comp->pad_tune0) + tune_reg = &host->base->pad_tune0; + + if (mmc->selected_mode == MMC_HS_200 || + mmc->selected_mode == UHS_SDR104) + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, + host->hs200_cmd_int_delay << + MSDC_PAD_TUNE_CMDRRDLY_S); + + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + + for (i = 0; i < PAD_DELAY_MAX; i++) { + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M, + i << MSDC_PAD_TUNE_CMDRDLY_S); + + for (j = 0; j < 3; j++) { + mmc_send_tuning(mmc, opcode, &cmd_err); + if (!cmd_err) { + rise_delay |= (1 << i); + } else { + rise_delay &= ~(1 << i); + break; + } + } + } + + final_rise_delay = get_best_delay(host, rise_delay); + /* if rising edge has enough margin, do not scan falling edge */ + if (final_rise_delay.maxlen >= 12 || + (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) + goto skip_fall; + + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + for (i = 0; i < PAD_DELAY_MAX; i++) { + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M, + i << MSDC_PAD_TUNE_CMDRDLY_S); + + for (j = 0; j < 3; j++) { + mmc_send_tuning(mmc, opcode, &cmd_err); + if (!cmd_err) { + fall_delay |= (1 << i); + } else { + fall_delay &= ~(1 << i); + break; + } + } + } + + final_fall_delay = get_best_delay(host, fall_delay); + +skip_fall: + final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); + if (final_maxlen == final_rise_delay.maxlen) { + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M, + final_rise_delay.final_phase << + MSDC_PAD_TUNE_CMDRDLY_S); + final_delay = final_rise_delay.final_phase; + } else { + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M, + final_fall_delay.final_phase << + MSDC_PAD_TUNE_CMDRDLY_S); + final_delay = final_fall_delay.final_phase; + } + + if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay) + goto skip_internal; + + for (i = 0; i < PAD_DELAY_MAX; i++) { + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, + i << MSDC_PAD_TUNE_CMDRRDLY_S); + + mmc_send_tuning(mmc, opcode, &cmd_err); + if (!cmd_err) + internal_delay |= (1 << i); + } + + dev_err(dev, "Final internal delay: 0x%x\n", internal_delay); + + internal_delay_phase = get_best_delay(host, internal_delay); + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M, + internal_delay_phase.final_phase << + MSDC_PAD_TUNE_CMDRRDLY_S); + +skip_internal: + dev_err(dev, "Final cmd pad delay: %x\n", final_delay); + return final_delay == 0xff ? -EIO : 0; +} + +static int msdc_tune_data(struct udevice *dev, u32 opcode) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc *mmc = &plat->mmc; + u32 rise_delay = 0, fall_delay = 0; + struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, }; + u8 final_delay, final_maxlen; + void __iomem *tune_reg = &host->base->pad_tune; + int cmd_err; + int i, ret; + + if (host->dev_comp->pad_tune0) + tune_reg = &host->base->pad_tune0; + + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL); + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL); + + for (i = 0; i < PAD_DELAY_MAX; i++) { + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, + i << MSDC_PAD_TUNE_DATRRDLY_S); + + ret = mmc_send_tuning(mmc, opcode, &cmd_err); + if (!ret) { + rise_delay |= (1 << i); + } else if (cmd_err) { + /* in this case, retune response is needed */ + ret = msdc_tune_response(dev, opcode); + if (ret) + break; + } + } + + final_rise_delay = get_best_delay(host, rise_delay); + if (final_rise_delay.maxlen >= 12 || + (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) + goto skip_fall; + + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL); + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL); + + for (i = 0; i < PAD_DELAY_MAX; i++) { + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, + i << MSDC_PAD_TUNE_DATRRDLY_S); + + ret = mmc_send_tuning(mmc, opcode, &cmd_err); + if (!ret) { + fall_delay |= (1 << i); + } else if (cmd_err) { + /* in this case, retune response is needed */ + ret = msdc_tune_response(dev, opcode); + if (ret) + break; + } + } + + final_fall_delay = get_best_delay(host, fall_delay); + +skip_fall: + final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); + if (final_maxlen == final_rise_delay.maxlen) { + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL); + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL); + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, + final_rise_delay.final_phase << + MSDC_PAD_TUNE_DATRRDLY_S); + final_delay = final_rise_delay.final_phase; + } else { + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL); + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL); + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M, + final_fall_delay.final_phase << + MSDC_PAD_TUNE_DATRRDLY_S); + final_delay = final_fall_delay.final_phase; + } + + if (mmc->selected_mode == MMC_HS_200 || + mmc->selected_mode == UHS_SDR104) + clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATWRDLY_M, + host->hs200_write_int_delay << + MSDC_PAD_TUNE_DATWRDLY_S); + + dev_err(dev, "Final data pad delay: %x\n", final_delay); + + return final_delay == 0xff ? -EIO : 0; +} + +static int msdc_execute_tuning(struct udevice *dev, uint opcode) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc *mmc = &plat->mmc; + int ret; + + if (mmc->selected_mode == MMC_HS_400) { + writel(host->hs400_ds_delay, &host->base->pad_ds_tune); + /* for hs400 mode it must be set to 0 */ + clrbits_le32(&host->base->patch_bit2, MSDC_PB2_CFGCRCSTS); + host->hs400_mode = true; + } + + ret = msdc_tune_response(dev, opcode); + if (ret == -EIO) { + dev_err(dev, "Tune response fail!\n"); + return ret; + } + + if (!host->hs400_mode) { + ret = msdc_tune_data(dev, opcode); + if (ret == -EIO) + dev_err(dev, "Tune data fail!\n"); + } + + host->saved_tune_para.iocon = readl(&host->base->msdc_iocon); + host->saved_tune_para.pad_tune = readl(&host->base->pad_tune); + + return ret; +} +#endif + +static void msdc_init_hw(struct msdc_host *host) +{ + u32 val; + void __iomem *tune_reg = &host->base->pad_tune; + + if (host->dev_comp->pad_tune0) + tune_reg = &host->base->pad_tune0; + + /* Configure to MMC/SD mode, clock free running */ + setbits_le32(&host->base->msdc_cfg, MSDC_CFG_MODE); + + /* Use PIO mode */ + setbits_le32(&host->base->msdc_cfg, MSDC_CFG_PIO); + + /* Reset */ + msdc_reset_hw(host); + + /* Enable/disable hw card detection according to fdt option */ + if (host->builtin_cd) + clrsetbits_le32(&host->base->msdc_ps, + MSDC_PS_CDDBCE_M, + (DEFAULT_CD_DEBOUNCE << MSDC_PS_CDDBCE_S) | + MSDC_PS_CDEN); + else + clrbits_le32(&host->base->msdc_ps, MSDC_PS_CDEN); + + /* Clear all interrupts */ + val = readl(&host->base->msdc_int); + writel(val, &host->base->msdc_int); + + /* Enable data & cmd interrupts */ + writel(DATA_INTS_MASK | CMD_INTS_MASK, &host->base->msdc_inten); + + writel(0, tune_reg); + writel(0, &host->base->msdc_iocon); + + if (host->r_smpl) + setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + else + clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL); + + writel(0x403c0046, &host->base->patch_bit0); + writel(0xffff4089, &host->base->patch_bit1); + + if (host->dev_comp->stop_clk_fix) + clrsetbits_le32(&host->base->patch_bit1, MSDC_PB1_STOP_DLY_M, + 3 << MSDC_PB1_STOP_DLY_S); + + if (host->dev_comp->busy_check) + clrbits_le32(&host->base->patch_bit1, (1 << 7)); + + setbits_le32(&host->base->emmc50_cfg0, EMMC50_CFG_CFCSTS_SEL); + + if (host->dev_comp->async_fifo) { + clrsetbits_le32(&host->base->patch_bit2, MSDC_PB2_RESPWAIT_M, + 3 << MSDC_PB2_RESPWAIT_S); + + if (host->dev_comp->enhance_rx) { + setbits_le32(&host->base->sdc_adv_cfg0, + SDC_RX_ENHANCE_EN); + } else { + clrsetbits_le32(&host->base->patch_bit2, + MSDC_PB2_RESPSTSENSEL_M, + 2 << MSDC_PB2_RESPSTSENSEL_S); + clrsetbits_le32(&host->base->patch_bit2, + MSDC_PB2_CRCSTSENSEL_M, + 2 << MSDC_PB2_CRCSTSENSEL_S); + } + + /* use async fifo to avoid tune internal delay */ + clrbits_le32(&host->base->patch_bit2, + MSDC_PB2_CFGRESP); + clrbits_le32(&host->base->patch_bit2, + MSDC_PB2_CFGCRCSTS); + } + + if (host->dev_comp->data_tune) { + setbits_le32(tune_reg, + MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL); + clrsetbits_le32(&host->base->patch_bit0, + MSDC_INT_DAT_LATCH_CK_SEL_M, + host->latch_ck << + MSDC_INT_DAT_LATCH_CK_SEL_S); + } else { + /* choose clock tune */ + setbits_le32(tune_reg, MSDC_PAD_TUNE_RXDLYSEL); + } + + /* Configure to enable SDIO mode otherwise sdio cmd5 won't work */ + setbits_le32(&host->base->sdc_cfg, SDC_CFG_SDIO); + + /* disable detecting SDIO device interrupt function */ + clrbits_le32(&host->base->sdc_cfg, SDC_CFG_SDIOIDE); + + /* Configure to default data timeout */ + clrsetbits_le32(&host->base->sdc_cfg, SDC_CFG_DTOC_M, + 3 << SDC_CFG_DTOC_S); + + if (host->dev_comp->stop_clk_fix) { + clrbits_le32(&host->base->sdc_fifo_cfg, + SDC_FIFO_CFG_WRVALIDSEL); + clrbits_le32(&host->base->sdc_fifo_cfg, + SDC_FIFO_CFG_RDVALIDSEL); + } + + host->def_tune_para.iocon = readl(&host->base->msdc_iocon); + host->def_tune_para.pad_tune = readl(&host->base->pad_tune); +} + +static void msdc_ungate_clock(struct msdc_host *host) +{ + clk_enable(&host->src_clk); + clk_enable(&host->h_clk); +} + +static int msdc_drv_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + + cfg->name = dev->name; + + host->dev_comp = (struct msdc_compatible *)dev_get_driver_data(dev); + + host->src_clk_freq = clk_get_rate(&host->src_clk); + + if (host->dev_comp->clk_div_bits == 8) + cfg->f_min = host->src_clk_freq / (4 * 255); + else + cfg->f_min = host->src_clk_freq / (4 * 4095); + cfg->f_max = host->src_clk_freq / 2; + + cfg->b_max = 1024; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + + host->mmc = &plat->mmc; + host->timeout_ns = 100000000; + host->timeout_clks = 3 * 1048576; + +#ifdef CONFIG_PINCTRL + pinctrl_select_state(dev, "default"); +#endif + + msdc_ungate_clock(host); + msdc_init_hw(host); + + upriv->mmc = &plat->mmc; + + return 0; +} + +static int msdc_ofdata_to_platdata(struct udevice *dev) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + struct msdc_host *host = dev_get_priv(dev); + struct mmc_config *cfg = &plat->cfg; + int ret; + + host->base = (void *)dev_read_addr(dev); + if (!host->base) + return -EINVAL; + + ret = mmc_of_parse(dev, cfg); + if (ret) + return ret; + + ret = clk_get_by_name(dev, "source", &host->src_clk); + if (ret < 0) + return ret; + + ret = clk_get_by_name(dev, "hclk", &host->h_clk); + if (ret < 0) + return ret; + +#ifdef CONFIG_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); + 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); + host->r_smpl = dev_read_u32_default(dev, "r_smpl", 0); + host->builtin_cd = dev_read_u32_default(dev, "builtin-cd", 0); + + return 0; +} + +static int msdc_drv_bind(struct udevice *dev) +{ + struct msdc_plat *plat = dev_get_platdata(dev); + + return mmc_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct dm_mmc_ops msdc_ops = { + .send_cmd = msdc_ops_send_cmd, + .set_ios = msdc_ops_set_ios, + .get_cd = msdc_ops_get_cd, + .get_wp = msdc_ops_get_wp, +#ifdef MMC_SUPPORTS_TUNING + .execute_tuning = msdc_execute_tuning, +#endif +}; + +static const struct msdc_compatible mt7623_compat = { + .clk_div_bits = 12, + .pad_tune0 = true, + .async_fifo = true, + .data_tune = true, + .busy_check = false, + .stop_clk_fix = false, + .enhance_rx = false +}; + +static const struct udevice_id msdc_ids[] = { + { .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat }, + {} +}; + +U_BOOT_DRIVER(mtk_sd_drv) = { + .name = "mtk_sd", + .id = UCLASS_MMC, + .of_match = msdc_ids, + .ofdata_to_platdata = msdc_ofdata_to_platdata, + .bind = msdc_drv_bind, + .probe = msdc_drv_probe, + .ops = &msdc_ops, + .platdata_auto_alloc_size = sizeof(struct msdc_plat), + .priv_auto_alloc_size = sizeof(struct msdc_host), +}; diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index e7f96f8bf22..733b6d62f5d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -17,7 +17,9 @@ #include "tmio-common.h" -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) /* SCC registers */ #define RENESAS_SDHI_SCC_DTCNTL 0x800 @@ -107,6 +109,56 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv) tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); } +static int renesas_sdhi_hs400(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + bool hs400 = (mmc->selected_mode == MMC_HS_400); + int ret, taps = hs400 ? priv->nrtaps : 8; + u32 reg; + + if (taps == 4) /* HS400 on 4tap SoC needs different clock */ + ret = clk_set_rate(&priv->clk, 400000000); + else + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) + return ret; + + tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2); + if (hs400) { + reg |= RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL; + } else { + reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); + } + + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); + + tmio_sd_writel(priv, (taps << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | + RENESAS_SDHI_SCC_DTCNTL_TAPEN, + RENESAS_SDHI_SCC_DTCNTL); + + if (taps == 4) { + tmio_sd_writel(priv, priv->tap_set >> 1, + RENESAS_SDHI_SCC_TAPSET); + } else { + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET); + } + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); + reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + return 0; +} + static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv, unsigned long tap) { @@ -125,7 +177,6 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, unsigned int smpcmp) { unsigned long tap_cnt; /* counter of tuning success */ - unsigned long tap_set; /* tap position */ unsigned long tap_start;/* start position of tuning success */ unsigned long tap_end; /* end position of tuning success */ unsigned long ntap; /* temporary counter of tuning success */ @@ -209,12 +260,12 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, select = true; if (select) - tap_set = ((tap_start + tap_end) / 2) % tap_num; + priv->tap_set = ((tap_start + tap_end) / 2) % tap_num; else return -EIO; /* Set SCC */ - tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET); + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET); /* Enable auto re-tuning */ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); @@ -240,6 +291,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) /* clock tuning is not needed for upto 52MHz */ if (!((mmc->selected_mode == MMC_HS_200) || + (mmc->selected_mode == MMC_HS_400) || (mmc->selected_mode == UHS_SDR104) || (mmc->selected_mode == UHS_SDR50))) return 0; @@ -287,19 +339,42 @@ out: return ret; } +#else +static int renesas_sdhi_hs400(struct udevice *dev) +{ + return 0; +} #endif static int renesas_sdhi_set_ios(struct udevice *dev) { - int ret = tmio_sd_set_ios(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + u32 tmp; + int ret; - mdelay(10); + /* Stop the clock before changing its rate to avoid a glitch signal */ + tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) - struct tmio_sd_priv *priv = dev_get_priv(dev); + ret = renesas_sdhi_hs400(dev); + if (ret) + return ret; + + ret = tmio_sd_set_ios(dev); - if (priv->caps & TMIO_SD_CAP_RCAR_UHS) + mdelay(10); + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) + struct mmc *mmc = mmc_get_mmc_dev(dev); + if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) && + (mmc->selected_mode != UHS_SDR104) && + (mmc->selected_mode != MMC_HS_200) && + (mmc->selected_mode != MMC_HS_400)) { renesas_sdhi_reset_tuning(priv); + } #endif return ret; @@ -331,7 +406,9 @@ static const struct dm_mmc_ops renesas_sdhi_ops = { .send_cmd = tmio_sd_send_cmd, .set_ios = renesas_sdhi_set_ios, .get_cd = tmio_sd_get_cd, -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) .execute_tuning = renesas_sdhi_execute_tuning, #endif #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) @@ -358,15 +435,45 @@ static const struct udevice_id renesas_sdhi_match[] = { { /* sentinel */ } }; +static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv) +{ + return clk_get_rate(&priv->clk); +} + +static void renesas_sdhi_filter_caps(struct udevice *dev) +{ + struct tmio_sd_plat *plat = dev_get_platdata(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + + if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3)) + return; + + /* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1 */ + if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() <= 1)) || + ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && + (rmobile_get_cpu_rev_integer() == 1) && + (rmobile_get_cpu_rev_fraction() <= 1))) + plat->cfg.host_caps &= ~MMC_MODE_HS400; + + /* H3 ES2.0 uses 4 tuning taps */ + if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() == 2)) + priv->nrtaps = 4; + else + priv->nrtaps = 8; +} + static int renesas_sdhi_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); u32 quirks = dev_get_driver_data(dev); struct fdt_resource reg_res; - struct clk clk; DECLARE_GLOBAL_DATA_PTR; int ret; + priv->clk_get_rate = renesas_sdhi_clk_get_rate; + if (quirks == RENESAS_GEN2_QUIRKS) { ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", 0, ®_res); @@ -380,29 +487,33 @@ static int renesas_sdhi_probe(struct udevice *dev) quirks |= TMIO_SD_CAP_16BIT; } - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; } /* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; } - ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } ret = tmio_sd_probe(dev, quirks); -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + + renesas_sdhi_filter_caps(dev); + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) renesas_sdhi_reset_tuning(priv); #endif diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 147eb9b4d5f..9bf040cb408 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -98,24 +98,21 @@ static int mmc_resource_init(int sdc_no) static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) { unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; - bool new_mode = false; + bool new_mode = true; bool calibrate = false; u32 val = 0; - if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2)) - new_mode = true; + if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE)) + new_mode = false; + + /* A83T support new mode only on eMMC */ + if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) + new_mode = false; #if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6) calibrate = true; #endif - /* - * The MMC clock has an extra /2 post-divider when operating in the new - * mode. - */ - if (new_mode) - hz = hz * 2; - if (hz <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; pll_hz = 24000000; @@ -176,7 +173,9 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) if (new_mode) { #ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE +#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH val = CCM_MMC_CTRL_MODE_SEL_NEW; +#endif setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW); #endif } else if (!calibrate) { diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 0eca83a0f4d..201492001f5 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -555,55 +555,76 @@ static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv, tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); } -static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, - struct mmc *mmc) +static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv) { - unsigned int divisor; - u32 val, tmp; + return priv->clk_get_rate(priv); +} - if (!mmc->clock) - return; - - divisor = DIV_ROUND_UP(priv->mclk, mmc->clock); - - if (divisor <= 1) - val = (priv->caps & TMIO_SD_CAP_RCAR) ? - TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1; - else if (divisor <= 2) - val = TMIO_SD_CLKCTL_DIV2; - else if (divisor <= 4) - val = TMIO_SD_CLKCTL_DIV4; - else if (divisor <= 8) - val = TMIO_SD_CLKCTL_DIV8; - else if (divisor <= 16) - val = TMIO_SD_CLKCTL_DIV16; - else if (divisor <= 32) - val = TMIO_SD_CLKCTL_DIV32; - else if (divisor <= 64) - val = TMIO_SD_CLKCTL_DIV64; - else if (divisor <= 128) - val = TMIO_SD_CLKCTL_DIV128; - else if (divisor <= 256) - val = TMIO_SD_CLKCTL_DIV256; - else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024)) - val = TMIO_SD_CLKCTL_DIV512; - else - val = TMIO_SD_CLKCTL_DIV1024; +static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, struct mmc *mmc) +{ + unsigned int divisor; + u32 tmp, val = 0; + ulong mclk; + + if (mmc->clock) { + mclk = tmio_sd_clk_get_rate(priv); + + divisor = DIV_ROUND_UP(mclk, mmc->clock); + + /* Do not set divider to 0xff in DDR mode */ + if (mmc->ddr_mode && (divisor == 1)) + divisor = 2; + + if (divisor <= 1) + val = (priv->caps & TMIO_SD_CAP_RCAR) ? + TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1; + else if (divisor <= 2) + val = TMIO_SD_CLKCTL_DIV2; + else if (divisor <= 4) + val = TMIO_SD_CLKCTL_DIV4; + else if (divisor <= 8) + val = TMIO_SD_CLKCTL_DIV8; + else if (divisor <= 16) + val = TMIO_SD_CLKCTL_DIV16; + else if (divisor <= 32) + val = TMIO_SD_CLKCTL_DIV32; + else if (divisor <= 64) + val = TMIO_SD_CLKCTL_DIV64; + else if (divisor <= 128) + val = TMIO_SD_CLKCTL_DIV128; + else if (divisor <= 256) + val = TMIO_SD_CLKCTL_DIV256; + else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024)) + val = TMIO_SD_CLKCTL_DIV512; + else + val = TMIO_SD_CLKCTL_DIV1024; + } tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); - if (tmp & TMIO_SD_CLKCTL_SCLKEN && - (tmp & TMIO_SD_CLKCTL_DIV_MASK) == val) - return; + if (mmc->clock && + !((tmp & TMIO_SD_CLKCTL_SCLKEN) && + ((tmp & TMIO_SD_CLKCTL_DIV_MASK) == val))) { + /* + * Stop the clock before changing its rate + * to avoid a glitch signal + */ + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); - /* stop the clock before changing its rate to avoid a glitch signal */ - tmp &= ~TMIO_SD_CLKCTL_SCLKEN; - tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + /* Change the clock rate. */ + tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; + tmp |= val; + } - tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; - tmp |= val | TMIO_SD_CLKCTL_OFFEN; - tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + /* Enable or Disable the clock */ + if (mmc->clk_disable) { + tmp |= TMIO_SD_CLKCTL_OFFEN; + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + } else { + tmp &= ~TMIO_SD_CLKCTL_OFFEN; + tmp |= TMIO_SD_CLKCTL_SCLKEN; + } - tmp |= TMIO_SD_CLKCTL_SCLKEN; tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); udelay(1000); @@ -708,6 +729,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) struct tmio_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); fdt_addr_t base; + ulong mclk; int ret; base = devfdt_get_addr(dev); @@ -750,10 +772,12 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) tmio_sd_host_init(priv); + mclk = tmio_sd_clk_get_rate(priv); + plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; - plat->cfg.f_min = priv->mclk / + plat->cfg.f_min = mclk / (priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); - plat->cfg.f_max = priv->mclk; + plat->cfg.f_max = mclk; plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */ upriv->mmc = &plat->mmc; diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 792b1ba5ae6..192026ce3ee 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -117,7 +117,6 @@ struct tmio_sd_plat { struct tmio_sd_priv { void __iomem *regbase; - unsigned long mclk; unsigned int version; u32 caps; #define TMIO_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */ @@ -133,6 +132,14 @@ struct tmio_sd_priv { #ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev; #endif +#if CONFIG_IS_ENABLED(CLK) + struct clk clk; +#endif +#if CONFIG_IS_ENABLED(RENESAS_SDHI) + u8 tap_set; + u8 nrtaps; +#endif + ulong (*clk_get_rate)(struct tmio_sd_priv *); }; int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 813c28494c3..6539880ab5d 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -31,35 +31,45 @@ static const struct udevice_id uniphier_sd_match[] = { { /* sentinel */ } }; +static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ +#if CONFIG_IS_ENABLED(CLK) + return clk_get_rate(&priv->clk); +#elif CONFIG_SPL_BUILD + return 100000000; +#else + return 0; +#endif +} + static int uniphier_sd_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); + + priv->clk_get_rate = uniphier_sd_clk_get_rate; + #ifndef CONFIG_SPL_BUILD - struct clk clk; int ret; - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; } /* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, ULONG_MAX); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; } - ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } -#else - priv->mclk = 100000000; #endif return tmio_sd_probe(dev, 0); diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c index 41db9f8bb9b..dc531ccb682 100644 --- a/drivers/mtd/nand/raw/arasan_nfc.c +++ b/drivers/mtd/nand/raw/arasan_nfc.c @@ -1201,6 +1201,10 @@ static int arasan_nand_init(struct nand_chip *nand_chip, int devnum) mtd = nand_to_mtd(nand_chip); nand_set_controller_data(nand_chip, nand); +#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE + nand_chip->options |= NAND_NO_SUBPAGE_WRITE; +#endif + /* Set the driver entry points for MTD */ nand_chip->cmdfunc = arasan_nand_cmd_function; nand_chip->select_chip = arasan_nand_select_chip; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 7fef754c634..7b9891cb981 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -57,6 +57,8 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state) /* Bits for the status register */ #define STAT_WIP (1 << 0) #define STAT_WEL (1 << 1) +#define STAT_BP_SHIFT 2 +#define STAT_BP_MASK (7 << STAT_BP_SHIFT) /* Assume all SPI flashes have 3 byte addresses since they do atm */ #define SF_ADDR_LEN 3 @@ -102,6 +104,14 @@ struct sandbox_spi_flash_plat_data { int cs; }; +void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask) +{ + struct sandbox_spi_flash *sbsf = dev_get_priv(dev); + + sbsf->status &= ~STAT_BP_MASK; + sbsf->status |= bp_mask << STAT_BP_SHIFT; +} + /** * This is a very strange probe function. If it has platform data (which may * have come from the device tree) then this function gets the filename and diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index 662525f016f..719a2fd23ae 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -28,6 +28,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) return log_ret(sf_get_ops(dev)->erase(dev, offset, len)); } +int spl_flash_get_sw_write_prot(struct udevice *dev) +{ + struct dm_spi_flash_ops *ops = sf_get_ops(dev); + + if (!ops->get_sw_write_prot) + return -ENOSYS; + return log_ret(ops->get_sw_write_prot(dev)); +} + /* * TODO(sjg@chromium.org): This is an old-style function. We should remove * it when all SPI flash drivers use dm diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 26f5c7c995e..46a50444175 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -170,6 +170,9 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, /* Flash erase(sectors) operation, support all possible erase commands */ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); +/* Get software write-protect value (BP bits) */ +int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); + /* Lock stmicro spi flash region */ int stm_lock(struct spi_flash *flash, u32 ofs, size_t len); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 4d7320fe8c1..00f8558e701 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -124,6 +124,13 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) return spi_flash_cmd_erase_ops(flash, offset, len); } +static int spi_flash_std_get_sw_write_prot(struct udevice *dev) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_get_sw_write_prot(flash); +} + static int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parent_priv(dev); @@ -149,6 +156,7 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = { .read = spi_flash_std_read, .write = spi_flash_std_write, .erase = spi_flash_std_erase, + .get_sw_write_prot = spi_flash_std_get_sw_write_prot, }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index a87bacd4ac7..0c2392f28a4 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -110,6 +110,18 @@ static int write_cr(struct spi_flash *flash, u8 wc) } #endif +int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash) +{ + u8 status; + int ret; + + ret = read_sr(flash, &status); + if (ret) + return ret; + + return (status >> 2) & 7; +} + #ifdef CONFIG_SPI_FLASH_BAR /* * This "clean_bar" is necessary in a situation when one was accessing diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 19db0a8114a..4fa26abc1b8 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -838,6 +838,8 @@ static const struct udevice_id designware_eth_ids[] = { { .compatible = "altr,socfpga-stmmac" }, { .compatible = "amlogic,meson6-dwmac" }, { .compatible = "amlogic,meson-gx-dwmac" }, + { .compatible = "amlogic,meson-gxbb-dwmac" }, + { .compatible = "amlogic,meson-axg-dwmac" }, { .compatible = "st,stm32-dwmac" }, { } }; diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 3ba3a1ff8be..c9798445c7d 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -60,6 +60,10 @@ #define SC_ETCS_MASK GENMASK(1, 0) #define SC_ETCS_EXT_GMII 0x1 #define SC_ETCS_INT_GMII 0x2 +#define SC_ETXDC_MASK GENMASK(12, 10) +#define SC_ETXDC_OFFSET 10 +#define SC_ERXDC_MASK GENMASK(9, 5) +#define SC_ERXDC_OFFSET 5 #define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ) @@ -140,6 +144,8 @@ struct emac_eth_dev { struct sun8i_eth_pdata { struct eth_pdata eth_pdata; u32 reset_delays[3]; + int tx_delay_ps; + int rx_delay_ps; }; @@ -273,7 +279,8 @@ static int sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 *reg) return 0; } -static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) +static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, + struct emac_eth_dev *priv) { int ret; u32 reg; @@ -312,6 +319,14 @@ static int sun8i_emac_set_syscon(struct emac_eth_dev *priv) return -EINVAL; } + if (pdata->tx_delay_ps) + reg |= ((pdata->tx_delay_ps / 100) << SC_ETXDC_OFFSET) + & SC_ETXDC_MASK; + + if (pdata->rx_delay_ps) + reg |= ((pdata->rx_delay_ps / 100) << SC_ERXDC_OFFSET) + & SC_ERXDC_MASK; + writel(reg, priv->sysctl_reg + 0x30); return 0; @@ -784,13 +799,14 @@ static void sun8i_emac_eth_stop(struct udevice *dev) static int sun8i_emac_eth_probe(struct udevice *dev) { - struct eth_pdata *pdata = dev_get_platdata(dev); + struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev); + struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; struct emac_eth_dev *priv = dev_get_priv(dev); priv->mac_reg = (void *)pdata->iobase; sun8i_emac_board_setup(priv); - sun8i_emac_set_syscon(priv); + sun8i_emac_set_syscon(sun8i_pdata, priv); sun8i_mdio_init(dev->name, dev); priv->bus = miiphy_get_dev_by_name(dev->name); @@ -891,6 +907,18 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) if (!priv->use_internal_phy) parse_phy_pins(dev); + sun8i_pdata->tx_delay_ps = fdtdec_get_int(gd->fdt_blob, node, + "allwinner,tx-delay-ps", 0); + if (sun8i_pdata->tx_delay_ps < 0 || sun8i_pdata->tx_delay_ps > 700) + printf("%s: Invalid TX delay value %d\n", __func__, + sun8i_pdata->tx_delay_ps); + + sun8i_pdata->rx_delay_ps = fdtdec_get_int(gd->fdt_blob, node, + "allwinner,rx-delay-ps", 0); + if (sun8i_pdata->rx_delay_ps < 0 || sun8i_pdata->rx_delay_ps > 3100) + printf("%s: Invalid RX delay value %d\n", __func__, + sun8i_pdata->rx_delay_ps); + #ifdef CONFIG_DM_GPIO if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), "snps,reset-active-low")) diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index bc33126536c..9bd79b198a2 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -86,15 +86,24 @@ DECLARE_GLOBAL_DATA_PTR; /* Set with binary 00011000 to use 1536 byte(1*max length frame/buffer) */ #define ZYNQ_GEM_DMACR_RXBUF 0x00180000 +#if defined(CONFIG_PHYS_64BIT) +# define ZYNQ_GEM_DMA_BUS_WIDTH BIT(30) /* 64 bit bus */ +#else +# define ZYNQ_GEM_DMA_BUS_WIDTH (0 << 30) /* 32 bit bus */ +#endif + #define ZYNQ_GEM_DMACR_INIT (ZYNQ_GEM_DMACR_BLENGTH | \ ZYNQ_GEM_DMACR_RXSIZE | \ ZYNQ_GEM_DMACR_TXSIZE | \ - ZYNQ_GEM_DMACR_RXBUF) + ZYNQ_GEM_DMACR_RXBUF | \ + ZYNQ_GEM_DMA_BUS_WIDTH) #define ZYNQ_GEM_TSR_DONE 0x00000020 /* Tx done mask */ #define ZYNQ_GEM_PCS_CTL_ANEG_ENBL 0x1000 +#define ZYNQ_GEM_DCFG_DBG6_DMA_64B BIT(23) + /* Use MII register 1 (MII status register) to detect PHY */ #define PHY_DETECT_REG 1 @@ -143,16 +152,26 @@ struct zynq_gem_regs { u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */ u32 reserved9[20]; u32 pcscntrl; - u32 reserved7[143]; + u32 rserved12[36]; + u32 dcfg6; /* 0x294 Design config reg6 */ + u32 reserved7[106]; u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */ u32 reserved8[15]; u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */ + u32 reserved10[17]; + u32 upper_txqbase; /* 0x4C8 - Upper tx_q base addr */ + u32 reserved11[2]; + u32 upper_rxqbase; /* 0x4D4 - Upper rx_q base addr */ }; /* BD descriptors */ struct emac_bd { u32 addr; /* Next descriptor pointer */ u32 status; +#if defined(CONFIG_PHYS_64BIT) + u32 addr_hi; + u32 reserved; +#endif }; #define RX_BUF 32 @@ -183,6 +202,7 @@ struct zynq_gem_priv { struct clk clk; u32 max_speed; bool int_pcs; + bool dma_64bit; }; static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum, @@ -363,6 +383,23 @@ static int zynq_gem_init(struct udevice *dev) struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC]; struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2]; + if (readl(®s->dcfg6) & ZYNQ_GEM_DCFG_DBG6_DMA_64B) + priv->dma_64bit = true; + else + priv->dma_64bit = false; + +#if defined(CONFIG_PHYS_64BIT) + if (!priv->dma_64bit) { + printf("ERR: %s: Using 64-bit DMA but HW doesn't support it\n", + __func__); + return -EINVAL; + } +#else + if (priv->dma_64bit) + debug("WARN: %s: Not using 64-bit dma even HW supports it\n", + __func__); +#endif + if (!priv->init) { /* Disable all interrupts */ writel(0xFFFFFFFF, ®s->idr); @@ -390,13 +427,21 @@ static int zynq_gem_init(struct udevice *dev) for (i = 0; i < RX_BUF; i++) { priv->rx_bd[i].status = 0xF0000000; priv->rx_bd[i].addr = - ((ulong)(priv->rxbuffers) + - (i * PKTSIZE_ALIGN)); - } + (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((ulong)priv->rx_bd, ®s->rxqbase); + 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); @@ -406,12 +451,18 @@ static int zynq_gem_init(struct udevice *dev) /* Disable the second priority queue */ dummy_tx_bd->addr = 0; +#if defined(CONFIG_PHYS_64BIT) + dummy_tx_bd->addr_hi = 0; +#endif dummy_tx_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK | ZYNQ_GEM_TXBUF_LAST_MASK| ZYNQ_GEM_TXBUF_USED_MASK; dummy_rx_bd->addr = ZYNQ_GEM_RXBUF_WRAP_MASK | ZYNQ_GEM_RXBUF_NEW_MASK; +#if defined(CONFIG_PHYS_64BIT) + dummy_rx_bd->addr_hi = 0; +#endif dummy_rx_bd->status = 0; writel((ulong)dummy_tx_bd, ®s->transmit_q1_ptr); @@ -485,7 +536,8 @@ static int zynq_gem_init(struct udevice *dev) static int zynq_gem_send(struct udevice *dev, void *ptr, int len) { - u32 addr, size; + dma_addr_t addr; + u32 size; struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct emac_bd *current_bd = &priv->tx_bd[1]; @@ -493,17 +545,26 @@ static int zynq_gem_send(struct udevice *dev, void *ptr, int len) /* Setup Tx BD */ memset(priv->tx_bd, 0, sizeof(struct emac_bd)); - priv->tx_bd->addr = (ulong)ptr; + priv->tx_bd->addr = lower_32_bits((ulong)ptr); +#if defined(CONFIG_PHYS_64BIT) + priv->tx_bd->addr_hi = upper_32_bits((ulong)ptr); +#endif priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) | ZYNQ_GEM_TXBUF_LAST_MASK; /* Dummy descriptor to mark it as the last in descriptor chain */ current_bd->addr = 0x0; +#if defined(CONFIG_PHYS_64BIT) + current_bd->addr_hi = 0x0; +#endif current_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK | ZYNQ_GEM_TXBUF_LAST_MASK| ZYNQ_GEM_TXBUF_USED_MASK; /* setup BD */ - writel((ulong)priv->tx_bd, ®s->txqbase); + writel(lower_32_bits((ulong)priv->tx_bd), ®s->txqbase); +#if defined(CONFIG_PHYS_64BIT) + writel(upper_32_bits((ulong)priv->tx_bd), ®s->upper_txqbase); +#endif addr = (ulong) ptr; addr &= ~(ARCH_DMA_MINALIGN - 1); @@ -531,7 +592,7 @@ static int zynq_gem_send(struct udevice *dev, void *ptr, int len) static int zynq_gem_recv(struct udevice *dev, int flags, uchar **packetp) { int frame_len; - u32 addr; + dma_addr_t addr; struct zynq_gem_priv *priv = dev_get_priv(dev); struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current]; @@ -550,8 +611,14 @@ static int zynq_gem_recv(struct udevice *dev, int flags, uchar **packetp) return -1; } +#if defined(CONFIG_PHYS_64BIT) + addr = (dma_addr_t)((current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK) + | ((dma_addr_t)current_bd->addr_hi << 32)); +#else addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK; +#endif addr &= ~(ARCH_DMA_MINALIGN - 1); + *packetp = (uchar *)(uintptr_t)addr; return frame_len; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 0c52337f33a..2cf55cb743d 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -774,16 +774,19 @@ int pci_bind_bus_devices(struct udevice *bus) found_multi = false; if (PCI_FUNC(bdf) && !found_multi) continue; + /* Check only the first access, we don't expect problems */ - ret = pci_bus_read_config(bus, bdf, PCI_HEADER_TYPE, - &header_type, PCI_SIZE_8); + ret = pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor, + PCI_SIZE_16); if (ret) goto error; - pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor, - PCI_SIZE_16); + if (vendor == 0xffff || vendor == 0x0000) continue; + pci_bus_read_config(bus, bdf, PCI_HEADER_TYPE, + &header_type, PCI_SIZE_8); + if (!PCI_FUNC(bdf)) found_multi = header_type & 0x80; diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index eaacd4066e8..7d9b75c2c45 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -331,6 +331,7 @@ int vbe_setup_video_priv(struct vesa_mode_info *vesa, return log_msg_ret("No x resolution", -ENXIO); uc_priv->xsize = vesa->x_resolution; uc_priv->ysize = vesa->y_resolution; + uc_priv->line_length = vesa->bytes_per_scanline; switch (vesa->bits_per_pixel) { case 32: case 24: diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ad0b8daba62..7e6fad305ae 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -301,6 +301,7 @@ config ASPEED_AST2500_PINCTRL endif source "drivers/pinctrl/meson/Kconfig" +source "drivers/pinctrl/mediatek/Kconfig" source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a3a6c6d163b..293bad3a950 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ obj-$(CONFIG_PINCTRL_MESON) += meson/ +obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_ARCH_MVEBU) += mvebu/ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig new file mode 100644 index 00000000000..1bd9a925a58 --- /dev/null +++ b/drivers/pinctrl/mediatek/Kconfig @@ -0,0 +1,15 @@ +if ARCH_MEDIATEK + +config PINCTRL_MTK + depends on PINCTRL_GENERIC + bool + +config PINCTRL_MT7623 + bool "MT7623 SoC pinctrl driver" + select PINCTRL_MTK + +config PINCTRL_MT7629 + bool "MT7629 SoC pinctrl driver" + select PINCTRL_MTK + +endif diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile new file mode 100644 index 00000000000..f6ef3627e80 --- /dev/null +++ b/drivers/pinctrl/mediatek/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# Core +obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o + +# SoC Drivers +obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o +obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c new file mode 100644 index 00000000000..fd37dfa4429 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -0,0 +1,1284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <dm.h> + +#include "pinctrl-mtk-common.h" + +#define PIN_BOND_REG0 0xb10 +#define PIN_BOND_REG1 0xf20 +#define PIN_BOND_REG2 0xef0 +#define BOND_PCIE_CLR (0x77 << 3) +#define BOND_I2S_CLR 0x3 +#define BOND_MSDC0E_CLR 0x1 + +#define PIN_FIELD15(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 15, false) + +#define PIN_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 16, false) + +#define PINS_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)\ + PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 16, true) + +static const struct mtk_pin_field_calc mt7623_pin_mode_range[] = { + PIN_FIELD15(0, 278, 0x760, 0x10, 0, 3), +}; + +static const struct mtk_pin_field_calc mt7623_pin_dir_range[] = { + PIN_FIELD16(0, 175, 0x0, 0x10, 0, 1), + PIN_FIELD16(176, 278, 0xc0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_di_range[] = { + PIN_FIELD16(0, 278, 0x630, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_do_range[] = { + PIN_FIELD16(0, 278, 0x500, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_ies_range[] = { + PINS_FIELD16(0, 6, 0xb20, 0x10, 0, 1), + PINS_FIELD16(7, 9, 0xb20, 0x10, 1, 1), + PINS_FIELD16(10, 13, 0xb30, 0x10, 3, 1), + PINS_FIELD16(14, 15, 0xb30, 0x10, 13, 1), + PINS_FIELD16(16, 17, 0xb40, 0x10, 7, 1), + PINS_FIELD16(18, 29, 0xb40, 0x10, 13, 1), + PINS_FIELD16(30, 32, 0xb40, 0x10, 7, 1), + PINS_FIELD16(33, 37, 0xb40, 0x10, 13, 1), + PIN_FIELD16(38, 38, 0xb20, 0x10, 13, 1), + PINS_FIELD16(39, 42, 0xb40, 0x10, 13, 1), + PINS_FIELD16(43, 45, 0xb20, 0x10, 10, 1), + PINS_FIELD16(47, 48, 0xb20, 0x10, 11, 1), + PIN_FIELD16(49, 49, 0xb20, 0x10, 12, 1), + PINS_FIELD16(50, 52, 0xb20, 0x10, 13, 1), + PINS_FIELD16(53, 56, 0xb20, 0x10, 14, 1), + PINS_FIELD16(57, 58, 0xb20, 0x10, 15, 1), + PIN_FIELD16(59, 59, 0xb30, 0x10, 10, 1), + PINS_FIELD16(60, 62, 0xb30, 0x10, 0, 1), + PINS_FIELD16(63, 65, 0xb30, 0x10, 1, 1), + PINS_FIELD16(66, 71, 0xb30, 0x10, 2, 1), + PINS_FIELD16(72, 74, 0xb20, 0x10, 12, 1), + PINS_FIELD16(75, 76, 0xb30, 0x10, 3, 1), + PINS_FIELD16(77, 78, 0xb30, 0x10, 4, 1), + PINS_FIELD16(79, 82, 0xb30, 0x10, 5, 1), + PINS_FIELD16(83, 84, 0xb30, 0x10, 2, 1), + PIN_FIELD16(85, 85, 0xda0, 0x10, 4, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 4, 1), + PINS_FIELD16(87, 90, 0xdb0, 0x10, 4, 1), + PINS_FIELD16(101, 104, 0xb30, 0x10, 6, 1), + PIN_FIELD16(105, 105, 0xd40, 0x10, 4, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 4, 1), + PINS_FIELD16(107, 110, 0xd50, 0x10, 4, 1), + PINS_FIELD16(111, 115, 0xce0, 0x10, 4, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 4, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 4, 1), + PINS_FIELD16(118, 121, 0xce0, 0x10, 4, 1), + PINS_FIELD16(122, 125, 0xb30, 0x10, 7, 1), + PIN_FIELD16(126, 126, 0xb20, 0x10, 12, 1), + PINS_FIELD16(127, 142, 0xb30, 0x10, 9, 1), + PINS_FIELD16(143, 160, 0xb30, 0x10, 10, 1), + PINS_FIELD16(161, 168, 0xb30, 0x10, 12, 1), + PINS_FIELD16(169, 183, 0xb30, 0x10, 10, 1), + PINS_FIELD16(184, 186, 0xb30, 0x10, 9, 1), + PIN_FIELD16(187, 187, 0xb30, 0x10, 14, 1), + PIN_FIELD16(188, 188, 0xb20, 0x10, 13, 1), + PINS_FIELD16(189, 193, 0xb30, 0x10, 15, 1), + PINS_FIELD16(194, 198, 0xb40, 0x10, 0, 1), + PIN_FIELD16(199, 199, 0xb20, 0x10, 1, 1), + PINS_FIELD16(200, 202, 0xb40, 0x10, 1, 1), + PINS_FIELD16(203, 207, 0xb40, 0x10, 2, 1), + PINS_FIELD16(208, 209, 0xb40, 0x10, 3, 1), + PIN_FIELD16(210, 210, 0xb40, 0x10, 4, 1), + PINS_FIELD16(211, 235, 0xb40, 0x10, 5, 1), + PINS_FIELD16(236, 241, 0xb40, 0x10, 6, 1), + PINS_FIELD16(242, 243, 0xb40, 0x10, 7, 1), + PINS_FIELD16(244, 247, 0xb40, 0x10, 8, 1), + PIN_FIELD16(248, 248, 0xb40, 0x10, 9, 1), + PINS_FIELD16(249, 257, 0xfc0, 0x10, 4, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 4, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 4, 1), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 4, 1), + PIN_FIELD16(261, 261, 0xd50, 0x10, 4, 1), + PINS_FIELD16(262, 277, 0xb40, 0x10, 12, 1), + PIN_FIELD16(278, 278, 0xb40, 0x10, 13, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_smt_range[] = { + PINS_FIELD16(0, 6, 0xb50, 0x10, 0, 1), + PINS_FIELD16(7, 9, 0xb50, 0x10, 1, 1), + PINS_FIELD16(10, 13, 0xb60, 0x10, 3, 1), + PINS_FIELD16(14, 15, 0xb60, 0x10, 13, 1), + PINS_FIELD16(16, 17, 0xb70, 0x10, 7, 1), + PINS_FIELD16(18, 29, 0xb70, 0x10, 13, 1), + PINS_FIELD16(30, 32, 0xb70, 0x10, 7, 1), + PINS_FIELD16(33, 37, 0xb70, 0x10, 13, 1), + PIN_FIELD16(38, 38, 0xb50, 0x10, 13, 1), + PINS_FIELD16(39, 42, 0xb70, 0x10, 13, 1), + PINS_FIELD16(43, 45, 0xb50, 0x10, 10, 1), + PINS_FIELD16(47, 48, 0xb50, 0x10, 11, 1), + PIN_FIELD16(49, 49, 0xb50, 0x10, 12, 1), + PINS_FIELD16(50, 52, 0xb50, 0x10, 13, 1), + PINS_FIELD16(53, 56, 0xb50, 0x10, 14, 1), + PINS_FIELD16(57, 58, 0xb50, 0x10, 15, 1), + PIN_FIELD16(59, 59, 0xb60, 0x10, 10, 1), + PINS_FIELD16(60, 62, 0xb60, 0x10, 0, 1), + PINS_FIELD16(63, 65, 0xb60, 0x10, 1, 1), + PINS_FIELD16(66, 71, 0xb60, 0x10, 2, 1), + PINS_FIELD16(72, 74, 0xb50, 0x10, 12, 1), + PINS_FIELD16(75, 76, 0xb60, 0x10, 3, 1), + PINS_FIELD16(77, 78, 0xb60, 0x10, 4, 1), + PINS_FIELD16(79, 82, 0xb60, 0x10, 5, 1), + PINS_FIELD16(83, 84, 0xb60, 0x10, 2, 1), + PIN_FIELD16(85, 85, 0xda0, 0x10, 11, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 11, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 3, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 7, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 11, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 15, 1), + PINS_FIELD16(101, 104, 0xb60, 0x10, 6, 1), + PIN_FIELD16(105, 105, 0xd40, 0x10, 11, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 11, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 3, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 7, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 11, 1), + PIN_FIELD16(110, 110, 0xd60, 0x10, 15, 1), + PIN_FIELD16(111, 111, 0xd00, 0x10, 15, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 11, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 7, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 3, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 3, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 11, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 11, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 15, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 7, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 3, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 7, 1), + PINS_FIELD16(122, 125, 0xb60, 0x10, 7, 1), + PIN_FIELD16(126, 126, 0xb50, 0x10, 12, 1), + PINS_FIELD16(127, 142, 0xb60, 0x10, 9, 1), + PINS_FIELD16(143, 160, 0xb60, 0x10, 10, 1), + PINS_FIELD16(161, 168, 0xb60, 0x10, 12, 1), + PINS_FIELD16(169, 183, 0xb60, 0x10, 10, 1), + PINS_FIELD16(184, 186, 0xb60, 0x10, 9, 1), + PIN_FIELD16(187, 187, 0xb60, 0x10, 14, 1), + PIN_FIELD16(188, 188, 0xb50, 0x10, 13, 1), + PINS_FIELD16(189, 193, 0xb60, 0x10, 15, 1), + PINS_FIELD16(194, 198, 0xb70, 0x10, 0, 1), + PIN_FIELD16(199, 199, 0xb50, 0x10, 1, 1), + PINS_FIELD16(200, 202, 0xb70, 0x10, 1, 1), + PINS_FIELD16(203, 207, 0xb70, 0x10, 2, 1), + PINS_FIELD16(208, 209, 0xb70, 0x10, 3, 1), + PIN_FIELD16(210, 210, 0xb70, 0x10, 4, 1), + PINS_FIELD16(211, 235, 0xb70, 0x10, 5, 1), + PINS_FIELD16(236, 241, 0xb70, 0x10, 6, 1), + PINS_FIELD16(242, 243, 0xb70, 0x10, 7, 1), + PINS_FIELD16(244, 247, 0xb70, 0x10, 8, 1), + PIN_FIELD16(248, 248, 0xb70, 0x10, 9, 10), + PIN_FIELD16(249, 249, 0x140, 0x10, 3, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 15, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 11, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 7, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 3, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 15, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 11, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 7, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 3, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 11, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 11, 1), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 11, 1), + PIN_FIELD16(261, 261, 0x0b0, 0x10, 3, 1), + PINS_FIELD16(262, 277, 0xb70, 0x10, 12, 1), + PIN_FIELD16(278, 278, 0xb70, 0x10, 13, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_pullen_range[] = { + PIN_FIELD16(0, 278, 0x150, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_pullsel_range[] = { + PIN_FIELD16(0, 278, 0x280, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_drv_range[] = { + PINS_FIELD16(0, 6, 0xf50, 0x10, 0, 4), + PINS_FIELD16(7, 9, 0xf50, 0x10, 4, 4), + PINS_FIELD16(10, 13, 0xf50, 0x10, 4, 4), + PINS_FIELD16(14, 15, 0xf50, 0x10, 12, 4), + PINS_FIELD16(16, 17, 0xf60, 0x10, 0, 4), + PINS_FIELD16(18, 21, 0xf60, 0x10, 0, 4), + PINS_FIELD16(22, 26, 0xf60, 0x10, 8, 4), + PINS_FIELD16(27, 29, 0xf60, 0x10, 12, 4), + PINS_FIELD16(30, 32, 0xf60, 0x10, 0, 4), + PINS_FIELD16(33, 37, 0xf70, 0x10, 0, 4), + PIN_FIELD16(38, 38, 0xf70, 0x10, 4, 4), + PINS_FIELD16(39, 42, 0xf70, 0x10, 8, 4), + PINS_FIELD16(43, 45, 0xf70, 0x10, 12, 4), + PINS_FIELD16(47, 48, 0xf80, 0x10, 0, 4), + PIN_FIELD16(49, 49, 0xf80, 0x10, 4, 4), + PINS_FIELD16(50, 52, 0xf70, 0x10, 4, 4), + PINS_FIELD16(53, 56, 0xf80, 0x10, 12, 4), + PINS_FIELD16(60, 62, 0xf90, 0x10, 8, 4), + PINS_FIELD16(63, 65, 0xf90, 0x10, 12, 4), + PINS_FIELD16(66, 71, 0xfa0, 0x10, 0, 4), + PINS_FIELD16(72, 74, 0xf80, 0x10, 4, 4), + PIN_FIELD16(85, 85, 0xda0, 0x10, 0, 4), + PIN_FIELD16(86, 86, 0xd90, 0x10, 0, 4), + PINS_FIELD16(87, 90, 0xdb0, 0x10, 0, 4), + PIN_FIELD16(105, 105, 0xd40, 0x10, 0, 4), + PIN_FIELD16(106, 106, 0xd30, 0x10, 0, 4), + PINS_FIELD16(107, 110, 0xd50, 0x10, 0, 4), + PINS_FIELD16(111, 115, 0xce0, 0x10, 0, 4), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 0, 4), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 0, 4), + PINS_FIELD16(118, 121, 0xce0, 0x10, 0, 4), + PIN_FIELD16(126, 126, 0xf80, 0x10, 4, 4), + PIN_FIELD16(188, 188, 0xf70, 0x10, 4, 4), + PINS_FIELD16(189, 193, 0xfe0, 0x10, 8, 4), + PINS_FIELD16(194, 198, 0xfe0, 0x10, 12, 4), + PIN_FIELD16(199, 199, 0xf50, 0x10, 4, 4), + PINS_FIELD16(200, 202, 0xfd0, 0x10, 0, 4), + PINS_FIELD16(203, 207, 0xfd0, 0x10, 4, 4), + PINS_FIELD16(208, 209, 0xfd0, 0x10, 8, 4), + PIN_FIELD16(210, 210, 0xfd0, 0x10, 12, 4), + PINS_FIELD16(211, 235, 0xff0, 0x10, 0, 4), + PINS_FIELD16(236, 241, 0xff0, 0x10, 4, 4), + PINS_FIELD16(242, 243, 0xff0, 0x10, 8, 4), + PIN_FIELD16(248, 248, 0xf00, 0x10, 0, 4), + PINS_FIELD16(249, 256, 0xfc0, 0x10, 0, 4), + PIN_FIELD16(257, 257, 0xce0, 0x10, 0, 4), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 0, 4), + PIN_FIELD16(259, 259, 0xc90, 0x10, 0, 4), + PIN_FIELD16(260, 260, 0x3a0, 0x10, 0, 4), + PIN_FIELD16(261, 261, 0xd50, 0x10, 0, 4), + PINS_FIELD16(262, 277, 0xf00, 0x10, 8, 4), + PIN_FIELD16(278, 278, 0xf70, 0x10, 8, 4), +}; + +static const struct mtk_pin_reg_calc mt7623_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7623_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7623_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7623_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7623_pin_do_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7623_pin_ies_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7623_pin_smt_range), + [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7623_pin_pullsel_range), + [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7623_pin_pullen_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7623_pin_drv_range), +}; + +static const struct mtk_pin_desc mt7623_pins[] = { + MTK_PIN(0, "PWRAP_SPI0_MI", DRV_GRP3), + MTK_PIN(1, "PWRAP_SPI0_MO", DRV_GRP3), + MTK_PIN(2, "PWRAP_INT", DRV_GRP3), + MTK_PIN(3, "PWRAP_SPI0_CK", DRV_GRP3), + MTK_PIN(4, "PWRAP_SPI0_CSN", DRV_GRP3), + MTK_PIN(5, "PWRAP_SPI0_CK2", DRV_GRP3), + MTK_PIN(6, "PWRAP_SPI0_CSN2", DRV_GRP3), + MTK_PIN(7, "SPI1_CSN", DRV_GRP3), + MTK_PIN(8, "SPI1_MI", DRV_GRP3), + MTK_PIN(9, "SPI1_MO", DRV_GRP3), + MTK_PIN(10, "RTC32K_CK", DRV_GRP3), + MTK_PIN(11, "WATCHDOG", DRV_GRP3), + MTK_PIN(12, "SRCLKENA", DRV_GRP3), + MTK_PIN(13, "SRCLKENAI", DRV_GRP3), + MTK_PIN(14, "URXD2", DRV_GRP1), + MTK_PIN(15, "UTXD2", DRV_GRP1), + MTK_PIN(16, "I2S5_DATA_IN", DRV_GRP1), + MTK_PIN(17, "I2S5_BCK", DRV_GRP1), + MTK_PIN(18, "PCM_CLK", DRV_GRP1), + MTK_PIN(19, "PCM_SYNC", DRV_GRP1), + MTK_PIN(20, "PCM_RX", DRV_GRP1), + MTK_PIN(21, "PCM_TX", DRV_GRP1), + MTK_PIN(22, "EINT0", DRV_GRP1), + MTK_PIN(23, "EINT1", DRV_GRP1), + MTK_PIN(24, "EINT2", DRV_GRP1), + MTK_PIN(25, "EINT3", DRV_GRP1), + MTK_PIN(26, "EINT4", DRV_GRP1), + MTK_PIN(27, "EINT5", DRV_GRP1), + MTK_PIN(28, "EINT6", DRV_GRP1), + MTK_PIN(29, "EINT7", DRV_GRP1), + MTK_PIN(30, "I2S5_LRCK", DRV_GRP1), + MTK_PIN(31, "I2S5_MCLK", DRV_GRP1), + MTK_PIN(32, "I2S5_DATA", DRV_GRP1), + MTK_PIN(33, "I2S1_DATA", DRV_GRP1), + MTK_PIN(34, "I2S1_DATA_IN", DRV_GRP1), + MTK_PIN(35, "I2S1_BCK", DRV_GRP1), + MTK_PIN(36, "I2S1_LRCK", DRV_GRP1), + MTK_PIN(37, "I2S1_MCLK", DRV_GRP1), + MTK_PIN(38, "I2S2_DATA", DRV_GRP1), + MTK_PIN(39, "JTMS", DRV_GRP3), + MTK_PIN(40, "JTCK", DRV_GRP3), + MTK_PIN(41, "JTDI", DRV_GRP3), + MTK_PIN(42, "JTDO", DRV_GRP3), + MTK_PIN(43, "NCLE", DRV_GRP1), + MTK_PIN(44, "NCEB1", DRV_GRP1), + MTK_PIN(45, "NCEB0", DRV_GRP1), + MTK_PIN(46, "IR", DRV_FIXED), + MTK_PIN(47, "NREB", DRV_GRP1), + MTK_PIN(48, "NRNB", DRV_GRP1), + MTK_PIN(49, "I2S0_DATA", DRV_GRP1), + MTK_PIN(50, "I2S2_BCK", DRV_GRP1), + MTK_PIN(51, "I2S2_DATA_IN", DRV_GRP1), + MTK_PIN(52, "I2S2_LRCK", DRV_GRP1), + MTK_PIN(53, "SPI0_CSN", DRV_GRP1), + MTK_PIN(54, "SPI0_CK", DRV_GRP1), + MTK_PIN(55, "SPI0_MI", DRV_GRP1), + MTK_PIN(56, "SPI0_MO", DRV_GRP1), + MTK_PIN(57, "SDA1", DRV_FIXED), + MTK_PIN(58, "SCL1", DRV_FIXED), + MTK_PIN(59, "RAMBUF_I_CLK", DRV_FIXED), + MTK_PIN(60, "WB_RSTB", DRV_GRP3), + MTK_PIN(61, "F2W_DATA", DRV_GRP3), + MTK_PIN(62, "F2W_CLK", DRV_GRP3), + MTK_PIN(63, "WB_SCLK", DRV_GRP3), + MTK_PIN(64, "WB_SDATA", DRV_GRP3), + MTK_PIN(65, "WB_SEN", DRV_GRP3), + MTK_PIN(66, "WB_CRTL0", DRV_GRP3), + MTK_PIN(67, "WB_CRTL1", DRV_GRP3), + MTK_PIN(68, "WB_CRTL2", DRV_GRP3), + MTK_PIN(69, "WB_CRTL3", DRV_GRP3), + MTK_PIN(70, "WB_CRTL4", DRV_GRP3), + MTK_PIN(71, "WB_CRTL5", DRV_GRP3), + MTK_PIN(72, "I2S0_DATA_IN", DRV_GRP1), + MTK_PIN(73, "I2S0_LRCK", DRV_GRP1), + MTK_PIN(74, "I2S0_BCK", DRV_GRP1), + MTK_PIN(75, "SDA0", DRV_FIXED), + MTK_PIN(76, "SCL0", DRV_FIXED), + MTK_PIN(77, "SDA2", DRV_FIXED), + MTK_PIN(78, "SCL2", DRV_FIXED), + MTK_PIN(79, "URXD0", DRV_FIXED), + MTK_PIN(80, "UTXD0", DRV_FIXED), + MTK_PIN(81, "URXD1", DRV_FIXED), + MTK_PIN(82, "UTXD1", DRV_FIXED), + MTK_PIN(83, "LCM_RST", DRV_FIXED), + MTK_PIN(84, "DSI_TE", DRV_FIXED), + MTK_PIN(85, "MSDC2_CMD", DRV_GRP4), + MTK_PIN(86, "MSDC2_CLK", DRV_GRP4), + MTK_PIN(87, "MSDC2_DAT0", DRV_GRP4), + MTK_PIN(88, "MSDC2_DAT1", DRV_GRP4), + MTK_PIN(89, "MSDC2_DAT2", DRV_GRP4), + MTK_PIN(90, "MSDC2_DAT3", DRV_GRP4), + MTK_PIN(91, "TDN3", DRV_FIXED), + MTK_PIN(92, "TDP3", DRV_FIXED), + MTK_PIN(93, "TDN2", DRV_FIXED), + MTK_PIN(94, "TDP2", DRV_FIXED), + MTK_PIN(95, "TCN", DRV_FIXED), + MTK_PIN(96, "TCP", DRV_FIXED), + MTK_PIN(97, "TDN1", DRV_FIXED), + MTK_PIN(98, "TDP1", DRV_FIXED), + MTK_PIN(99, "TDN0", DRV_FIXED), + MTK_PIN(100, "TDP0", DRV_FIXED), + MTK_PIN(101, "SPI2_CSN", DRV_FIXED), + MTK_PIN(102, "SPI2_MI", DRV_FIXED), + MTK_PIN(103, "SPI2_MO", DRV_FIXED), + MTK_PIN(104, "SPI2_CLK", DRV_FIXED), + MTK_PIN(105, "MSDC1_CMD", DRV_GRP4), + MTK_PIN(106, "MSDC1_CLK", DRV_GRP4), + MTK_PIN(107, "MSDC1_DAT0", DRV_GRP4), + MTK_PIN(108, "MSDC1_DAT1", DRV_GRP4), + MTK_PIN(109, "MSDC1_DAT2", DRV_GRP4), + MTK_PIN(110, "MSDC1_DAT3", DRV_GRP4), + MTK_PIN(111, "MSDC0_DAT7", DRV_GRP4), + MTK_PIN(112, "MSDC0_DAT6", DRV_GRP4), + MTK_PIN(113, "MSDC0_DAT5", DRV_GRP4), + MTK_PIN(114, "MSDC0_DAT4", DRV_GRP4), + MTK_PIN(115, "MSDC0_RSTB", DRV_GRP4), + MTK_PIN(116, "MSDC0_CMD", DRV_GRP4), + MTK_PIN(117, "MSDC0_CLK", DRV_GRP4), + MTK_PIN(118, "MSDC0_DAT3", DRV_GRP4), + MTK_PIN(119, "MSDC0_DAT2", DRV_GRP4), + MTK_PIN(120, "MSDC0_DAT1", DRV_GRP4), + MTK_PIN(121, "MSDC0_DAT0", DRV_GRP4), + MTK_PIN(122, "CEC", DRV_FIXED), + MTK_PIN(123, "HTPLG", DRV_FIXED), + MTK_PIN(124, "HDMISCK", DRV_FIXED), + MTK_PIN(125, "HDMISD", DRV_FIXED), + MTK_PIN(126, "I2S0_MCLK", DRV_GRP1), + MTK_PIN(127, "RAMBUF_IDATA0", DRV_FIXED), + MTK_PIN(128, "RAMBUF_IDATA1", DRV_FIXED), + MTK_PIN(129, "RAMBUF_IDATA2", DRV_FIXED), + MTK_PIN(130, "RAMBUF_IDATA3", DRV_FIXED), + MTK_PIN(131, "RAMBUF_IDATA4", DRV_FIXED), + MTK_PIN(132, "RAMBUF_IDATA5", DRV_FIXED), + MTK_PIN(133, "RAMBUF_IDATA6", DRV_FIXED), + MTK_PIN(134, "RAMBUF_IDATA7", DRV_FIXED), + MTK_PIN(135, "RAMBUF_IDATA8", DRV_FIXED), + MTK_PIN(136, "RAMBUF_IDATA9", DRV_FIXED), + MTK_PIN(137, "RAMBUF_IDATA10", DRV_FIXED), + MTK_PIN(138, "RAMBUF_IDATA11", DRV_FIXED), + MTK_PIN(139, "RAMBUF_IDATA12", DRV_FIXED), + MTK_PIN(140, "RAMBUF_IDATA13", DRV_FIXED), + MTK_PIN(141, "RAMBUF_IDATA14", DRV_FIXED), + MTK_PIN(142, "RAMBUF_IDATA15", DRV_FIXED), + MTK_PIN(143, "RAMBUF_ODATA0", DRV_FIXED), + MTK_PIN(144, "RAMBUF_ODATA1", DRV_FIXED), + MTK_PIN(145, "RAMBUF_ODATA2", DRV_FIXED), + MTK_PIN(146, "RAMBUF_ODATA3", DRV_FIXED), + MTK_PIN(147, "RAMBUF_ODATA4", DRV_FIXED), + MTK_PIN(148, "RAMBUF_ODATA5", DRV_FIXED), + MTK_PIN(149, "RAMBUF_ODATA6", DRV_FIXED), + MTK_PIN(150, "RAMBUF_ODATA7", DRV_FIXED), + MTK_PIN(151, "RAMBUF_ODATA8", DRV_FIXED), + MTK_PIN(152, "RAMBUF_ODATA9", DRV_FIXED), + MTK_PIN(153, "RAMBUF_ODATA10", DRV_FIXED), + MTK_PIN(154, "RAMBUF_ODATA11", DRV_FIXED), + MTK_PIN(155, "RAMBUF_ODATA12", DRV_FIXED), + MTK_PIN(156, "RAMBUF_ODATA13", DRV_FIXED), + MTK_PIN(157, "RAMBUF_ODATA14", DRV_FIXED), + MTK_PIN(158, "RAMBUF_ODATA15", DRV_FIXED), + MTK_PIN(159, "RAMBUF_BE0", DRV_FIXED), + MTK_PIN(160, "RAMBUF_BE1", DRV_FIXED), + MTK_PIN(161, "AP2PT_INT", DRV_FIXED), + MTK_PIN(162, "AP2PT_INT_CLR", DRV_FIXED), + MTK_PIN(163, "PT2AP_INT", DRV_FIXED), + MTK_PIN(164, "PT2AP_INT_CLR", DRV_FIXED), + MTK_PIN(165, "AP2UP_INT", DRV_FIXED), + MTK_PIN(166, "AP2UP_INT_CLR", DRV_FIXED), + MTK_PIN(167, "UP2AP_INT", DRV_FIXED), + MTK_PIN(168, "UP2AP_INT_CLR", DRV_FIXED), + MTK_PIN(169, "RAMBUF_ADDR0", DRV_FIXED), + MTK_PIN(170, "RAMBUF_ADDR1", DRV_FIXED), + MTK_PIN(171, "RAMBUF_ADDR2", DRV_FIXED), + MTK_PIN(172, "RAMBUF_ADDR3", DRV_FIXED), + MTK_PIN(173, "RAMBUF_ADDR4", DRV_FIXED), + MTK_PIN(174, "RAMBUF_ADDR5", DRV_FIXED), + MTK_PIN(175, "RAMBUF_ADDR6", DRV_FIXED), + MTK_PIN(176, "RAMBUF_ADDR7", DRV_FIXED), + MTK_PIN(177, "RAMBUF_ADDR8", DRV_FIXED), + MTK_PIN(178, "RAMBUF_ADDR9", DRV_FIXED), + MTK_PIN(179, "RAMBUF_ADDR10", DRV_FIXED), + MTK_PIN(180, "RAMBUF_RW", DRV_FIXED), + MTK_PIN(181, "RAMBUF_LAST", DRV_FIXED), + MTK_PIN(182, "RAMBUF_HP", DRV_FIXED), + MTK_PIN(183, "RAMBUF_REQ", DRV_FIXED), + MTK_PIN(184, "RAMBUF_ALE", DRV_FIXED), + MTK_PIN(185, "RAMBUF_DLE", DRV_FIXED), + MTK_PIN(186, "RAMBUF_WDLE", DRV_FIXED), + MTK_PIN(187, "RAMBUF_O_CLK", DRV_FIXED), + MTK_PIN(188, "I2S2_MCLK", DRV_GRP1), + MTK_PIN(189, "I2S3_DATA", DRV_GRP1), + MTK_PIN(190, "I2S3_DATA_IN", DRV_GRP1), + MTK_PIN(191, "I2S3_BCK", DRV_GRP1), + MTK_PIN(192, "I2S3_LRCK", DRV_GRP1), + MTK_PIN(193, "I2S3_MCLK", DRV_GRP1), + MTK_PIN(194, "I2S4_DATA", DRV_GRP1), + MTK_PIN(195, "I2S4_DATA_IN", DRV_GRP1), + MTK_PIN(196, "I2S4_BCK", DRV_GRP1), + MTK_PIN(197, "I2S4_LRCK", DRV_GRP1), + MTK_PIN(198, "I2S4_MCLK", DRV_GRP1), + MTK_PIN(199, "SPI1_CLK", DRV_GRP3), + MTK_PIN(200, "SPDIF_OUT", DRV_GRP1), + MTK_PIN(201, "SPDIF_IN0", DRV_GRP1), + MTK_PIN(202, "SPDIF_IN1", DRV_GRP1), + MTK_PIN(203, "PWM0", DRV_GRP1), + MTK_PIN(204, "PWM1", DRV_GRP1), + MTK_PIN(205, "PWM2", DRV_GRP1), + MTK_PIN(206, "PWM3", DRV_GRP1), + MTK_PIN(207, "PWM4", DRV_GRP1), + MTK_PIN(208, "AUD_EXT_CK1", DRV_GRP1), + MTK_PIN(209, "AUD_EXT_CK2", DRV_GRP1), + MTK_PIN(210, "AUD_CLOCK", DRV_GRP3), + MTK_PIN(211, "DVP_RESET", DRV_GRP3), + MTK_PIN(212, "DVP_CLOCK", DRV_GRP3), + MTK_PIN(213, "DVP_CS", DRV_GRP3), + MTK_PIN(214, "DVP_CK", DRV_GRP3), + MTK_PIN(215, "DVP_DI", DRV_GRP3), + MTK_PIN(216, "DVP_DO", DRV_GRP3), + MTK_PIN(217, "AP_CS", DRV_GRP3), + MTK_PIN(218, "AP_CK", DRV_GRP3), + MTK_PIN(219, "AP_DI", DRV_GRP3), + MTK_PIN(220, "AP_DO", DRV_GRP3), + MTK_PIN(221, "DVD_BCLK", DRV_GRP3), + MTK_PIN(222, "T8032_CLK", DRV_GRP3), + MTK_PIN(223, "AP_BCLK", DRV_GRP3), + MTK_PIN(224, "HOST_CS", DRV_GRP3), + MTK_PIN(225, "HOST_CK", DRV_GRP3), + MTK_PIN(226, "HOST_DO0", DRV_GRP3), + MTK_PIN(227, "HOST_DO1", DRV_GRP3), + MTK_PIN(228, "SLV_CS", DRV_GRP3), + MTK_PIN(229, "SLV_CK", DRV_GRP3), + MTK_PIN(230, "SLV_DI0", DRV_GRP3), + MTK_PIN(231, "SLV_DI1", DRV_GRP3), + MTK_PIN(232, "AP2DSP_INT", DRV_GRP3), + MTK_PIN(233, "AP2DSP_INT_CLR", DRV_GRP3), + MTK_PIN(234, "DSP2AP_INT", DRV_GRP3), + MTK_PIN(235, "DSP2AP_INT_CLR", DRV_GRP3), + MTK_PIN(236, "EXT_SDIO3", DRV_GRP1), + MTK_PIN(237, "EXT_SDIO2", DRV_GRP1), + MTK_PIN(238, "EXT_SDIO1", DRV_GRP1), + MTK_PIN(239, "EXT_SDIO0", DRV_GRP1), + MTK_PIN(240, "EXT_XCS", DRV_GRP1), + MTK_PIN(241, "EXT_SCK", DRV_GRP1), + MTK_PIN(242, "URTS2", DRV_GRP1), + MTK_PIN(243, "UCTS2", DRV_GRP1), + MTK_PIN(244, "HDMI_SDA_RX", DRV_FIXED), + MTK_PIN(245, "HDMI_SCL_RX", DRV_FIXED), + MTK_PIN(246, "MHL_SENCE", DRV_FIXED), + MTK_PIN(247, "HDMI_HPD_CBUS_RX", DRV_FIXED), + MTK_PIN(248, "HDMI_TESTOUTP_RX", DRV_GRP1), + MTK_PIN(249, "MSDC0E_RSTB", DRV_GRP4), + MTK_PIN(250, "MSDC0E_DAT7", DRV_GRP4), + MTK_PIN(251, "MSDC0E_DAT6", DRV_GRP4), + MTK_PIN(252, "MSDC0E_DAT5", DRV_GRP4), + MTK_PIN(253, "MSDC0E_DAT4", DRV_GRP4), + MTK_PIN(254, "MSDC0E_DAT3", DRV_GRP4), + MTK_PIN(255, "MSDC0E_DAT2", DRV_GRP4), + MTK_PIN(256, "MSDC0E_DAT1", DRV_GRP4), + MTK_PIN(257, "MSDC0E_DAT0", DRV_GRP4), + MTK_PIN(258, "MSDC0E_CMD", DRV_GRP4), + MTK_PIN(259, "MSDC0E_CLK", DRV_GRP4), + MTK_PIN(260, "MSDC0E_DSL", DRV_GRP4), + MTK_PIN(261, "MSDC1_INS", DRV_GRP4), + MTK_PIN(262, "G2_TXEN", DRV_GRP1), + MTK_PIN(263, "G2_TXD3", DRV_GRP1), + MTK_PIN(264, "G2_TXD2", DRV_GRP1), + MTK_PIN(265, "G2_TXD1", DRV_GRP1), + MTK_PIN(266, "G2_TXD0", DRV_GRP1), + MTK_PIN(267, "G2_TXC", DRV_GRP1), + MTK_PIN(268, "G2_RXC", DRV_GRP1), + MTK_PIN(269, "G2_RXD0", DRV_GRP1), + MTK_PIN(270, "G2_RXD1", DRV_GRP1), + MTK_PIN(271, "G2_RXD2", DRV_GRP1), + MTK_PIN(272, "G2_RXD3", DRV_GRP1), + MTK_PIN(273, "ESW_INT", DRV_GRP1), + MTK_PIN(274, "G2_RXDV", DRV_GRP1), + MTK_PIN(275, "MDC", DRV_GRP1), + MTK_PIN(276, "MDIO", DRV_GRP1), + MTK_PIN(277, "ESW_RST", DRV_GRP1), + MTK_PIN(278, "JTAG_RESET", DRV_GRP3), + MTK_PIN(279, "USB3_RES_BOND", DRV_GRP1), +}; + +/* List all groups consisting of these pins dedicated to the enablement of + * certain hardware block and the corresponding mode for all of the pins. + * The hardware probably has multiple combinations of these pinouts. + */ + +/* AUDIO EXT CLK */ +static int mt7623_aud_ext_clk0_pins[] = { 208, }; +static int mt7623_aud_ext_clk0_funcs[] = { 1, }; +static int mt7623_aud_ext_clk1_pins[] = { 209, }; +static int mt7623_aud_ext_clk1_funcs[] = { 1, }; + +/* DISP PWM */ +static int mt7623_disp_pwm_0_pins[] = { 72, }; +static int mt7623_disp_pwm_0_funcs[] = { 5, }; +static int mt7623_disp_pwm_1_pins[] = { 203, }; +static int mt7623_disp_pwm_1_funcs[] = { 2, }; +static int mt7623_disp_pwm_2_pins[] = { 208, }; +static int mt7623_disp_pwm_2_funcs[] = { 5, }; + +/* ESW */ +static int mt7623_esw_int_pins[] = { 273, }; +static int mt7623_esw_int_funcs[] = { 1, }; +static int mt7623_esw_rst_pins[] = { 277, }; +static int mt7623_esw_rst_funcs[] = { 1, }; + +/* EPHY */ +static int mt7623_ephy_pins[] = { 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 274, }; +static int mt7623_ephy_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* EXT_SDIO */ +static int mt7623_ext_sdio_pins[] = { 236, 237, 238, 239, 240, 241, }; +static int mt7623_ext_sdio_funcs[] = { 1, 1, 1, 1, 1, 1, }; + +/* HDMI RX */ +static int mt7623_hdmi_rx_pins[] = { 247, 248, }; +static int mt7623_hdmi_rx_funcs[] = { 1, 1 }; +static int mt7623_hdmi_rx_i2c_pins[] = { 244, 245, }; +static int mt7623_hdmi_rx_i2c_funcs[] = { 1, 1 }; + +/* HDMI TX */ +static int mt7623_hdmi_cec_pins[] = { 122, }; +static int mt7623_hdmi_cec_funcs[] = { 1, }; +static int mt7623_hdmi_htplg_pins[] = { 123, }; +static int mt7623_hdmi_htplg_funcs[] = { 1, }; +static int mt7623_hdmi_i2c_pins[] = { 124, 125, }; +static int mt7623_hdmi_i2c_funcs[] = { 1, 1 }; + +/* I2C */ +static int mt7623_i2c0_pins[] = { 75, 76, }; +static int mt7623_i2c0_funcs[] = { 1, 1, }; +static int mt7623_i2c1_0_pins[] = { 57, 58, }; +static int mt7623_i2c1_0_funcs[] = { 1, 1, }; +static int mt7623_i2c1_1_pins[] = { 242, 243, }; +static int mt7623_i2c1_1_funcs[] = { 4, 4, }; +static int mt7623_i2c1_2_pins[] = { 85, 86, }; +static int mt7623_i2c1_2_funcs[] = { 3, 3, }; +static int mt7623_i2c1_3_pins[] = { 105, 106, }; +static int mt7623_i2c1_3_funcs[] = { 3, 3, }; +static int mt7623_i2c1_4_pins[] = { 124, 125, }; +static int mt7623_i2c1_4_funcs[] = { 4, 4, }; +static int mt7623_i2c2_0_pins[] = { 77, 78, }; +static int mt7623_i2c2_0_funcs[] = { 1, 1, }; +static int mt7623_i2c2_1_pins[] = { 89, 90, }; +static int mt7623_i2c2_1_funcs[] = { 3, 3, }; +static int mt7623_i2c2_2_pins[] = { 109, 110, }; +static int mt7623_i2c2_2_funcs[] = { 3, 3, }; +static int mt7623_i2c2_3_pins[] = { 122, 123, }; +static int mt7623_i2c2_3_funcs[] = { 4, 4, }; + +/* I2S */ +static int mt7623_i2s0_pins[] = { 49, 72, 73, 74, 126, }; +static int mt7623_i2s0_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s1_pins[] = { 33, 34, 35, 36, 37, }; +static int mt7623_i2s1_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s2_bclk_lrclk_mclk_pins[] = { 50, 52, 188, }; +static int mt7623_i2s2_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, }; +static int mt7623_i2s2_data_in_pins[] = { 51, }; +static int mt7623_i2s2_data_in_funcs[] = { 1, }; +static int mt7623_i2s2_data_0_pins[] = { 203, }; +static int mt7623_i2s2_data_0_funcs[] = { 9, }; +static int mt7623_i2s2_data_1_pins[] = { 38, }; +static int mt7623_i2s2_data_1_funcs[] = { 4, }; +static int mt7623_i2s3_bclk_lrclk_mclk_pins[] = { 191, 192, 193, }; +static int mt7623_i2s3_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, }; +static int mt7623_i2s3_data_in_pins[] = { 190, }; +static int mt7623_i2s3_data_in_funcs[] = { 1, }; +static int mt7623_i2s3_data_0_pins[] = { 204, }; +static int mt7623_i2s3_data_0_funcs[] = { 9, }; +static int mt7623_i2s3_data_1_pins[] = { 2, }; +static int mt7623_i2s3_data_1_funcs[] = { 0, }; +static int mt7623_i2s4_pins[] = { 194, 195, 196, 197, 198, }; +static int mt7623_i2s4_funcs[] = { 1, 1, 1, 1, 1, }; +static int mt7623_i2s5_pins[] = { 16, 17, 30, 31, 32, }; +static int mt7623_i2s5_funcs[] = { 1, 1, 1, 1, 1, }; + +/* IR */ +static int mt7623_ir_pins[] = { 46, }; +static int mt7623_ir_funcs[] = { 1, }; + +/* LCD */ +static int mt7623_mipi_tx_pins[] = { 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, }; +static int mt7623_mipi_tx_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +static int mt7623_dsi_te_pins[] = { 84, }; +static int mt7623_dsi_te_funcs[] = { 1, }; +static int mt7623_lcm_rst_pins[] = { 83, }; +static int mt7623_lcm_rst_funcs[] = { 1, }; + +/* MDC/MDIO */ +static int mt7623_mdc_mdio_pins[] = { 275, 276, }; +static int mt7623_mdc_mdio_funcs[] = { 1, 1, }; + +/* MSDC */ +static int mt7623_msdc0_pins[] = { 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, }; +static int mt7623_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc1_pins[] = { 105, 106, 107, 108, 109, 110, }; +static int mt7623_msdc1_funcs[] = { 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc1_ins_pins[] = { 261, }; +static int mt7623_msdc1_ins_funcs[] = { 1, }; +static int mt7623_msdc1_wp_0_pins[] = { 29, }; +static int mt7623_msdc1_wp_0_funcs[] = { 1, }; +static int mt7623_msdc1_wp_1_pins[] = { 55, }; +static int mt7623_msdc1_wp_1_funcs[] = { 3, }; +static int mt7623_msdc1_wp_2_pins[] = { 209, }; +static int mt7623_msdc1_wp_2_funcs[] = { 2, }; +static int mt7623_msdc2_pins[] = { 85, 86, 87, 88, 89, 90, }; +static int mt7623_msdc2_funcs[] = { 1, 1, 1, 1, 1, 1, }; +static int mt7623_msdc3_pins[] = { 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, }; +static int mt7623_msdc3_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* NAND */ +static int mt7623_nandc_pins[] = { 43, 47, 48, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, }; +static int mt7623_nandc_funcs[] = { 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, }; +static int mt7623_nandc_ceb0_pins[] = { 45, }; +static int mt7623_nandc_ceb0_funcs[] = { 1, }; +static int mt7623_nandc_ceb1_pins[] = { 44, }; +static int mt7623_nandc_ceb1_funcs[] = { 1, }; + +/* RTC */ +static int mt7623_rtc_pins[] = { 10, }; +static int mt7623_rtc_funcs[] = { 1, }; + +/* OTG */ +static int mt7623_otg_iddig0_0_pins[] = { 29, }; +static int mt7623_otg_iddig0_0_funcs[] = { 1, }; +static int mt7623_otg_iddig0_1_pins[] = { 44, }; +static int mt7623_otg_iddig0_1_funcs[] = { 2, }; +static int mt7623_otg_iddig0_2_pins[] = { 236, }; +static int mt7623_otg_iddig0_2_funcs[] = { 2, }; +static int mt7623_otg_iddig1_0_pins[] = { 27, }; +static int mt7623_otg_iddig1_0_funcs[] = { 2, }; +static int mt7623_otg_iddig1_1_pins[] = { 47, }; +static int mt7623_otg_iddig1_1_funcs[] = { 2, }; +static int mt7623_otg_iddig1_2_pins[] = { 238, }; +static int mt7623_otg_iddig1_2_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus0_0_pins[] = { 28, }; +static int mt7623_otg_drv_vbus0_0_funcs[] = { 1, }; +static int mt7623_otg_drv_vbus0_1_pins[] = { 45, }; +static int mt7623_otg_drv_vbus0_1_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus0_2_pins[] = { 237, }; +static int mt7623_otg_drv_vbus0_2_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_0_pins[] = { 26, }; +static int mt7623_otg_drv_vbus1_0_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_1_pins[] = { 48, }; +static int mt7623_otg_drv_vbus1_1_funcs[] = { 2, }; +static int mt7623_otg_drv_vbus1_2_pins[] = { 239, }; +static int mt7623_otg_drv_vbus1_2_funcs[] = { 2, }; + +/* PCIE */ +static int mt7623_pcie0_0_perst_pins[] = { 208, }; +static int mt7623_pcie0_0_perst_funcs[] = { 3, }; +static int mt7623_pcie0_1_perst_pins[] = { 22, }; +static int mt7623_pcie0_1_perst_funcs[] = { 2, }; +static int mt7623_pcie1_0_perst_pins[] = { 209, }; +static int mt7623_pcie1_0_perst_funcs[] = { 3, }; +static int mt7623_pcie1_1_perst_pins[] = { 23, }; +static int mt7623_pcie1_1_perst_funcs[] = { 2, }; +static int mt7623_pcie2_0_perst_pins[] = { 24, }; +static int mt7623_pcie2_0_perst_funcs[] = { 2, }; +static int mt7623_pcie2_1_perst_pins[] = { 29, }; +static int mt7623_pcie2_1_perst_funcs[] = { 6, }; +static int mt7623_pcie0_0_wake_pins[] = { 28, }; +static int mt7623_pcie0_0_wake_funcs[] = { 6, }; +static int mt7623_pcie0_1_wake_pins[] = { 251, }; +static int mt7623_pcie0_1_wake_funcs[] = { 6, }; +static int mt7623_pcie1_0_wake_pins[] = { 27, }; +static int mt7623_pcie1_0_wake_funcs[] = { 6, }; +static int mt7623_pcie1_1_wake_pins[] = { 253, }; +static int mt7623_pcie1_1_wake_funcs[] = { 6, }; +static int mt7623_pcie2_0_wake_pins[] = { 26, }; +static int mt7623_pcie2_0_wake_funcs[] = { 6, }; +static int mt7623_pcie2_1_wake_pins[] = { 255, }; +static int mt7623_pcie2_1_wake_funcs[] = { 6, }; +static int mt7623_pcie0_clkreq_pins[] = { 250, }; +static int mt7623_pcie0_clkreq_funcs[] = { 6, }; +static int mt7623_pcie1_clkreq_pins[] = { 252, }; +static int mt7623_pcie1_clkreq_funcs[] = { 6, }; +static int mt7623_pcie2_clkreq_pins[] = { 254, }; +static int mt7623_pcie2_clkreq_funcs[] = { 6, }; +/* the pcie_*_rev are only used for MT7623 */ +static int mt7623_pcie0_0_rev_perst_pins[] = { 208, }; +static int mt7623_pcie0_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie0_1_rev_perst_pins[] = { 22, }; +static int mt7623_pcie0_1_rev_perst_funcs[] = { 10, }; +static int mt7623_pcie1_0_rev_perst_pins[] = { 209, }; +static int mt7623_pcie1_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie1_1_rev_perst_pins[] = { 23, }; +static int mt7623_pcie1_1_rev_perst_funcs[] = { 10, }; +static int mt7623_pcie2_0_rev_perst_pins[] = { 24, }; +static int mt7623_pcie2_0_rev_perst_funcs[] = { 11, }; +static int mt7623_pcie2_1_rev_perst_pins[] = { 29, }; +static int mt7623_pcie2_1_rev_perst_funcs[] = { 14, }; + +/* PCM */ +static int mt7623_pcm_clk_0_pins[] = { 18, }; +static int mt7623_pcm_clk_0_funcs[] = { 1, }; +static int mt7623_pcm_clk_1_pins[] = { 17, }; +static int mt7623_pcm_clk_1_funcs[] = { 3, }; +static int mt7623_pcm_clk_2_pins[] = { 35, }; +static int mt7623_pcm_clk_2_funcs[] = { 3, }; +static int mt7623_pcm_clk_3_pins[] = { 50, }; +static int mt7623_pcm_clk_3_funcs[] = { 3, }; +static int mt7623_pcm_clk_4_pins[] = { 74, }; +static int mt7623_pcm_clk_4_funcs[] = { 3, }; +static int mt7623_pcm_clk_5_pins[] = { 191, }; +static int mt7623_pcm_clk_5_funcs[] = { 3, }; +static int mt7623_pcm_clk_6_pins[] = { 196, }; +static int mt7623_pcm_clk_6_funcs[] = { 3, }; +static int mt7623_pcm_sync_0_pins[] = { 19, }; +static int mt7623_pcm_sync_0_funcs[] = { 1, }; +static int mt7623_pcm_sync_1_pins[] = { 30, }; +static int mt7623_pcm_sync_1_funcs[] = { 3, }; +static int mt7623_pcm_sync_2_pins[] = { 36, }; +static int mt7623_pcm_sync_2_funcs[] = { 3, }; +static int mt7623_pcm_sync_3_pins[] = { 52, }; +static int mt7623_pcm_sync_3_funcs[] = { 31, }; +static int mt7623_pcm_sync_4_pins[] = { 73, }; +static int mt7623_pcm_sync_4_funcs[] = { 3, }; +static int mt7623_pcm_sync_5_pins[] = { 192, }; +static int mt7623_pcm_sync_5_funcs[] = { 3, }; +static int mt7623_pcm_sync_6_pins[] = { 197, }; +static int mt7623_pcm_sync_6_funcs[] = { 3, }; +static int mt7623_pcm_rx_0_pins[] = { 20, }; +static int mt7623_pcm_rx_0_funcs[] = { 1, }; +static int mt7623_pcm_rx_1_pins[] = { 16, }; +static int mt7623_pcm_rx_1_funcs[] = { 3, }; +static int mt7623_pcm_rx_2_pins[] = { 34, }; +static int mt7623_pcm_rx_2_funcs[] = { 3, }; +static int mt7623_pcm_rx_3_pins[] = { 51, }; +static int mt7623_pcm_rx_3_funcs[] = { 3, }; +static int mt7623_pcm_rx_4_pins[] = { 72, }; +static int mt7623_pcm_rx_4_funcs[] = { 3, }; +static int mt7623_pcm_rx_5_pins[] = { 190, }; +static int mt7623_pcm_rx_5_funcs[] = { 3, }; +static int mt7623_pcm_rx_6_pins[] = { 195, }; +static int mt7623_pcm_rx_6_funcs[] = { 3, }; +static int mt7623_pcm_tx_0_pins[] = { 21, }; +static int mt7623_pcm_tx_0_funcs[] = { 1, }; +static int mt7623_pcm_tx_1_pins[] = { 32, }; +static int mt7623_pcm_tx_1_funcs[] = { 3, }; +static int mt7623_pcm_tx_2_pins[] = { 33, }; +static int mt7623_pcm_tx_2_funcs[] = { 3, }; +static int mt7623_pcm_tx_3_pins[] = { 38, }; +static int mt7623_pcm_tx_3_funcs[] = { 3, }; +static int mt7623_pcm_tx_4_pins[] = { 49, }; +static int mt7623_pcm_tx_4_funcs[] = { 3, }; +static int mt7623_pcm_tx_5_pins[] = { 189, }; +static int mt7623_pcm_tx_5_funcs[] = { 3, }; +static int mt7623_pcm_tx_6_pins[] = { 194, }; +static int mt7623_pcm_tx_6_funcs[] = { 3, }; + +/* PWM */ +static int mt7623_pwm_ch1_0_pins[] = { 203, }; +static int mt7623_pwm_ch1_0_funcs[] = { 1, }; +static int mt7623_pwm_ch1_1_pins[] = { 208, }; +static int mt7623_pwm_ch1_1_funcs[] = { 2, }; +static int mt7623_pwm_ch1_2_pins[] = { 72, }; +static int mt7623_pwm_ch1_2_funcs[] = { 4, }; +static int mt7623_pwm_ch1_3_pins[] = { 88, }; +static int mt7623_pwm_ch1_3_funcs[] = { 3, }; +static int mt7623_pwm_ch1_4_pins[] = { 108, }; +static int mt7623_pwm_ch1_4_funcs[] = { 3, }; +static int mt7623_pwm_ch2_0_pins[] = { 204, }; +static int mt7623_pwm_ch2_0_funcs[] = { 1, }; +static int mt7623_pwm_ch2_1_pins[] = { 53, }; +static int mt7623_pwm_ch2_1_funcs[] = { 5, }; +static int mt7623_pwm_ch2_2_pins[] = { 88, }; +static int mt7623_pwm_ch2_2_funcs[] = { 6, }; +static int mt7623_pwm_ch2_3_pins[] = { 108, }; +static int mt7623_pwm_ch2_3_funcs[] = { 6, }; +static int mt7623_pwm_ch2_4_pins[] = { 209, }; +static int mt7623_pwm_ch2_4_funcs[] = { 5, }; +static int mt7623_pwm_ch3_0_pins[] = { 205, }; +static int mt7623_pwm_ch3_0_funcs[] = { 1, }; +static int mt7623_pwm_ch3_1_pins[] = { 55, }; +static int mt7623_pwm_ch3_1_funcs[] = { 5, }; +static int mt7623_pwm_ch3_2_pins[] = { 89, }; +static int mt7623_pwm_ch3_2_funcs[] = { 6, }; +static int mt7623_pwm_ch3_3_pins[] = { 109, }; +static int mt7623_pwm_ch3_3_funcs[] = { 6, }; +static int mt7623_pwm_ch4_0_pins[] = { 206, }; +static int mt7623_pwm_ch4_0_funcs[] = { 1, }; +static int mt7623_pwm_ch4_1_pins[] = { 90, }; +static int mt7623_pwm_ch4_1_funcs[] = { 6, }; +static int mt7623_pwm_ch4_2_pins[] = { 110, }; +static int mt7623_pwm_ch4_2_funcs[] = { 6, }; +static int mt7623_pwm_ch4_3_pins[] = { 124, }; +static int mt7623_pwm_ch4_3_funcs[] = { 5, }; +static int mt7623_pwm_ch5_0_pins[] = { 207, }; +static int mt7623_pwm_ch5_0_funcs[] = { 1, }; +static int mt7623_pwm_ch5_1_pins[] = { 125, }; +static int mt7623_pwm_ch5_1_funcs[] = { 5, }; + +/* PWRAP */ +static int mt7623_pwrap_pins[] = { 0, 1, 2, 3, 4, 5, 6, }; +static int mt7623_pwrap_funcs[] = { 1, 1, 1, 1, 1, 1, 1, }; + +/* SPDIF */ +static int mt7623_spdif_in0_0_pins[] = { 56, }; +static int mt7623_spdif_in0_0_funcs[] = { 3, }; +static int mt7623_spdif_in0_1_pins[] = { 201, }; +static int mt7623_spdif_in0_1_funcs[] = { 1, }; +static int mt7623_spdif_in1_0_pins[] = { 54, }; +static int mt7623_spdif_in1_0_funcs[] = { 3, }; +static int mt7623_spdif_in1_1_pins[] = { 202, }; +static int mt7623_spdif_in1_1_funcs[] = { 1, }; +static int mt7623_spdif_out_pins[] = { 202, }; +static int mt7623_spdif_out_funcs[] = { 1, }; + +/* SPI */ +static int mt7623_spi0_pins[] = { 53, 54, 55, 56, }; +static int mt7623_spi0_funcs[] = { 1, 1, 1, 1, }; +static int mt7623_spi1_pins[] = { 7, 199, 8, 9, }; +static int mt7623_spi1_funcs[] = { 1, 1, 1, 1, }; +static int mt7623_spi2_pins[] = { 101, 104, 102, 103, }; +static int mt7623_spi2_funcs[] = { 1, 1, 1, 1, }; + +/* UART */ +static int mt7623_uart0_0_txd_rxd_pins[] = { 79, 80, }; +static int mt7623_uart0_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart0_1_txd_rxd_pins[] = { 87, 88, }; +static int mt7623_uart0_1_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_2_txd_rxd_pins[] = { 107, 108, }; +static int mt7623_uart0_2_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_3_txd_rxd_pins[] = { 123, 122, }; +static int mt7623_uart0_3_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart0_rts_cts_pins[] = { 22, 23, }; +static int mt7623_uart0_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart1_0_txd_rxd_pins[] = { 81, 82, }; +static int mt7623_uart1_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart1_1_txd_rxd_pins[] = { 89, 90, }; +static int mt7623_uart1_1_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart1_2_txd_rxd_pins[] = { 109, 110, }; +static int mt7623_uart1_2_txd_rxd_funcs[] = { 5, 5, }; +static int mt7623_uart1_rts_cts_pins[] = { 24, 25, }; +static int mt7623_uart1_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart2_0_txd_rxd_pins[] = { 14, 15, }; +static int mt7623_uart2_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7623_uart2_1_txd_rxd_pins[] = { 200, 201, }; +static int mt7623_uart2_1_txd_rxd_funcs[] = { 6, 6, }; +static int mt7623_uart2_rts_cts_pins[] = { 242, 243, }; +static int mt7623_uart2_rts_cts_funcs[] = { 1, 1, }; +static int mt7623_uart3_txd_rxd_pins[] = { 242, 243, }; +static int mt7623_uart3_txd_rxd_funcs[] = { 2, 2, }; +static int mt7623_uart3_rts_cts_pins[] = { 26, 27, }; +static int mt7623_uart3_rts_cts_funcs[] = { 1, 1, }; + +/* Watchdog */ +static int mt7623_watchdog_0_pins[] = { 11, }; +static int mt7623_watchdog_0_funcs[] = { 1, }; +static int mt7623_watchdog_1_pins[] = { 121, }; +static int mt7623_watchdog_1_funcs[] = { 5, }; + +static const struct mtk_group_desc mt7623_groups[] = { + PINCTRL_PIN_GROUP("aud_ext_clk0", mt7623_aud_ext_clk0), + PINCTRL_PIN_GROUP("aud_ext_clk1", mt7623_aud_ext_clk1), + PINCTRL_PIN_GROUP("dsi_te", mt7623_dsi_te), + PINCTRL_PIN_GROUP("disp_pwm_0", mt7623_disp_pwm_0), + PINCTRL_PIN_GROUP("disp_pwm_1", mt7623_disp_pwm_1), + PINCTRL_PIN_GROUP("disp_pwm_2", mt7623_disp_pwm_2), + PINCTRL_PIN_GROUP("ephy", mt7623_ephy), + PINCTRL_PIN_GROUP("esw_int", mt7623_esw_int), + PINCTRL_PIN_GROUP("esw_rst", mt7623_esw_rst), + PINCTRL_PIN_GROUP("ext_sdio", mt7623_ext_sdio), + PINCTRL_PIN_GROUP("hdmi_cec", mt7623_hdmi_cec), + PINCTRL_PIN_GROUP("hdmi_htplg", mt7623_hdmi_htplg), + PINCTRL_PIN_GROUP("hdmi_i2c", mt7623_hdmi_i2c), + PINCTRL_PIN_GROUP("hdmi_rx", mt7623_hdmi_rx), + PINCTRL_PIN_GROUP("hdmi_rx_i2c", mt7623_hdmi_rx_i2c), + PINCTRL_PIN_GROUP("i2c0", mt7623_i2c0), + PINCTRL_PIN_GROUP("i2c1_0", mt7623_i2c1_0), + PINCTRL_PIN_GROUP("i2c1_1", mt7623_i2c1_1), + PINCTRL_PIN_GROUP("i2c1_2", mt7623_i2c1_2), + PINCTRL_PIN_GROUP("i2c1_3", mt7623_i2c1_3), + PINCTRL_PIN_GROUP("i2c1_4", mt7623_i2c1_4), + PINCTRL_PIN_GROUP("i2c2_0", mt7623_i2c2_0), + PINCTRL_PIN_GROUP("i2c2_1", mt7623_i2c2_1), + PINCTRL_PIN_GROUP("i2c2_2", mt7623_i2c2_2), + PINCTRL_PIN_GROUP("i2c2_3", mt7623_i2c2_3), + PINCTRL_PIN_GROUP("i2s0", mt7623_i2s0), + PINCTRL_PIN_GROUP("i2s1", mt7623_i2s1), + PINCTRL_PIN_GROUP("i2s4", mt7623_i2s4), + PINCTRL_PIN_GROUP("i2s5", mt7623_i2s5), + PINCTRL_PIN_GROUP("i2s2_bclk_lrclk_mclk", mt7623_i2s2_bclk_lrclk_mclk), + PINCTRL_PIN_GROUP("i2s3_bclk_lrclk_mclk", mt7623_i2s3_bclk_lrclk_mclk), + PINCTRL_PIN_GROUP("i2s2_data_in", mt7623_i2s2_data_in), + PINCTRL_PIN_GROUP("i2s3_data_in", mt7623_i2s3_data_in), + PINCTRL_PIN_GROUP("i2s2_data_0", mt7623_i2s2_data_0), + PINCTRL_PIN_GROUP("i2s2_data_1", mt7623_i2s2_data_1), + PINCTRL_PIN_GROUP("i2s3_data_0", mt7623_i2s3_data_0), + PINCTRL_PIN_GROUP("i2s3_data_1", mt7623_i2s3_data_1), + PINCTRL_PIN_GROUP("ir", mt7623_ir), + PINCTRL_PIN_GROUP("lcm_rst", mt7623_lcm_rst), + PINCTRL_PIN_GROUP("mdc_mdio", mt7623_mdc_mdio), + PINCTRL_PIN_GROUP("mipi_tx", mt7623_mipi_tx), + PINCTRL_PIN_GROUP("msdc0", mt7623_msdc0), + PINCTRL_PIN_GROUP("msdc1", mt7623_msdc1), + PINCTRL_PIN_GROUP("msdc1_ins", mt7623_msdc1_ins), + PINCTRL_PIN_GROUP("msdc1_wp_0", mt7623_msdc1_wp_0), + PINCTRL_PIN_GROUP("msdc1_wp_1", mt7623_msdc1_wp_1), + PINCTRL_PIN_GROUP("msdc1_wp_2", mt7623_msdc1_wp_2), + PINCTRL_PIN_GROUP("msdc2", mt7623_msdc2), + PINCTRL_PIN_GROUP("msdc3", mt7623_msdc3), + PINCTRL_PIN_GROUP("nandc", mt7623_nandc), + PINCTRL_PIN_GROUP("nandc_ceb0", mt7623_nandc_ceb0), + PINCTRL_PIN_GROUP("nandc_ceb1", mt7623_nandc_ceb1), + PINCTRL_PIN_GROUP("otg_iddig0_0", mt7623_otg_iddig0_0), + PINCTRL_PIN_GROUP("otg_iddig0_1", mt7623_otg_iddig0_1), + PINCTRL_PIN_GROUP("otg_iddig0_2", mt7623_otg_iddig0_2), + PINCTRL_PIN_GROUP("otg_iddig1_0", mt7623_otg_iddig1_0), + PINCTRL_PIN_GROUP("otg_iddig1_1", mt7623_otg_iddig1_1), + PINCTRL_PIN_GROUP("otg_iddig1_2", mt7623_otg_iddig1_2), + PINCTRL_PIN_GROUP("otg_drv_vbus0_0", mt7623_otg_drv_vbus0_0), + PINCTRL_PIN_GROUP("otg_drv_vbus0_1", mt7623_otg_drv_vbus0_1), + PINCTRL_PIN_GROUP("otg_drv_vbus0_2", mt7623_otg_drv_vbus0_2), + PINCTRL_PIN_GROUP("otg_drv_vbus1_0", mt7623_otg_drv_vbus1_0), + PINCTRL_PIN_GROUP("otg_drv_vbus1_1", mt7623_otg_drv_vbus1_1), + PINCTRL_PIN_GROUP("otg_drv_vbus1_2", mt7623_otg_drv_vbus1_2), + PINCTRL_PIN_GROUP("pcie0_0_perst", mt7623_pcie0_0_perst), + PINCTRL_PIN_GROUP("pcie0_1_perst", mt7623_pcie0_1_perst), + PINCTRL_PIN_GROUP("pcie1_0_perst", mt7623_pcie1_0_perst), + PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst), + PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst), + PINCTRL_PIN_GROUP("pcie0_0_rev_perst", mt7623_pcie0_0_rev_perst), + PINCTRL_PIN_GROUP("pcie0_1_rev_perst", mt7623_pcie0_1_rev_perst), + PINCTRL_PIN_GROUP("pcie1_0_rev_perst", mt7623_pcie1_0_rev_perst), + PINCTRL_PIN_GROUP("pcie1_1_rev_perst", mt7623_pcie1_1_rev_perst), + PINCTRL_PIN_GROUP("pcie2_0_rev_perst", mt7623_pcie2_0_rev_perst), + PINCTRL_PIN_GROUP("pcie2_1_rev_perst", mt7623_pcie2_1_rev_perst), + PINCTRL_PIN_GROUP("pcie2_0_perst", mt7623_pcie2_0_perst), + PINCTRL_PIN_GROUP("pcie2_1_perst", mt7623_pcie2_1_perst), + PINCTRL_PIN_GROUP("pcie0_0_wake", mt7623_pcie0_0_wake), + PINCTRL_PIN_GROUP("pcie0_1_wake", mt7623_pcie0_1_wake), + PINCTRL_PIN_GROUP("pcie1_0_wake", mt7623_pcie1_0_wake), + PINCTRL_PIN_GROUP("pcie1_1_wake", mt7623_pcie1_1_wake), + PINCTRL_PIN_GROUP("pcie2_0_wake", mt7623_pcie2_0_wake), + PINCTRL_PIN_GROUP("pcie2_1_wake", mt7623_pcie2_1_wake), + PINCTRL_PIN_GROUP("pcie0_clkreq", mt7623_pcie0_clkreq), + PINCTRL_PIN_GROUP("pcie1_clkreq", mt7623_pcie1_clkreq), + PINCTRL_PIN_GROUP("pcie2_clkreq", mt7623_pcie2_clkreq), + PINCTRL_PIN_GROUP("pcm_clk_0", mt7623_pcm_clk_0), + PINCTRL_PIN_GROUP("pcm_clk_1", mt7623_pcm_clk_1), + PINCTRL_PIN_GROUP("pcm_clk_2", mt7623_pcm_clk_2), + PINCTRL_PIN_GROUP("pcm_clk_3", mt7623_pcm_clk_3), + PINCTRL_PIN_GROUP("pcm_clk_4", mt7623_pcm_clk_4), + PINCTRL_PIN_GROUP("pcm_clk_5", mt7623_pcm_clk_5), + PINCTRL_PIN_GROUP("pcm_clk_6", mt7623_pcm_clk_6), + PINCTRL_PIN_GROUP("pcm_sync_0", mt7623_pcm_sync_0), + PINCTRL_PIN_GROUP("pcm_sync_1", mt7623_pcm_sync_1), + PINCTRL_PIN_GROUP("pcm_sync_2", mt7623_pcm_sync_2), + PINCTRL_PIN_GROUP("pcm_sync_3", mt7623_pcm_sync_3), + PINCTRL_PIN_GROUP("pcm_sync_4", mt7623_pcm_sync_4), + PINCTRL_PIN_GROUP("pcm_sync_5", mt7623_pcm_sync_5), + PINCTRL_PIN_GROUP("pcm_sync_6", mt7623_pcm_sync_6), + PINCTRL_PIN_GROUP("pcm_rx_0", mt7623_pcm_rx_0), + PINCTRL_PIN_GROUP("pcm_rx_1", mt7623_pcm_rx_1), + PINCTRL_PIN_GROUP("pcm_rx_2", mt7623_pcm_rx_2), + PINCTRL_PIN_GROUP("pcm_rx_3", mt7623_pcm_rx_3), + PINCTRL_PIN_GROUP("pcm_rx_4", mt7623_pcm_rx_4), + PINCTRL_PIN_GROUP("pcm_rx_5", mt7623_pcm_rx_5), + PINCTRL_PIN_GROUP("pcm_rx_6", mt7623_pcm_rx_6), + PINCTRL_PIN_GROUP("pcm_tx_0", mt7623_pcm_tx_0), + PINCTRL_PIN_GROUP("pcm_tx_1", mt7623_pcm_tx_1), + PINCTRL_PIN_GROUP("pcm_tx_2", mt7623_pcm_tx_2), + PINCTRL_PIN_GROUP("pcm_tx_3", mt7623_pcm_tx_3), + PINCTRL_PIN_GROUP("pcm_tx_4", mt7623_pcm_tx_4), + PINCTRL_PIN_GROUP("pcm_tx_5", mt7623_pcm_tx_5), + PINCTRL_PIN_GROUP("pcm_tx_6", mt7623_pcm_tx_6), + PINCTRL_PIN_GROUP("pwm_ch1_0", mt7623_pwm_ch1_0), + PINCTRL_PIN_GROUP("pwm_ch1_1", mt7623_pwm_ch1_1), + PINCTRL_PIN_GROUP("pwm_ch1_2", mt7623_pwm_ch1_2), + PINCTRL_PIN_GROUP("pwm_ch1_3", mt7623_pwm_ch1_3), + PINCTRL_PIN_GROUP("pwm_ch1_4", mt7623_pwm_ch1_4), + PINCTRL_PIN_GROUP("pwm_ch2_0", mt7623_pwm_ch2_0), + PINCTRL_PIN_GROUP("pwm_ch2_1", mt7623_pwm_ch2_1), + PINCTRL_PIN_GROUP("pwm_ch2_2", mt7623_pwm_ch2_2), + PINCTRL_PIN_GROUP("pwm_ch2_3", mt7623_pwm_ch2_3), + PINCTRL_PIN_GROUP("pwm_ch2_4", mt7623_pwm_ch2_4), + PINCTRL_PIN_GROUP("pwm_ch3_0", mt7623_pwm_ch3_0), + PINCTRL_PIN_GROUP("pwm_ch3_1", mt7623_pwm_ch3_1), + PINCTRL_PIN_GROUP("pwm_ch3_2", mt7623_pwm_ch3_2), + PINCTRL_PIN_GROUP("pwm_ch3_3", mt7623_pwm_ch3_3), + PINCTRL_PIN_GROUP("pwm_ch4_0", mt7623_pwm_ch4_0), + PINCTRL_PIN_GROUP("pwm_ch4_1", mt7623_pwm_ch4_1), + PINCTRL_PIN_GROUP("pwm_ch4_2", mt7623_pwm_ch4_2), + PINCTRL_PIN_GROUP("pwm_ch4_3", mt7623_pwm_ch4_3), + PINCTRL_PIN_GROUP("pwm_ch5_0", mt7623_pwm_ch5_0), + PINCTRL_PIN_GROUP("pwm_ch5_1", mt7623_pwm_ch5_1), + PINCTRL_PIN_GROUP("pwrap", mt7623_pwrap), + PINCTRL_PIN_GROUP("rtc", mt7623_rtc), + PINCTRL_PIN_GROUP("spdif_in0_0", mt7623_spdif_in0_0), + PINCTRL_PIN_GROUP("spdif_in0_1", mt7623_spdif_in0_1), + PINCTRL_PIN_GROUP("spdif_in1_0", mt7623_spdif_in1_0), + PINCTRL_PIN_GROUP("spdif_in1_1", mt7623_spdif_in1_1), + PINCTRL_PIN_GROUP("spdif_out", mt7623_spdif_out), + PINCTRL_PIN_GROUP("spi0", mt7623_spi0), + PINCTRL_PIN_GROUP("spi1", mt7623_spi1), + PINCTRL_PIN_GROUP("spi2", mt7623_spi2), + PINCTRL_PIN_GROUP("uart0_0_txd_rxd", mt7623_uart0_0_txd_rxd), + PINCTRL_PIN_GROUP("uart0_1_txd_rxd", mt7623_uart0_1_txd_rxd), + PINCTRL_PIN_GROUP("uart0_2_txd_rxd", mt7623_uart0_2_txd_rxd), + PINCTRL_PIN_GROUP("uart0_3_txd_rxd", mt7623_uart0_3_txd_rxd), + PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7623_uart1_0_txd_rxd), + PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7623_uart1_1_txd_rxd), + PINCTRL_PIN_GROUP("uart1_2_txd_rxd", mt7623_uart1_2_txd_rxd), + PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7623_uart2_0_txd_rxd), + PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7623_uart2_1_txd_rxd), + PINCTRL_PIN_GROUP("uart3_txd_rxd", mt7623_uart3_txd_rxd), + PINCTRL_PIN_GROUP("uart0_rts_cts", mt7623_uart0_rts_cts), + PINCTRL_PIN_GROUP("uart1_rts_cts", mt7623_uart1_rts_cts), + PINCTRL_PIN_GROUP("uart2_rts_cts", mt7623_uart2_rts_cts), + PINCTRL_PIN_GROUP("uart3_rts_cts", mt7623_uart3_rts_cts), + PINCTRL_PIN_GROUP("watchdog_0", mt7623_watchdog_0), + PINCTRL_PIN_GROUP("watchdog_1", mt7623_watchdog_1), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ + +static const char *const mt7623_aud_clk_groups[] = { "aud_ext_clk0", + "aud_ext_clk1", }; +static const char *const mt7623_disp_pwm_groups[] = { "disp_pwm_0", + "disp_pwm_1", + "disp_pwm_2", }; +static const char *const mt7623_ethernet_groups[] = { "esw_int", "esw_rst", + "ephy", "mdc_mdio", }; +static const char *const mt7623_ext_sdio_groups[] = { "ext_sdio", }; +static const char *const mt7623_hdmi_groups[] = { "hdmi_cec", "hdmi_htplg", + "hdmi_i2c", "hdmi_rx", + "hdmi_rx_i2c", }; +static const char *const mt7623_i2c_groups[] = { "i2c0", "i2c1_0", "i2c1_1", + "i2c1_2", "i2c1_3", "i2c1_4", + "i2c2_0", "i2c2_1", "i2c2_2", + "i2c2_3", }; +static const char *const mt7623_i2s_groups[] = { "i2s0", "i2s1", + "i2s2_bclk_lrclk_mclk", + "i2s3_bclk_lrclk_mclk", + "i2s4", "i2s5", + "i2s2_data_in", "i2s3_data_in", + "i2s2_data_0", "i2s2_data_1", + "i2s3_data_0", "i2s3_data_1",}; +static const char *const mt7623_ir_groups[] = { "ir", }; +static const char *const mt7623_lcd_groups[] = { "dsi_te", "lcm_rst", + "mipi_tx", }; +static const char *const mt7623_msdc_groups[] = { "msdc0", "msdc1", + "msdc1_ins", "msdc1_wp_0", + "msdc1_wp_1", "msdc1_wp_2", + "msdc2", "msdc3", }; +static const char *const mt7623_nandc_groups[] = { "nandc", "nandc_ceb0", + "nandc_ceb1", }; +static const char *const mt7623_otg_groups[] = { "otg_iddig0_0", + "otg_iddig0_1", + "otg_iddig0_2", + "otg_iddig1_0", + "otg_iddig1_1", + "otg_iddig1_2", + "otg_drv_vbus0_0", + "otg_drv_vbus0_1", + "otg_drv_vbus0_2", + "otg_drv_vbus1_0", + "otg_drv_vbus1_1", + "otg_drv_vbus1_2", }; +static const char *const mt7623_pcie_groups[] = { "pcie0_0_perst", + "pcie0_1_perst", + "pcie1_0_perst", + "pcie1_1_perst", + "pcie2_0_perst", + "pcie2_1_perst", + "pcie0_0_rev_perst", + "pcie0_1_rev_perst", + "pcie1_0_rev_perst", + "pcie1_1_rev_perst", + "pcie2_0_rev_perst", + "pcie2_1_rev_perst", + "pcie0_0_wake", "pcie0_1_wake", + "pcie2_0_wake", "pcie2_1_wake", + "pcie0_clkreq", "pcie1_clkreq", + "pcie2_clkreq", }; +static const char *const mt7623_pcm_groups[] = { "pcm_clk_0", "pcm_clk_1", + "pcm_clk_2", "pcm_clk_3", + "pcm_clk_4", "pcm_clk_5", + "pcm_clk_6", "pcm_sync_0", + "pcm_sync_1", "pcm_sync_2", + "pcm_sync_3", "pcm_sync_4", + "pcm_sync_5", "pcm_sync_6", + "pcm_rx_0", "pcm_rx_1", + "pcm_rx_2", "pcm_rx_3", + "pcm_rx_4", "pcm_rx_5", + "pcm_rx_6", "pcm_tx_0", + "pcm_tx_1", "pcm_tx_2", + "pcm_tx_3", "pcm_tx_4", + "pcm_tx_5", "pcm_tx_6", }; +static const char *const mt7623_pwm_groups[] = { "pwm_ch1_0", "pwm_ch1_1", + "pwm_ch1_2", "pwm_ch2_0", + "pwm_ch2_1", "pwm_ch2_2", + "pwm_ch3_0", "pwm_ch3_1", + "pwm_ch3_2", "pwm_ch4_0", + "pwm_ch4_1", "pwm_ch4_2", + "pwm_ch4_3", "pwm_ch5_0", + "pwm_ch5_1", "pwm_ch5_2", + "pwm_ch6_0", "pwm_ch6_1", + "pwm_ch6_2", "pwm_ch6_3", + "pwm_ch7_0", "pwm_ch7_1", + "pwm_ch7_2", }; +static const char *const mt7623_pwrap_groups[] = { "pwrap", }; +static const char *const mt7623_rtc_groups[] = { "rtc", }; +static const char *const mt7623_spi_groups[] = { "spi0", "spi2", "spi2", }; +static const char *const mt7623_spdif_groups[] = { "spdif_in0_0", + "spdif_in0_1", "spdif_in1_0", + "spdif_in1_1", "spdif_out", }; +static const char *const mt7623_uart_groups[] = { "uart0_0_txd_rxd", + "uart0_1_txd_rxd", + "uart0_2_txd_rxd", + "uart0_3_txd_rxd", + "uart1_0_txd_rxd", + "uart1_1_txd_rxd", + "uart1_2_txd_rxd", + "uart2_0_txd_rxd", + "uart2_1_txd_rxd", + "uart3_txd_rxd", + "uart0_rts_cts", + "uart1_rts_cts", + "uart2_rts_cts", + "uart3_rts_cts", }; +static const char *const mt7623_wdt_groups[] = { "watchdog_0", "watchdog_1", }; + +static const struct mtk_function_desc mt7623_functions[] = { + {"audck", mt7623_aud_clk_groups, ARRAY_SIZE(mt7623_aud_clk_groups)}, + {"disp", mt7623_disp_pwm_groups, ARRAY_SIZE(mt7623_disp_pwm_groups)}, + {"eth", mt7623_ethernet_groups, ARRAY_SIZE(mt7623_ethernet_groups)}, + {"sdio", mt7623_ext_sdio_groups, ARRAY_SIZE(mt7623_ext_sdio_groups)}, + {"hdmi", mt7623_hdmi_groups, ARRAY_SIZE(mt7623_hdmi_groups)}, + {"i2c", mt7623_i2c_groups, ARRAY_SIZE(mt7623_i2c_groups)}, + {"i2s", mt7623_i2s_groups, ARRAY_SIZE(mt7623_i2s_groups)}, + {"ir", mt7623_ir_groups, ARRAY_SIZE(mt7623_ir_groups)}, + {"lcd", mt7623_lcd_groups, ARRAY_SIZE(mt7623_lcd_groups)}, + {"msdc", mt7623_msdc_groups, ARRAY_SIZE(mt7623_msdc_groups)}, + {"nand", mt7623_nandc_groups, ARRAY_SIZE(mt7623_nandc_groups)}, + {"otg", mt7623_otg_groups, ARRAY_SIZE(mt7623_otg_groups)}, + {"pcie", mt7623_pcie_groups, ARRAY_SIZE(mt7623_pcie_groups)}, + {"pcm", mt7623_pcm_groups, ARRAY_SIZE(mt7623_pcm_groups)}, + {"pwm", mt7623_pwm_groups, ARRAY_SIZE(mt7623_pwm_groups)}, + {"pwrap", mt7623_pwrap_groups, ARRAY_SIZE(mt7623_pwrap_groups)}, + {"rtc", mt7623_rtc_groups, ARRAY_SIZE(mt7623_rtc_groups)}, + {"spi", mt7623_spi_groups, ARRAY_SIZE(mt7623_spi_groups)}, + {"spdif", mt7623_spdif_groups, ARRAY_SIZE(mt7623_spdif_groups)}, + {"uart", mt7623_uart_groups, ARRAY_SIZE(mt7623_uart_groups)}, + {"watchdog", mt7623_wdt_groups, ARRAY_SIZE(mt7623_wdt_groups)}, +}; + +static struct mtk_pinctrl_soc mt7623_data = { + .name = "mt7623_pinctrl", + .reg_cal = mt7623_reg_cals, + .pins = mt7623_pins, + .npins = ARRAY_SIZE(mt7623_pins), + .grps = mt7623_groups, + .ngrps = ARRAY_SIZE(mt7623_groups), + .funcs = mt7623_functions, + .nfuncs = ARRAY_SIZE(mt7623_functions), +}; + +/* + * There are some specific pins have mux functions greater than 8, + * and if we want to switch thees high modes we need to disable + * bonding constraints firstly. + */ +static void mt7623_bonding_disable(struct udevice *dev) +{ + mtk_rmw(dev, PIN_BOND_REG0, BOND_PCIE_CLR, BOND_PCIE_CLR); + mtk_rmw(dev, PIN_BOND_REG1, BOND_I2S_CLR, BOND_I2S_CLR); + mtk_rmw(dev, PIN_BOND_REG2, BOND_MSDC0E_CLR, BOND_MSDC0E_CLR); +} + +static int mtk_pinctrl_mt7623_probe(struct udevice *dev) +{ + int err; + + err = mtk_pinctrl_common_probe(dev, &mt7623_data); + if (err) + return err; + + mt7623_bonding_disable(dev); + + return 0; +} + +static const struct udevice_id mt7623_pctrl_match[] = { + { .compatible = "mediatek,mt7623-pinctrl", }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mt7623_pinctrl) = { + .name = "mt7623_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = mt7623_pctrl_match, + .ops = &mtk_pinctrl_ops, + .probe = mtk_pinctrl_mt7623_probe, + .priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv), +}; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c new file mode 100644 index 00000000000..aa6d1c2d914 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <dm.h> + +#include "pinctrl-mtk-common.h" + +#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, false) + +#define MT7629_PIN(_number, _name) MTK_PIN(_number, _name, DRV_GRP1) + +static const struct mtk_pin_field_calc mt7629_pin_mode_range[] = { + PIN_FIELD(0, 78, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt7629_pin_dir_range[] = { + PIN_FIELD(0, 78, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_di_range[] = { + PIN_FIELD(0, 78, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_do_range[] = { + PIN_FIELD(0, 78, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_ies_range[] = { + PIN_FIELD(0, 10, 0x1000, 0x10, 0, 1), + PIN_FIELD(11, 18, 0x2000, 0x10, 0, 1), + PIN_FIELD(19, 32, 0x3000, 0x10, 0, 1), + PIN_FIELD(33, 48, 0x4000, 0x10, 0, 1), + PIN_FIELD(49, 50, 0x5000, 0x10, 0, 1), + PIN_FIELD(51, 69, 0x6000, 0x10, 0, 1), + PIN_FIELD(70, 78, 0x7000, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_smt_range[] = { + PIN_FIELD(0, 10, 0x1100, 0x10, 0, 1), + PIN_FIELD(11, 18, 0x2100, 0x10, 0, 1), + PIN_FIELD(19, 32, 0x3100, 0x10, 0, 1), + PIN_FIELD(33, 48, 0x4100, 0x10, 0, 1), + PIN_FIELD(49, 50, 0x5100, 0x10, 0, 1), + PIN_FIELD(51, 69, 0x6100, 0x10, 0, 1), + PIN_FIELD(70, 78, 0x7100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_pullen_range[] = { + PIN_FIELD(0, 10, 0x1400, 0x10, 0, 1), + PIN_FIELD(11, 18, 0x2400, 0x10, 0, 1), + PIN_FIELD(19, 32, 0x3400, 0x10, 0, 1), + PIN_FIELD(33, 48, 0x4400, 0x10, 0, 1), + PIN_FIELD(49, 50, 0x5400, 0x10, 0, 1), + PIN_FIELD(51, 69, 0x6400, 0x10, 0, 1), + PIN_FIELD(70, 78, 0x7400, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_pullsel_range[] = { + PIN_FIELD(0, 10, 0x1500, 0x10, 0, 1), + PIN_FIELD(11, 18, 0x2500, 0x10, 0, 1), + PIN_FIELD(19, 32, 0x3500, 0x10, 0, 1), + PIN_FIELD(33, 48, 0x4500, 0x10, 0, 1), + PIN_FIELD(49, 50, 0x5500, 0x10, 0, 1), + PIN_FIELD(51, 69, 0x6500, 0x10, 0, 1), + PIN_FIELD(70, 78, 0x7500, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7629_pin_drv_range[] = { + PIN_FIELD(0, 10, 0x1600, 0x10, 0, 4), + PIN_FIELD(11, 18, 0x2600, 0x10, 0, 4), + PIN_FIELD(19, 32, 0x3600, 0x10, 0, 4), + PIN_FIELD(33, 48, 0x4600, 0x10, 0, 4), + PIN_FIELD(49, 50, 0x5600, 0x10, 0, 4), + PIN_FIELD(51, 69, 0x6600, 0x10, 0, 4), + PIN_FIELD(70, 78, 0x7600, 0x10, 0, 4), +}; + +static const struct mtk_pin_reg_calc mt7629_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7629_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7629_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7629_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7629_pin_do_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7629_pin_ies_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7629_pin_smt_range), + [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7629_pin_pullsel_range), + [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7629_pin_pullen_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7629_pin_drv_range), +}; + +static const struct mtk_pin_desc mt7629_pins[] = { + MT7629_PIN(0, "TOP_5G_CLK"), + MT7629_PIN(1, "TOP_5G_DATA"), + MT7629_PIN(2, "WF0_5G_HB0"), + MT7629_PIN(3, "WF0_5G_HB1"), + MT7629_PIN(4, "WF0_5G_HB2"), + MT7629_PIN(5, "WF0_5G_HB3"), + MT7629_PIN(6, "WF0_5G_HB4"), + MT7629_PIN(7, "WF0_5G_HB5"), + MT7629_PIN(8, "WF0_5G_HB6"), + MT7629_PIN(9, "XO_REQ"), + MT7629_PIN(10, "TOP_RST_N"), + MT7629_PIN(11, "SYS_WATCHDOG"), + MT7629_PIN(12, "EPHY_LED0_N_JTDO"), + MT7629_PIN(13, "EPHY_LED1_N_JTDI"), + MT7629_PIN(14, "EPHY_LED2_N_JTMS"), + MT7629_PIN(15, "EPHY_LED3_N_JTCLK"), + MT7629_PIN(16, "EPHY_LED4_N_JTRST_N"), + MT7629_PIN(17, "WF2G_LED_N"), + MT7629_PIN(18, "WF5G_LED_N"), + MT7629_PIN(19, "I2C_SDA"), + MT7629_PIN(20, "I2C_SCL"), + MT7629_PIN(21, "GPIO_9"), + MT7629_PIN(22, "GPIO_10"), + MT7629_PIN(23, "GPIO_11"), + MT7629_PIN(24, "GPIO_12"), + MT7629_PIN(25, "UART1_TXD"), + MT7629_PIN(26, "UART1_RXD"), + MT7629_PIN(27, "UART1_CTS"), + MT7629_PIN(28, "UART1_RTS"), + MT7629_PIN(29, "UART2_TXD"), + MT7629_PIN(30, "UART2_RXD"), + MT7629_PIN(31, "UART2_CTS"), + MT7629_PIN(32, "UART2_RTS"), + MT7629_PIN(33, "MDI_TP_P1"), + MT7629_PIN(34, "MDI_TN_P1"), + MT7629_PIN(35, "MDI_RP_P1"), + MT7629_PIN(36, "MDI_RN_P1"), + MT7629_PIN(37, "MDI_RP_P2"), + MT7629_PIN(38, "MDI_RN_P2"), + MT7629_PIN(39, "MDI_TP_P2"), + MT7629_PIN(40, "MDI_TN_P2"), + MT7629_PIN(41, "MDI_TP_P3"), + MT7629_PIN(42, "MDI_TN_P3"), + MT7629_PIN(43, "MDI_RP_P3"), + MT7629_PIN(44, "MDI_RN_P3"), + MT7629_PIN(45, "MDI_RP_P4"), + MT7629_PIN(46, "MDI_RN_P4"), + MT7629_PIN(47, "MDI_TP_P4"), + MT7629_PIN(48, "MDI_TN_P4"), + MT7629_PIN(49, "SMI_MDC"), + MT7629_PIN(50, "SMI_MDIO"), + MT7629_PIN(51, "PCIE_PERESET_N"), + MT7629_PIN(52, "PWM_0"), + MT7629_PIN(53, "GPIO_0"), + MT7629_PIN(54, "GPIO_1"), + MT7629_PIN(55, "GPIO_2"), + MT7629_PIN(56, "GPIO_3"), + MT7629_PIN(57, "GPIO_4"), + MT7629_PIN(58, "GPIO_5"), + MT7629_PIN(59, "GPIO_6"), + MT7629_PIN(60, "GPIO_7"), + MT7629_PIN(61, "GPIO_8"), + MT7629_PIN(62, "SPI_CLK"), + MT7629_PIN(63, "SPI_CS"), + MT7629_PIN(64, "SPI_MOSI"), + MT7629_PIN(65, "SPI_MISO"), + MT7629_PIN(66, "SPI_WP"), + MT7629_PIN(67, "SPI_HOLD"), + MT7629_PIN(68, "UART0_TXD"), + MT7629_PIN(69, "UART0_RXD"), + MT7629_PIN(70, "TOP_2G_CLK"), + MT7629_PIN(71, "TOP_2G_DATA"), + MT7629_PIN(72, "WF0_2G_HB0"), + MT7629_PIN(73, "WF0_2G_HB1"), + MT7629_PIN(74, "WF0_2G_HB2"), + MT7629_PIN(75, "WF0_2G_HB3"), + MT7629_PIN(76, "WF0_2G_HB4"), + MT7629_PIN(77, "WF0_2G_HB5"), + MT7629_PIN(78, "WF0_2G_HB6"), +}; + +/* List all groups consisting of these pins dedicated to the enablement of + * certain hardware block and the corresponding mode for all of the pins. + * The hardware probably has multiple combinations of these pinouts. + */ + +/* WF 5G */ +static int mt7629_wf0_5g_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, }; +static int mt7629_wf0_5g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* LED for EPHY */ +static int mt7629_ephy_leds_pins[] = { 12, 13, 14, 15, 16, 17, 18, }; +static int mt7629_ephy_leds_funcs[] = { 1, 1, 1, 1, 1, 1, 1, }; +static int mt7629_ephy_led0_pins[] = { 12, }; +static int mt7629_ephy_led0_funcs[] = { 1, }; +static int mt7629_ephy_led1_pins[] = { 13, }; +static int mt7629_ephy_led1_funcs[] = { 1, }; +static int mt7629_ephy_led2_pins[] = { 14, }; +static int mt7629_ephy_led2_funcs[] = { 1, }; +static int mt7629_ephy_led3_pins[] = { 15, }; +static int mt7629_ephy_led3_funcs[] = { 1, }; +static int mt7629_ephy_led4_pins[] = { 16, }; +static int mt7629_ephy_led4_funcs[] = { 1, }; +static int mt7629_wf2g_led_pins[] = { 17, }; +static int mt7629_wf2g_led_funcs[] = { 1, }; +static int mt7629_wf5g_led_pins[] = { 18, }; +static int mt7629_wf5g_led_funcs[] = { 1, }; + +/* Watchdog */ +static int mt7629_watchdog_pins[] = { 11, }; +static int mt7629_watchdog_funcs[] = { 1, }; + +/* LED for GPHY */ +static int mt7629_gphy_leds_0_pins[] = { 21, 22, 23, }; +static int mt7629_gphy_leds_0_funcs[] = { 2, 2, 2, }; +static int mt7629_gphy_led1_0_pins[] = { 21, }; +static int mt7629_gphy_led1_0_funcs[] = { 2, }; +static int mt7629_gphy_led2_0_pins[] = { 22, }; +static int mt7629_gphy_led2_0_funcs[] = { 2, }; +static int mt7629_gphy_led3_0_pins[] = { 23, }; +static int mt7629_gphy_led3_0_funcs[] = { 2, }; +static int mt7629_gphy_leds_1_pins[] = { 57, 58, 59, }; +static int mt7629_gphy_leds_1_funcs[] = { 1, 1, 1, }; +static int mt7629_gphy_led1_1_pins[] = { 57, }; +static int mt7629_gphy_led1_1_funcs[] = { 1, }; +static int mt7629_gphy_led2_1_pins[] = { 58, }; +static int mt7629_gphy_led2_1_funcs[] = { 1, }; +static int mt7629_gphy_led3_1_pins[] = { 59, }; +static int mt7629_gphy_led3_1_funcs[] = { 1, }; + +/* I2C */ +static int mt7629_i2c_0_pins[] = { 19, 20, }; +static int mt7629_i2c_0_funcs[] = { 1, 1, }; +static int mt7629_i2c_1_pins[] = { 53, 54, }; +static int mt7629_i2c_1_funcs[] = { 1, 1, }; + +/* SPI */ +static int mt7629_spi_0_pins[] = { 21, 22, 23, 24, }; +static int mt7629_spi_0_funcs[] = { 1, 1, 1, 1, }; +static int mt7629_spi_1_pins[] = { 62, 63, 64, 65, }; +static int mt7629_spi_1_funcs[] = { 1, 1, 1, 1, }; +static int mt7629_spi_wp_pins[] = { 66, }; +static int mt7629_spi_wp_funcs[] = { 1, }; +static int mt7629_spi_hold_pins[] = { 67, }; +static int mt7629_spi_hold_funcs[] = { 1, }; + +/* UART */ +static int mt7629_uart1_0_txd_rxd_pins[] = { 25, 26, }; +static int mt7629_uart1_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7629_uart1_1_txd_rxd_pins[] = { 53, 54, }; +static int mt7629_uart1_1_txd_rxd_funcs[] = { 2, 2, }; +static int mt7629_uart2_0_txd_rxd_pins[] = { 29, 30, }; +static int mt7629_uart2_0_txd_rxd_funcs[] = { 1, 1, }; +static int mt7629_uart2_1_txd_rxd_pins[] = { 57, 58, }; +static int mt7629_uart2_1_txd_rxd_funcs[] = { 2, 2, }; +static int mt7629_uart1_0_cts_rts_pins[] = { 27, 28, }; +static int mt7629_uart1_0_cts_rts_funcs[] = { 1, 1, }; +static int mt7629_uart1_1_cts_rts_pins[] = { 55, 56, }; +static int mt7629_uart1_1_cts_rts_funcs[] = { 2, 2, }; +static int mt7629_uart2_0_cts_rts_pins[] = { 31, 32, }; +static int mt7629_uart2_0_cts_rts_funcs[] = { 1, 1, }; +static int mt7629_uart2_1_cts_rts_pins[] = { 59, 60, }; +static int mt7629_uart2_1_cts_rts_funcs[] = { 2, 2, }; +static int mt7629_uart0_txd_rxd_pins[] = { 68, 69, }; +static int mt7629_uart0_txd_rxd_funcs[] = { 1, 1, }; + +/* MDC/MDIO */ +static int mt7629_mdc_mdio_pins[] = { 49, 50, }; +static int mt7629_mdc_mdio_funcs[] = { 1, 1, }; + +/* PCIE */ +static int mt7629_pcie_pereset_pins[] = { 51, }; +static int mt7629_pcie_pereset_funcs[] = { 1, }; +static int mt7629_pcie_wake_pins[] = { 55, }; +static int mt7629_pcie_wake_funcs[] = { 1, }; +static int mt7629_pcie_clkreq_pins[] = { 56, }; +static int mt7629_pcie_clkreq_funcs[] = { 1, }; + +/* PWM */ +static int mt7629_pwm_0_pins[] = { 52, }; +static int mt7629_pwm_0_funcs[] = { 1, }; +static int mt7629_pwm_1_pins[] = { 61, }; +static int mt7629_pwm_1_funcs[] = { 2, }; + +/* WF 2G */ +static int mt7629_wf0_2g_pins[] = { 70, 71, 72, 73, 74, 75, 76, 77, 78, }; +static int mt7629_wf0_2g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, }; + +/* SNFI */ +static int mt7629_snfi_pins[] = { 62, 63, 64, 65, 66, 67 }; +static int mt7629_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 }; + +/* SPI NOR */ +static int mt7629_snor_pins[] = { 62, 63, 64, 65, 66, 67 }; +static int mt7629_snor_funcs[] = { 1, 1, 1, 1, 1, 1 }; + +static const struct mtk_group_desc mt7629_groups[] = { + PINCTRL_PIN_GROUP("wf0_5g", mt7629_wf0_5g), + PINCTRL_PIN_GROUP("ephy_leds", mt7629_ephy_leds), + PINCTRL_PIN_GROUP("ephy_led0", mt7629_ephy_led0), + PINCTRL_PIN_GROUP("ephy_led1", mt7629_ephy_led1), + PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2), + PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3), + PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4), + PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led), + PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led), + PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog), + PINCTRL_PIN_GROUP("gphy_leds_0", mt7629_gphy_leds_0), + PINCTRL_PIN_GROUP("gphy_led1_0", mt7629_gphy_led1_0), + PINCTRL_PIN_GROUP("gphy_led2_0", mt7629_gphy_led2_0), + PINCTRL_PIN_GROUP("gphy_led3_0", mt7629_gphy_led3_0), + PINCTRL_PIN_GROUP("gphy_leds_1", mt7629_gphy_leds_1), + PINCTRL_PIN_GROUP("gphy_led1_1", mt7629_gphy_led1_1), + PINCTRL_PIN_GROUP("gphy_led2_1", mt7629_gphy_led2_1), + PINCTRL_PIN_GROUP("gphy_led3_1", mt7629_gphy_led3_1), + PINCTRL_PIN_GROUP("i2c_0", mt7629_i2c_0), + PINCTRL_PIN_GROUP("i2c_1", mt7629_i2c_1), + PINCTRL_PIN_GROUP("spi_0", mt7629_spi_0), + PINCTRL_PIN_GROUP("spi_1", mt7629_spi_1), + PINCTRL_PIN_GROUP("spi_wp", mt7629_spi_wp), + PINCTRL_PIN_GROUP("spi_hold", mt7629_spi_hold), + PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7629_uart1_0_txd_rxd), + PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7629_uart1_1_txd_rxd), + PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7629_uart2_0_txd_rxd), + PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7629_uart2_1_txd_rxd), + PINCTRL_PIN_GROUP("uart1_0_cts_rts", mt7629_uart1_0_cts_rts), + PINCTRL_PIN_GROUP("uart1_1_cts_rts", mt7629_uart1_1_cts_rts), + PINCTRL_PIN_GROUP("uart2_0_cts_rts", mt7629_uart2_0_cts_rts), + PINCTRL_PIN_GROUP("uart2_1_cts_rts", mt7629_uart2_1_cts_rts), + PINCTRL_PIN_GROUP("uart0_txd_rxd", mt7629_uart0_txd_rxd), + PINCTRL_PIN_GROUP("mdc_mdio", mt7629_mdc_mdio), + PINCTRL_PIN_GROUP("pcie_pereset", mt7629_pcie_pereset), + PINCTRL_PIN_GROUP("pcie_wake", mt7629_pcie_wake), + PINCTRL_PIN_GROUP("pcie_clkreq", mt7629_pcie_clkreq), + PINCTRL_PIN_GROUP("pwm_0", mt7629_pwm_0), + PINCTRL_PIN_GROUP("pwm_1", mt7629_pwm_1), + PINCTRL_PIN_GROUP("wf0_2g", mt7629_wf0_2g), + PINCTRL_PIN_GROUP("snfi", mt7629_snfi), + PINCTRL_PIN_GROUP("spi_nor", mt7629_snor), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char *const mt7629_ethernet_groups[] = { "mdc_mdio", }; +static const char *const mt7629_i2c_groups[] = { "i2c_0", "i2c_1", }; +static const char *const mt7629_led_groups[] = { "ephy_leds", "ephy_led0", + "ephy_led1", "ephy_led2", + "ephy_led3", "ephy_led4", + "wf2g_led", "wf5g_led", + "gphy_leds_0", "gphy_led1_0", + "gphy_led2_0", "gphy_led3_0", + "gphy_leds_1", "gphy_led1_1", + "gphy_led2_1", "gphy_led3_1",}; +static const char *const mt7629_pcie_groups[] = { "pcie_pereset", "pcie_wake", + "pcie_clkreq", }; +static const char *const mt7629_pwm_groups[] = { "pwm_0", "pwm_1", }; +static const char *const mt7629_spi_groups[] = { "spi_0", "spi_1", "spi_wp", + "spi_hold", }; +static const char *const mt7629_uart_groups[] = { "uart1_0_txd_rxd", + "uart1_1_txd_rxd", + "uart2_0_txd_rxd", + "uart2_1_txd_rxd", + "uart1_0_cts_rts", + "uart1_1_cts_rts", + "uart2_0_cts_rts", + "uart2_1_cts_rts", + "uart0_txd_rxd", }; +static const char *const mt7629_wdt_groups[] = { "watchdog", }; +static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", }; +static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" }; + +static const struct mtk_function_desc mt7629_functions[] = { + {"eth", mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)}, + {"i2c", mt7629_i2c_groups, ARRAY_SIZE(mt7629_i2c_groups)}, + {"led", mt7629_led_groups, ARRAY_SIZE(mt7629_led_groups)}, + {"pcie", mt7629_pcie_groups, ARRAY_SIZE(mt7629_pcie_groups)}, + {"pwm", mt7629_pwm_groups, ARRAY_SIZE(mt7629_pwm_groups)}, + {"spi", mt7629_spi_groups, ARRAY_SIZE(mt7629_spi_groups)}, + {"uart", mt7629_uart_groups, ARRAY_SIZE(mt7629_uart_groups)}, + {"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)}, + {"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)}, + {"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)}, +}; + +static struct mtk_pinctrl_soc mt7629_data = { + .name = "mt7629_pinctrl", + .reg_cal = mt7629_reg_cals, + .pins = mt7629_pins, + .npins = ARRAY_SIZE(mt7629_pins), + .grps = mt7629_groups, + .ngrps = ARRAY_SIZE(mt7629_groups), + .funcs = mt7629_functions, + .nfuncs = ARRAY_SIZE(mt7629_functions), +}; + +static int mtk_pinctrl_mt7629_probe(struct udevice *dev) +{ + return mtk_pinctrl_common_probe(dev, &mt7629_data); +} + +static const struct udevice_id mt7629_pctrl_match[] = { + { .compatible = "mediatek,mt7629-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mt7629_pinctrl) = { + .name = "mt7629_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = mt7629_pctrl_match, + .ops = &mtk_pinctrl_ops, + .probe = mtk_pinctrl_mt7629_probe, + .priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv), +}; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c new file mode 100644 index 00000000000..938cc75496a --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <asm/io.h> +#include <asm-generic/gpio.h> + +#include "pinctrl-mtk-common.h" + +/** + * struct mtk_drive_desc - the structure that holds the information + * of the driving current + * @min: the minimum current of this group + * @max: the maximum current of this group + * @step: the step current of this group + * @scal: the weight factor + * + * formula: output = ((input) / step - 1) * scal + */ +struct mtk_drive_desc { + u8 min; + u8 max; + u8 step; + u8 scal; +}; + +/* The groups of drive strength */ +static const struct mtk_drive_desc mtk_drive[] = { + [DRV_GRP0] = { 4, 16, 4, 1 }, + [DRV_GRP1] = { 4, 16, 4, 2 }, + [DRV_GRP2] = { 2, 8, 2, 1 }, + [DRV_GRP3] = { 2, 8, 2, 2 }, + [DRV_GRP4] = { 2, 16, 2, 1 }, +}; + +static const char *mtk_pinctrl_dummy_name = "_dummy"; + +static void mtk_w32(struct udevice *dev, u32 reg, u32 val) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + __raw_writel(val, priv->base + reg); +} + +static u32 mtk_r32(struct udevice *dev, u32 reg) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + return __raw_readl(priv->base + reg); +} + +static inline int get_count_order(unsigned int count) +{ + int order; + + order = fls(count) - 1; + if (count & (count - 1)) + order++; + return order; +} + +void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set) +{ + u32 val; + + val = mtk_r32(dev, reg); + val &= ~mask; + val |= set; + mtk_w32(dev, reg, val); +} + +static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin, + const struct mtk_pin_reg_calc *rc, + struct mtk_pin_field *pfd) +{ + const struct mtk_pin_field_calc *c, *e; + u32 bits; + + c = rc->range; + e = c + rc->nranges; + + while (c < e) { + if (pin >= c->s_pin && pin <= c->e_pin) + break; + c++; + } + + if (c >= e) + return -EINVAL; + + /* Calculated bits as the overall offset the pin is located at, + * if c->fixed is held, that determines the all the pins in the + * range use the same field with the s_pin. + */ + bits = c->fixed ? c->s_bit : c->s_bit + (pin - c->s_pin) * (c->x_bits); + + /* Fill pfd from bits. For example 32-bit register applied is assumed + * when c->sz_reg is equal to 32. + */ + pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg); + pfd->bitpos = bits % c->sz_reg; + pfd->mask = (1 << c->x_bits) - 1; + + /* pfd->next is used for indicating that bit wrapping-around happens + * which requires the manipulation for bit 0 starting in the next + * register to form the complete field read/write. + */ + pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0; + + return 0; +} + +static int mtk_hw_pin_field_get(struct udevice *dev, int pin, + int field, struct mtk_pin_field *pfd) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + const struct mtk_pin_reg_calc *rc; + + if (field < 0 || field >= PINCTRL_PIN_REG_MAX) + return -EINVAL; + + if (priv->soc->reg_cal && priv->soc->reg_cal[field].range) + rc = &priv->soc->reg_cal[field]; + else + return -EINVAL; + + return mtk_hw_pin_field_lookup(dev, pin, rc, pfd); +} + +static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) +{ + *l = 32 - pf->bitpos; + *h = get_count_order(pf->mask) - *l; +} + +static void mtk_hw_write_cross_field(struct udevice *dev, + struct mtk_pin_field *pf, int value) +{ + int nbits_l, nbits_h; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + mtk_rmw(dev, pf->offset, pf->mask << pf->bitpos, + (value & pf->mask) << pf->bitpos); + + mtk_rmw(dev, pf->offset + pf->next, BIT(nbits_h) - 1, + (value & pf->mask) >> nbits_l); +} + +static void mtk_hw_read_cross_field(struct udevice *dev, + struct mtk_pin_field *pf, int *value) +{ + int nbits_l, nbits_h, h, l; + + mtk_hw_bits_part(pf, &nbits_h, &nbits_l); + + l = (mtk_r32(dev, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1); + h = (mtk_r32(dev, pf->offset + pf->next)) & (BIT(nbits_h) - 1); + + *value = (h << nbits_l) | l; +} + +static int mtk_hw_set_value(struct udevice *dev, int pin, int field, + int value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(dev, pin, field, &pf); + if (err) + return err; + + if (!pf.next) + mtk_rmw(dev, pf.offset, pf.mask << pf.bitpos, + (value & pf.mask) << pf.bitpos); + else + mtk_hw_write_cross_field(dev, &pf, value); + + return 0; +} + +static int mtk_hw_get_value(struct udevice *dev, int pin, int field, + int *value) +{ + struct mtk_pin_field pf; + int err; + + err = mtk_hw_pin_field_get(dev, pin, field, &pf); + if (err) + return err; + + if (!pf.next) + *value = (mtk_r32(dev, pf.offset) >> pf.bitpos) & pf.mask; + else + mtk_hw_read_cross_field(dev, &pf, value); + + return 0; +} + +static int mtk_get_groups_count(struct udevice *dev) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->soc->ngrps; +} + +static const char *mtk_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + if (!priv->soc->grps[selector].name) + return mtk_pinctrl_dummy_name; + + return priv->soc->pins[selector].name; +} + +static int mtk_get_pins_count(struct udevice *dev) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->soc->npins; +} + +static const char *mtk_get_group_name(struct udevice *dev, + unsigned int selector) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + if (!priv->soc->grps[selector].name) + return mtk_pinctrl_dummy_name; + + return priv->soc->grps[selector].name; +} + +static int mtk_get_functions_count(struct udevice *dev) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->soc->nfuncs; +} + +static const char *mtk_get_function_name(struct udevice *dev, + unsigned int selector) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + + if (!priv->soc->funcs[selector].name) + return mtk_pinctrl_dummy_name; + + return priv->soc->funcs[selector].name; +} + +static int mtk_pinmux_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + const struct mtk_group_desc *grp = + &priv->soc->grps[group_selector]; + int i; + + for (i = 0; i < grp->num_pins; i++) { + int *pin_modes = grp->data; + + mtk_hw_set_value(dev, grp->pins[i], PINCTRL_PIN_REG_MODE, + pin_modes[i]); + } + + return 0; +} + +#if CONFIG_IS_ENABLED(PINCONF) +static const struct pinconf_param mtk_conf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, + { "output-high", PIN_CONFIG_OUTPUT, 1, }, + { "output-low", PIN_CONFIG_OUTPUT, 0, }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, +}; + +int mtk_pinconf_drive_set(struct udevice *dev, u32 pin, u32 arg) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + const struct mtk_pin_desc *desc = &priv->soc->pins[pin]; + const struct mtk_drive_desc *tb; + int err = -ENOTSUPP; + + tb = &mtk_drive[desc->drv_n]; + /* 4mA when (e8, e4) = (0, 0) + * 8mA when (e8, e4) = (0, 1) + * 12mA when (e8, e4) = (1, 0) + * 16mA when (e8, e4) = (1, 1) + */ + if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) { + arg = (arg / tb->step - 1) * tb->scal; + + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DRV, arg); + if (err) + return err; + } + + return 0; +} + +static int mtk_pinconf_set(struct udevice *dev, unsigned int pin, + unsigned int param, unsigned int arg) +{ + int err = 0; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 : + (param == PIN_CONFIG_BIAS_PULL_UP) ? 3 : 2; + + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLSEL, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLEN, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT, 0); + if (err) + goto err; + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_ENABLE: + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_IES, 1); + if (err) + goto err; + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 0); + if (err) + goto err; + break; + case PIN_CONFIG_OUTPUT: + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1); + if (err) + goto err; + + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DO, arg); + if (err) + goto err; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + /* arg = 1: Input mode & SMT enable ; + * arg = 0: Output mode & SMT disable + */ + arg = arg ? 2 : 1; + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, + arg & 1); + if (err) + goto err; + + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT, + !!(arg & 2)); + if (err) + goto err; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + err = mtk_pinconf_drive_set(dev, pin, arg); + if (err) + goto err; + break; + + default: + err = -ENOTSUPP; + } + +err: + + return err; +} + +static int mtk_pinconf_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int param, unsigned int arg) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + const struct mtk_group_desc *grp = + &priv->soc->grps[group_selector]; + int i, ret; + + for (i = 0; i < grp->num_pins; i++) { + ret = mtk_pinconf_set(dev, grp->pins[i], param, arg); + if (ret) + return ret; + } + + return 0; +} +#endif + +const struct pinctrl_ops mtk_pinctrl_ops = { + .get_pins_count = mtk_get_pins_count, + .get_pin_name = mtk_get_pin_name, + .get_groups_count = mtk_get_groups_count, + .get_group_name = mtk_get_group_name, + .get_functions_count = mtk_get_functions_count, + .get_function_name = mtk_get_function_name, + .pinmux_group_set = mtk_pinmux_group_set, +#if CONFIG_IS_ENABLED(PINCONF) + .pinconf_num_params = ARRAY_SIZE(mtk_conf_params), + .pinconf_params = mtk_conf_params, + .pinconf_set = mtk_pinconf_set, + .pinconf_group_set = mtk_pinconf_group_set, +#endif + .set_state = pinctrl_generic_set_state, +}; + +static int mtk_gpio_get(struct udevice *dev, unsigned int off) +{ + int val, err; + + err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DI, &val); + if (err) + return err; + + return !!val; +} + +static int mtk_gpio_set(struct udevice *dev, unsigned int off, int val) +{ + return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DO, !!val); +} + +static int mtk_gpio_get_direction(struct udevice *dev, unsigned int off) +{ + int val, err; + + err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DIR, &val); + if (err) + return err; + + return val ? GPIOF_OUTPUT : GPIOF_INPUT; +} + +static int mtk_gpio_direction_input(struct udevice *dev, unsigned int off) +{ + return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 0); +} + +static int mtk_gpio_direction_output(struct udevice *dev, + unsigned int off, int val) +{ + mtk_gpio_set(dev, off, val); + + /* And set the requested value */ + return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 1); +} + +static int mtk_gpio_request(struct udevice *dev, unsigned int off, + const char *label) +{ + return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_MODE, 0); +} + +static int mtk_gpio_probe(struct udevice *dev) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = priv->soc->name; + uc_priv->gpio_count = priv->soc->npins; + + return 0; +} + +static const struct dm_gpio_ops mtk_gpio_ops = { + .request = mtk_gpio_request, + .set_value = mtk_gpio_set, + .get_value = mtk_gpio_get, + .get_function = mtk_gpio_get_direction, + .direction_input = mtk_gpio_direction_input, + .direction_output = mtk_gpio_direction_output, +}; + +static struct driver mtk_gpio_driver = { + .name = "mediatek_gpio", + .id = UCLASS_GPIO, + .probe = mtk_gpio_probe, + .ops = &mtk_gpio_ops, +}; + +static int mtk_gpiochip_register(struct udevice *parent) +{ + struct uclass_driver *drv; + struct udevice *dev; + int ret; + ofnode node; + + drv = lists_uclass_lookup(UCLASS_GPIO); + if (!drv) + return -ENOENT; + + dev_for_each_subnode(node, parent) + if (ofnode_read_bool(node, "gpio-controller")) { + ret = 0; + break; + } + + if (ret) + return ret; + + ret = device_bind_with_driver_data(parent, &mtk_gpio_driver, + "mediatek_gpio", 0, node, + &dev); + if (ret) + return ret; + + return 0; +} + +int mtk_pinctrl_common_probe(struct udevice *dev, + struct mtk_pinctrl_soc *soc) +{ + struct mtk_pinctrl_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + if (priv->base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + priv->soc = soc; + + ret = mtk_gpiochip_register(dev); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h new file mode 100644 index 00000000000..86559f0f144 --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#ifndef __PINCTRL_MEDIATEK_H__ +#define __PINCTRL_MEDIATEK_H__ + +#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), } +#define MTK_PIN(_number, _name, _drv_n) { \ + .number = _number, \ + .name = _name, \ + .drv_n = _drv_n, \ + } + +#define PINCTRL_PIN_GROUP(name, id) \ + { \ + name, \ + id##_pins, \ + ARRAY_SIZE(id##_pins), \ + id##_funcs, \ + } + +#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, \ + _x_bits, _sz_reg, _fixed) { \ + .s_pin = _s_pin, \ + .e_pin = _e_pin, \ + .s_addr = _s_addr, \ + .x_addrs = _x_addrs, \ + .s_bit = _s_bit, \ + .x_bits = _x_bits, \ + .sz_reg = _sz_reg, \ + .fixed = _fixed, \ + } + +/* List these attributes which could be modified for the pin */ +enum { + PINCTRL_PIN_REG_MODE, + PINCTRL_PIN_REG_DIR, + PINCTRL_PIN_REG_DI, + PINCTRL_PIN_REG_DO, + PINCTRL_PIN_REG_IES, + PINCTRL_PIN_REG_SMT, + PINCTRL_PIN_REG_PULLEN, + PINCTRL_PIN_REG_PULLSEL, + PINCTRL_PIN_REG_DRV, + PINCTRL_PIN_REG_MAX, +}; + +/* Group the pins by the driving current */ +enum { + DRV_FIXED, + DRV_GRP0, + DRV_GRP1, + DRV_GRP2, + DRV_GRP3, + DRV_GRP4, +}; + +/** + * struct mtk_pin_field - the structure that holds the information of the field + * used to describe the attribute for the pin + * @offset: the register offset relative to the base address + * @mask: the mask used to filter out the field from the register + * @bitpos: the start bit relative to the register + * @next: the indication that the field would be extended to the + next register + */ +struct mtk_pin_field { + u32 offset; + u32 mask; + u8 bitpos; + u8 next; +}; + +/** + * struct mtk_pin_field_calc - the structure that holds the range providing + * the guide used to look up the relevant field + * @s_pin: the start pin within the range + * @e_pin: the end pin within the range + * @s_addr: the start address for the range + * @x_addrs: the address distance between two consecutive registers + * within the range + * @s_bit: the start bit for the first register within the range + * @x_bits: the bit distance between two consecutive pins within + * the range + * @sz_reg: the size of bits in a register + * @fixed: the consecutive pins share the same bits with the 1st + * pin + */ +struct mtk_pin_field_calc { + u16 s_pin; + u16 e_pin; + u32 s_addr; + u8 x_addrs; + u8 s_bit; + u8 x_bits; + u8 sz_reg; + u8 fixed; +}; + +/** + * struct mtk_pin_reg_calc - the structure that holds all ranges used to + * determine which register the pin would make use of + * for certain pin attribute. + * @range: the start address for the range + * @nranges: the number of items in the range + */ +struct mtk_pin_reg_calc { + const struct mtk_pin_field_calc *range; + unsigned int nranges; +}; + +/** + * struct mtk_pin_desc - the structure that providing information + * for each pin of chips + * @number: unique pin number from the global pin number space + * @name: name for this pin + * @drv_n: the index with the driving group + */ +struct mtk_pin_desc { + unsigned int number; + const char *name; + u8 drv_n; +}; + +/** + * struct mtk_group_desc - generic pin group descriptor + * @name: name of the pin group + * @pins: array of pins that belong to the group + * @num_pins: number of pins in the group + * @data: pin controller driver specific data + */ +struct mtk_group_desc { + const char *name; + int *pins; + int num_pins; + void *data; +}; + +/** + * struct mtk_function_desc - generic function descriptor + * @name: name of the function + * @group_names: array of pin group names + * @num_group_names: number of pin group names + */ +struct mtk_function_desc { + const char *name; + const char * const *group_names; + int num_group_names; +}; + +/* struct mtk_pin_soc - the structure that holds SoC-specific data */ +struct mtk_pinctrl_soc { + const char *name; + const struct mtk_pin_reg_calc *reg_cal; + const struct mtk_pin_desc *pins; + int npins; + const struct mtk_group_desc *grps; + int ngrps; + const struct mtk_function_desc *funcs; + int nfuncs; +}; + +/** + * struct mtk_pinctrl_priv - private data for MTK pinctrl driver + * + * @base: base address of the pinctrl device + * @soc: SoC specific data + */ +struct mtk_pinctrl_priv { + void __iomem *base; + struct mtk_pinctrl_soc *soc; +}; + +extern const struct pinctrl_ops mtk_pinctrl_ops; + +/* A common read-modify-write helper for MediaTek chips */ +void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set); +int mtk_pinctrl_common_probe(struct udevice *dev, + struct mtk_pinctrl_soc *soc); + +#endif /* __PINCTRL_MEDIATEK_H__ */ diff --git a/drivers/pinctrl/meson/Kconfig b/drivers/pinctrl/meson/Kconfig index 27ba8909d79..ee820a57a0e 100644 --- a/drivers/pinctrl/meson/Kconfig +++ b/drivers/pinctrl/meson/Kconfig @@ -1,15 +1,27 @@ if ARCH_MESON config PINCTRL_MESON - depends on PINCTRL_GENERIC + select PINCTRL_GENERIC + bool + +config PINCTRL_MESON_GX_PMX + select PINCTRL_MESON + bool + +config PINCTRL_MESON_AXG_PMX + select PINCTRL_MESON bool config PINCTRL_MESON_GXBB bool "Amlogic Meson GXBB SoC pinctrl driver" - select PINCTRL_MESON + select PINCTRL_MESON_GX_PMX config PINCTRL_MESON_GXL bool "Amlogic Meson GXL SoC pinctrl driver" - select PINCTRL_MESON + select PINCTRL_MESON_GX_PMX + +config PINCTRL_MESON_AXG + bool "Amlogic Meson AXG SoC pinctrl driver" + select PINCTRL_MESON_AXG_PMX endif diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile index 965092cd813..707287cd1d0 100644 --- a/drivers/pinctrl/meson/Makefile +++ b/drivers/pinctrl/meson/Makefile @@ -1,5 +1,8 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += pinctrl-meson.o +obj-$(CONFIG_PINCTRL_MESON_GX_PMX) += pinctrl-meson-gx-pmx.o +obj-$(CONFIG_PINCTRL_MESON_AXG_PMX) += pinctrl-meson-axg-pmx.o obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o obj-$(CONFIG_PINCTRL_MESON_GXL) += pinctrl-meson-gxl.o +obj-$(CONFIG_PINCTRL_MESON_AXG) += pinctrl-meson-axg.o diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c new file mode 100644 index 00000000000..c82413d08f3 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg-pmx.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Jerome Brunet <jbrunet@baylibre.com> + * Copyright (C) 2017 Xingyu Chen <xingyu.chen@amlogic.com> + */ + +#include <asm/gpio.h> +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <linux/io.h> +#include "pinctrl-meson-axg.h" + +static int meson_axg_pmx_get_bank(struct udevice *dev, unsigned int pin, + struct meson_pmx_bank **bank) +{ + int i; + struct meson_pinctrl *priv = dev_get_priv(dev); + struct meson_axg_pmx_data *pmx = priv->data->pmx_data; + + for (i = 0; i < pmx->num_pmx_banks; i++) + if (pin >= pmx->pmx_banks[i].first && + pin <= pmx->pmx_banks[i].last) { + *bank = &pmx->pmx_banks[i]; + return 0; + } + + return -EINVAL; +} + +static int meson_axg_pmx_calc_reg_and_offset(struct meson_pmx_bank *bank, + unsigned int pin, + unsigned int *reg, + unsigned int *offset) +{ + int shift; + + shift = pin - bank->first; + + *reg = bank->reg + (bank->offset + (shift << 2)) / 32; + *offset = (bank->offset + (shift << 2)) % 32; + + return 0; +} + +static int meson_axg_pmx_update_function(struct udevice *dev, + unsigned int pin, unsigned int func) +{ + struct meson_pinctrl *priv = dev_get_priv(dev); + struct meson_pmx_bank *bank; + unsigned int offset; + unsigned int reg; + unsigned int tmp; + int ret; + + ret = meson_axg_pmx_get_bank(dev, pin, &bank); + if (ret) + return ret; + + meson_axg_pmx_calc_reg_and_offset(bank, pin, ®, &offset); + + tmp = readl(priv->reg_mux + (reg << 2)); + tmp &= ~(0xf << offset); + tmp |= (func & 0xf) << offset; + writel(tmp, priv->reg_mux + (reg << 2)); + + return ret; +} + +static int meson_axg_pinmux_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct meson_pinctrl *priv = dev_get_priv(dev); + const struct meson_pmx_group *group; + const struct meson_pmx_func *func; + struct meson_pmx_axg_data *pmx_data; + int i, ret; + + group = &priv->data->groups[group_selector]; + pmx_data = (struct meson_pmx_axg_data *)group->data; + func = &priv->data->funcs[func_selector]; + + debug("pinmux: set group %s func %s\n", group->name, func->name); + + for (i = 0; i < group->num_pins; i++) { + ret = meson_axg_pmx_update_function(dev, group->pins[i], + pmx_data->func); + if (ret) + return ret; + } + + return 0; +} + +const struct pinctrl_ops meson_axg_pinctrl_ops = { + .get_groups_count = meson_pinctrl_get_groups_count, + .get_group_name = meson_pinctrl_get_group_name, + .get_functions_count = meson_pinmux_get_functions_count, + .get_function_name = meson_pinmux_get_function_name, + .pinmux_group_set = meson_axg_pinmux_group_set, + .set_state = pinctrl_generic_set_state, +}; + +static int meson_axg_gpio_request(struct udevice *dev, + unsigned int offset, const char *label) +{ + return meson_axg_pmx_update_function(dev->parent, offset, 0); +} + +static const struct dm_gpio_ops meson_axg_gpio_ops = { + .request = meson_axg_gpio_request, + .set_value = meson_gpio_set, + .get_value = meson_gpio_get, + .get_function = meson_gpio_get_direction, + .direction_input = meson_gpio_direction_input, + .direction_output = meson_gpio_direction_output, +}; + +const struct driver meson_axg_gpio_driver = { + .name = "meson-axg-gpio", + .id = UCLASS_GPIO, + .probe = meson_gpio_probe, + .ops = &meson_axg_gpio_ops, +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.c b/drivers/pinctrl/meson/pinctrl-meson-axg.c new file mode 100644 index 00000000000..a54fbce910a --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.c @@ -0,0 +1,979 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright (C) 2018 Neil Armstrong <narmstrong@baylibre.com> + * + * Based on code from Linux kernel: + * Copyright (c) 2017 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen <xingyu.chen@amlogic.com> + */ + +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <dt-bindings/gpio/meson-axg-gpio.h> + +#include "pinctrl-meson-axg.h" + +#define EE_OFF 14 + +/* emmc */ +static const unsigned int emmc_nand_d0_pins[] = {BOOT_0}; +static const unsigned int emmc_nand_d1_pins[] = {BOOT_1}; +static const unsigned int emmc_nand_d2_pins[] = {BOOT_2}; +static const unsigned int emmc_nand_d3_pins[] = {BOOT_3}; +static const unsigned int emmc_nand_d4_pins[] = {BOOT_4}; +static const unsigned int emmc_nand_d5_pins[] = {BOOT_5}; +static const unsigned int emmc_nand_d6_pins[] = {BOOT_6}; +static const unsigned int emmc_nand_d7_pins[] = {BOOT_7}; + +static const unsigned int emmc_clk_pins[] = {BOOT_8}; +static const unsigned int emmc_cmd_pins[] = {BOOT_10}; +static const unsigned int emmc_ds_pins[] = {BOOT_13}; + +/* nand */ +static const unsigned int nand_ce0_pins[] = {BOOT_8}; +static const unsigned int nand_ale_pins[] = {BOOT_9}; +static const unsigned int nand_cle_pins[] = {BOOT_10}; +static const unsigned int nand_wen_clk_pins[] = {BOOT_11}; +static const unsigned int nand_ren_wr_pins[] = {BOOT_12}; +static const unsigned int nand_rb0_pins[] = {BOOT_13}; + +/* nor */ +static const unsigned int nor_hold_pins[] = {BOOT_3}; +static const unsigned int nor_d_pins[] = {BOOT_4}; +static const unsigned int nor_q_pins[] = {BOOT_5}; +static const unsigned int nor_c_pins[] = {BOOT_6}; +static const unsigned int nor_wp_pins[] = {BOOT_9}; +static const unsigned int nor_cs_pins[] = {BOOT_14}; + +/* sdio */ +static const unsigned int sdio_d0_pins[] = {GPIOX_0}; +static const unsigned int sdio_d1_pins[] = {GPIOX_1}; +static const unsigned int sdio_d2_pins[] = {GPIOX_2}; +static const unsigned int sdio_d3_pins[] = {GPIOX_3}; +static const unsigned int sdio_clk_pins[] = {GPIOX_4}; +static const unsigned int sdio_cmd_pins[] = {GPIOX_5}; + +/* spi0 */ +static const unsigned int spi0_clk_pins[] = {GPIOZ_0}; +static const unsigned int spi0_mosi_pins[] = {GPIOZ_1}; +static const unsigned int spi0_miso_pins[] = {GPIOZ_2}; +static const unsigned int spi0_ss0_pins[] = {GPIOZ_3}; +static const unsigned int spi0_ss1_pins[] = {GPIOZ_4}; +static const unsigned int spi0_ss2_pins[] = {GPIOZ_5}; + +/* spi1 */ +static const unsigned int spi1_clk_x_pins[] = {GPIOX_19}; +static const unsigned int spi1_mosi_x_pins[] = {GPIOX_17}; +static const unsigned int spi1_miso_x_pins[] = {GPIOX_18}; +static const unsigned int spi1_ss0_x_pins[] = {GPIOX_16}; + +static const unsigned int spi1_clk_a_pins[] = {GPIOA_4}; +static const unsigned int spi1_mosi_a_pins[] = {GPIOA_2}; +static const unsigned int spi1_miso_a_pins[] = {GPIOA_3}; +static const unsigned int spi1_ss0_a_pins[] = {GPIOA_5}; +static const unsigned int spi1_ss1_pins[] = {GPIOA_6}; + +/* i2c0 */ +static const unsigned int i2c0_sck_pins[] = {GPIOZ_6}; +static const unsigned int i2c0_sda_pins[] = {GPIOZ_7}; + +/* i2c1 */ +static const unsigned int i2c1_sck_z_pins[] = {GPIOZ_8}; +static const unsigned int i2c1_sda_z_pins[] = {GPIOZ_9}; + +static const unsigned int i2c1_sck_x_pins[] = {GPIOX_16}; +static const unsigned int i2c1_sda_x_pins[] = {GPIOX_17}; + +/* i2c2 */ +static const unsigned int i2c2_sck_x_pins[] = {GPIOX_18}; +static const unsigned int i2c2_sda_x_pins[] = {GPIOX_19}; + +static const unsigned int i2c2_sda_a_pins[] = {GPIOA_17}; +static const unsigned int i2c2_sck_a_pins[] = {GPIOA_18}; + +/* i2c3 */ +static const unsigned int i2c3_sda_a6_pins[] = {GPIOA_6}; +static const unsigned int i2c3_sck_a7_pins[] = {GPIOA_7}; + +static const unsigned int i2c3_sda_a12_pins[] = {GPIOA_12}; +static const unsigned int i2c3_sck_a13_pins[] = {GPIOA_13}; + +static const unsigned int i2c3_sda_a19_pins[] = {GPIOA_19}; +static const unsigned int i2c3_sck_a20_pins[] = {GPIOA_20}; + +/* uart_a */ +static const unsigned int uart_rts_a_pins[] = {GPIOX_11}; +static const unsigned int uart_cts_a_pins[] = {GPIOX_10}; +static const unsigned int uart_tx_a_pins[] = {GPIOX_8}; +static const unsigned int uart_rx_a_pins[] = {GPIOX_9}; + +/* uart_b */ +static const unsigned int uart_rts_b_z_pins[] = {GPIOZ_0}; +static const unsigned int uart_cts_b_z_pins[] = {GPIOZ_1}; +static const unsigned int uart_tx_b_z_pins[] = {GPIOZ_2}; +static const unsigned int uart_rx_b_z_pins[] = {GPIOZ_3}; + +static const unsigned int uart_rts_b_x_pins[] = {GPIOX_18}; +static const unsigned int uart_cts_b_x_pins[] = {GPIOX_19}; +static const unsigned int uart_tx_b_x_pins[] = {GPIOX_16}; +static const unsigned int uart_rx_b_x_pins[] = {GPIOX_17}; + +/* uart_ao_b */ +static const unsigned int uart_ao_tx_b_z_pins[] = {GPIOZ_8}; +static const unsigned int uart_ao_rx_b_z_pins[] = {GPIOZ_9}; +static const unsigned int uart_ao_cts_b_z_pins[] = {GPIOZ_6}; +static const unsigned int uart_ao_rts_b_z_pins[] = {GPIOZ_7}; + +/* pwm_a */ +static const unsigned int pwm_a_z_pins[] = {GPIOZ_5}; + +static const unsigned int pwm_a_x18_pins[] = {GPIOX_18}; +static const unsigned int pwm_a_x20_pins[] = {GPIOX_20}; + +static const unsigned int pwm_a_a_pins[] = {GPIOA_14}; + +/* pwm_b */ +static const unsigned int pwm_b_z_pins[] = {GPIOZ_4}; + +static const unsigned int pwm_b_x_pins[] = {GPIOX_19}; + +static const unsigned int pwm_b_a_pins[] = {GPIOA_15}; + +/* pwm_c */ +static const unsigned int pwm_c_x10_pins[] = {GPIOX_10}; +static const unsigned int pwm_c_x17_pins[] = {GPIOX_17}; + +static const unsigned int pwm_c_a_pins[] = {GPIOA_16}; + +/* pwm_d */ +static const unsigned int pwm_d_x11_pins[] = {GPIOX_11}; +static const unsigned int pwm_d_x16_pins[] = {GPIOX_16}; + +/* pwm_vs */ +static const unsigned int pwm_vs_pins[] = {GPIOA_0}; + +/* spdif_in */ +static const unsigned int spdif_in_z_pins[] = {GPIOZ_4}; + +static const unsigned int spdif_in_a1_pins[] = {GPIOA_1}; +static const unsigned int spdif_in_a7_pins[] = {GPIOA_7}; +static const unsigned int spdif_in_a19_pins[] = {GPIOA_19}; +static const unsigned int spdif_in_a20_pins[] = {GPIOA_20}; + +/* spdif_out */ +static const unsigned int spdif_out_z_pins[] = {GPIOZ_5}; + +static const unsigned int spdif_out_a1_pins[] = {GPIOA_1}; +static const unsigned int spdif_out_a11_pins[] = {GPIOA_11}; +static const unsigned int spdif_out_a19_pins[] = {GPIOA_19}; +static const unsigned int spdif_out_a20_pins[] = {GPIOA_20}; + +/* jtag_ee */ +static const unsigned int jtag_tdo_x_pins[] = {GPIOX_0}; +static const unsigned int jtag_tdi_x_pins[] = {GPIOX_1}; +static const unsigned int jtag_clk_x_pins[] = {GPIOX_4}; +static const unsigned int jtag_tms_x_pins[] = {GPIOX_5}; + +/* eth */ +static const unsigned int eth_txd0_x_pins[] = {GPIOX_8}; +static const unsigned int eth_txd1_x_pins[] = {GPIOX_9}; +static const unsigned int eth_txen_x_pins[] = {GPIOX_10}; +static const unsigned int eth_rgmii_rx_clk_x_pins[] = {GPIOX_12}; +static const unsigned int eth_rxd0_x_pins[] = {GPIOX_13}; +static const unsigned int eth_rxd1_x_pins[] = {GPIOX_14}; +static const unsigned int eth_rx_dv_x_pins[] = {GPIOX_15}; +static const unsigned int eth_mdio_x_pins[] = {GPIOX_21}; +static const unsigned int eth_mdc_x_pins[] = {GPIOX_22}; + +static const unsigned int eth_txd0_y_pins[] = {GPIOY_10}; +static const unsigned int eth_txd1_y_pins[] = {GPIOY_11}; +static const unsigned int eth_txen_y_pins[] = {GPIOY_9}; +static const unsigned int eth_rgmii_rx_clk_y_pins[] = {GPIOY_2}; +static const unsigned int eth_rxd0_y_pins[] = {GPIOY_4}; +static const unsigned int eth_rxd1_y_pins[] = {GPIOY_5}; +static const unsigned int eth_rx_dv_y_pins[] = {GPIOY_3}; +static const unsigned int eth_mdio_y_pins[] = {GPIOY_0}; +static const unsigned int eth_mdc_y_pins[] = {GPIOY_1}; + +static const unsigned int eth_rxd2_rgmii_pins[] = {GPIOY_6}; +static const unsigned int eth_rxd3_rgmii_pins[] = {GPIOY_7}; +static const unsigned int eth_rgmii_tx_clk_pins[] = {GPIOY_8}; +static const unsigned int eth_txd2_rgmii_pins[] = {GPIOY_12}; +static const unsigned int eth_txd3_rgmii_pins[] = {GPIOY_13}; + +/* pdm */ +static const unsigned int pdm_dclk_a14_pins[] = {GPIOA_14}; +static const unsigned int pdm_dclk_a19_pins[] = {GPIOA_19}; +static const unsigned int pdm_din0_pins[] = {GPIOA_15}; +static const unsigned int pdm_din1_pins[] = {GPIOA_16}; +static const unsigned int pdm_din2_pins[] = {GPIOA_17}; +static const unsigned int pdm_din3_pins[] = {GPIOA_18}; + +/* mclk */ +static const unsigned int mclk_c_pins[] = {GPIOA_0}; +static const unsigned int mclk_b_pins[] = {GPIOA_1}; + +/* tdm */ +static const unsigned int tdma_sclk_pins[] = {GPIOX_12}; +static const unsigned int tdma_sclk_slv_pins[] = {GPIOX_12}; +static const unsigned int tdma_fs_pins[] = {GPIOX_13}; +static const unsigned int tdma_fs_slv_pins[] = {GPIOX_13}; +static const unsigned int tdma_din0_pins[] = {GPIOX_14}; +static const unsigned int tdma_dout0_x14_pins[] = {GPIOX_14}; +static const unsigned int tdma_dout0_x15_pins[] = {GPIOX_15}; +static const unsigned int tdma_dout1_pins[] = {GPIOX_15}; +static const unsigned int tdma_din1_pins[] = {GPIOX_15}; + +static const unsigned int tdmc_sclk_pins[] = {GPIOA_2}; +static const unsigned int tdmc_sclk_slv_pins[] = {GPIOA_2}; +static const unsigned int tdmc_fs_pins[] = {GPIOA_3}; +static const unsigned int tdmc_fs_slv_pins[] = {GPIOA_3}; +static const unsigned int tdmc_din0_pins[] = {GPIOA_4}; +static const unsigned int tdmc_dout0_pins[] = {GPIOA_4}; +static const unsigned int tdmc_din1_pins[] = {GPIOA_5}; +static const unsigned int tdmc_dout1_pins[] = {GPIOA_5}; +static const unsigned int tdmc_din2_pins[] = {GPIOA_6}; +static const unsigned int tdmc_dout2_pins[] = {GPIOA_6}; +static const unsigned int tdmc_din3_pins[] = {GPIOA_7}; +static const unsigned int tdmc_dout3_pins[] = {GPIOA_7}; + +static const unsigned int tdmb_sclk_pins[] = {GPIOA_8}; +static const unsigned int tdmb_sclk_slv_pins[] = {GPIOA_8}; +static const unsigned int tdmb_fs_pins[] = {GPIOA_9}; +static const unsigned int tdmb_fs_slv_pins[] = {GPIOA_9}; +static const unsigned int tdmb_din0_pins[] = {GPIOA_10}; +static const unsigned int tdmb_dout0_pins[] = {GPIOA_10}; +static const unsigned int tdmb_din1_pins[] = {GPIOA_11}; +static const unsigned int tdmb_dout1_pins[] = {GPIOA_11}; +static const unsigned int tdmb_din2_pins[] = {GPIOA_12}; +static const unsigned int tdmb_dout2_pins[] = {GPIOA_12}; +static const unsigned int tdmb_din3_pins[] = {GPIOA_13}; +static const unsigned int tdmb_dout3_pins[] = {GPIOA_13}; + +static struct meson_pmx_group meson_axg_periphs_groups[] = { + GPIO_GROUP(GPIOZ_0, EE_OFF), + GPIO_GROUP(GPIOZ_1, EE_OFF), + GPIO_GROUP(GPIOZ_2, EE_OFF), + GPIO_GROUP(GPIOZ_3, EE_OFF), + GPIO_GROUP(GPIOZ_4, EE_OFF), + GPIO_GROUP(GPIOZ_5, EE_OFF), + GPIO_GROUP(GPIOZ_6, EE_OFF), + GPIO_GROUP(GPIOZ_7, EE_OFF), + GPIO_GROUP(GPIOZ_8, EE_OFF), + GPIO_GROUP(GPIOZ_9, EE_OFF), + GPIO_GROUP(GPIOZ_10, EE_OFF), + + GPIO_GROUP(BOOT_0, EE_OFF), + GPIO_GROUP(BOOT_1, EE_OFF), + GPIO_GROUP(BOOT_2, EE_OFF), + GPIO_GROUP(BOOT_3, EE_OFF), + GPIO_GROUP(BOOT_4, EE_OFF), + GPIO_GROUP(BOOT_5, EE_OFF), + GPIO_GROUP(BOOT_6, EE_OFF), + GPIO_GROUP(BOOT_7, EE_OFF), + GPIO_GROUP(BOOT_8, EE_OFF), + GPIO_GROUP(BOOT_9, EE_OFF), + GPIO_GROUP(BOOT_10, EE_OFF), + GPIO_GROUP(BOOT_11, EE_OFF), + GPIO_GROUP(BOOT_12, EE_OFF), + GPIO_GROUP(BOOT_13, EE_OFF), + GPIO_GROUP(BOOT_14, EE_OFF), + + GPIO_GROUP(GPIOA_0, EE_OFF), + GPIO_GROUP(GPIOA_1, EE_OFF), + GPIO_GROUP(GPIOA_2, EE_OFF), + GPIO_GROUP(GPIOA_3, EE_OFF), + GPIO_GROUP(GPIOA_4, EE_OFF), + GPIO_GROUP(GPIOA_5, EE_OFF), + GPIO_GROUP(GPIOA_6, EE_OFF), + GPIO_GROUP(GPIOA_7, EE_OFF), + GPIO_GROUP(GPIOA_8, EE_OFF), + GPIO_GROUP(GPIOA_9, EE_OFF), + GPIO_GROUP(GPIOA_10, EE_OFF), + GPIO_GROUP(GPIOA_11, EE_OFF), + GPIO_GROUP(GPIOA_12, EE_OFF), + GPIO_GROUP(GPIOA_13, EE_OFF), + GPIO_GROUP(GPIOA_14, EE_OFF), + GPIO_GROUP(GPIOA_15, EE_OFF), + GPIO_GROUP(GPIOA_16, EE_OFF), + GPIO_GROUP(GPIOA_17, EE_OFF), + GPIO_GROUP(GPIOA_19, EE_OFF), + GPIO_GROUP(GPIOA_20, EE_OFF), + + GPIO_GROUP(GPIOX_0, EE_OFF), + GPIO_GROUP(GPIOX_1, EE_OFF), + GPIO_GROUP(GPIOX_2, EE_OFF), + GPIO_GROUP(GPIOX_3, EE_OFF), + GPIO_GROUP(GPIOX_4, EE_OFF), + GPIO_GROUP(GPIOX_5, EE_OFF), + GPIO_GROUP(GPIOX_6, EE_OFF), + GPIO_GROUP(GPIOX_7, EE_OFF), + GPIO_GROUP(GPIOX_8, EE_OFF), + GPIO_GROUP(GPIOX_9, EE_OFF), + GPIO_GROUP(GPIOX_10, EE_OFF), + GPIO_GROUP(GPIOX_11, EE_OFF), + GPIO_GROUP(GPIOX_12, EE_OFF), + GPIO_GROUP(GPIOX_13, EE_OFF), + GPIO_GROUP(GPIOX_14, EE_OFF), + GPIO_GROUP(GPIOX_15, EE_OFF), + GPIO_GROUP(GPIOX_16, EE_OFF), + GPIO_GROUP(GPIOX_17, EE_OFF), + GPIO_GROUP(GPIOX_18, EE_OFF), + GPIO_GROUP(GPIOX_19, EE_OFF), + GPIO_GROUP(GPIOX_20, EE_OFF), + GPIO_GROUP(GPIOX_21, EE_OFF), + GPIO_GROUP(GPIOX_22, EE_OFF), + + GPIO_GROUP(GPIOY_0, EE_OFF), + GPIO_GROUP(GPIOY_1, EE_OFF), + GPIO_GROUP(GPIOY_2, EE_OFF), + GPIO_GROUP(GPIOY_3, EE_OFF), + GPIO_GROUP(GPIOY_4, EE_OFF), + GPIO_GROUP(GPIOY_5, EE_OFF), + GPIO_GROUP(GPIOY_6, EE_OFF), + GPIO_GROUP(GPIOY_7, EE_OFF), + GPIO_GROUP(GPIOY_8, EE_OFF), + GPIO_GROUP(GPIOY_9, EE_OFF), + GPIO_GROUP(GPIOY_10, EE_OFF), + GPIO_GROUP(GPIOY_11, EE_OFF), + GPIO_GROUP(GPIOY_12, EE_OFF), + GPIO_GROUP(GPIOY_13, EE_OFF), + GPIO_GROUP(GPIOY_14, EE_OFF), + GPIO_GROUP(GPIOY_15, EE_OFF), + + /* bank BOOT */ + GROUP(emmc_nand_d0, 1), + GROUP(emmc_nand_d1, 1), + GROUP(emmc_nand_d2, 1), + GROUP(emmc_nand_d3, 1), + GROUP(emmc_nand_d4, 1), + GROUP(emmc_nand_d5, 1), + GROUP(emmc_nand_d6, 1), + GROUP(emmc_nand_d7, 1), + GROUP(emmc_clk, 1), + GROUP(emmc_cmd, 1), + GROUP(emmc_ds, 1), + GROUP(nand_ce0, 2), + GROUP(nand_ale, 2), + GROUP(nand_cle, 2), + GROUP(nand_wen_clk, 2), + GROUP(nand_ren_wr, 2), + GROUP(nand_rb0, 2), + GROUP(nor_hold, 3), + GROUP(nor_d, 3), + GROUP(nor_q, 3), + GROUP(nor_c, 3), + GROUP(nor_wp, 3), + GROUP(nor_cs, 3), + + /* bank GPIOZ */ + GROUP(spi0_clk, 1), + GROUP(spi0_mosi, 1), + GROUP(spi0_miso, 1), + GROUP(spi0_ss0, 1), + GROUP(spi0_ss1, 1), + GROUP(spi0_ss2, 1), + GROUP(i2c0_sck, 1), + GROUP(i2c0_sda, 1), + GROUP(i2c1_sck_z, 1), + GROUP(i2c1_sda_z, 1), + GROUP(uart_rts_b_z, 2), + GROUP(uart_cts_b_z, 2), + GROUP(uart_tx_b_z, 2), + GROUP(uart_rx_b_z, 2), + GROUP(pwm_a_z, 2), + GROUP(pwm_b_z, 2), + GROUP(spdif_in_z, 3), + GROUP(spdif_out_z, 3), + GROUP(uart_ao_tx_b_z, 2), + GROUP(uart_ao_rx_b_z, 2), + GROUP(uart_ao_cts_b_z, 2), + GROUP(uart_ao_rts_b_z, 2), + + /* bank GPIOX */ + GROUP(sdio_d0, 1), + GROUP(sdio_d1, 1), + GROUP(sdio_d2, 1), + GROUP(sdio_d3, 1), + GROUP(sdio_clk, 1), + GROUP(sdio_cmd, 1), + GROUP(i2c1_sck_x, 1), + GROUP(i2c1_sda_x, 1), + GROUP(i2c2_sck_x, 1), + GROUP(i2c2_sda_x, 1), + GROUP(uart_rts_a, 1), + GROUP(uart_cts_a, 1), + GROUP(uart_tx_a, 1), + GROUP(uart_rx_a, 1), + GROUP(uart_rts_b_x, 2), + GROUP(uart_cts_b_x, 2), + GROUP(uart_tx_b_x, 2), + GROUP(uart_rx_b_x, 2), + GROUP(jtag_tdo_x, 2), + GROUP(jtag_tdi_x, 2), + GROUP(jtag_clk_x, 2), + GROUP(jtag_tms_x, 2), + GROUP(spi1_clk_x, 4), + GROUP(spi1_mosi_x, 4), + GROUP(spi1_miso_x, 4), + GROUP(spi1_ss0_x, 4), + GROUP(pwm_a_x18, 3), + GROUP(pwm_a_x20, 1), + GROUP(pwm_b_x, 3), + GROUP(pwm_c_x10, 3), + GROUP(pwm_c_x17, 3), + GROUP(pwm_d_x11, 3), + GROUP(pwm_d_x16, 3), + GROUP(eth_txd0_x, 4), + GROUP(eth_txd1_x, 4), + GROUP(eth_txen_x, 4), + GROUP(eth_rgmii_rx_clk_x, 4), + GROUP(eth_rxd0_x, 4), + GROUP(eth_rxd1_x, 4), + GROUP(eth_rx_dv_x, 4), + GROUP(eth_mdio_x, 4), + GROUP(eth_mdc_x, 4), + GROUP(tdma_sclk, 1), + GROUP(tdma_sclk_slv, 2), + GROUP(tdma_fs, 1), + GROUP(tdma_fs_slv, 2), + GROUP(tdma_din0, 1), + GROUP(tdma_dout0_x14, 2), + GROUP(tdma_dout0_x15, 1), + GROUP(tdma_dout1, 2), + GROUP(tdma_din1, 3), + + /* bank GPIOY */ + GROUP(eth_txd0_y, 1), + GROUP(eth_txd1_y, 1), + GROUP(eth_txen_y, 1), + GROUP(eth_rgmii_rx_clk_y, 1), + GROUP(eth_rxd0_y, 1), + GROUP(eth_rxd1_y, 1), + GROUP(eth_rx_dv_y, 1), + GROUP(eth_mdio_y, 1), + GROUP(eth_mdc_y, 1), + GROUP(eth_rxd2_rgmii, 1), + GROUP(eth_rxd3_rgmii, 1), + GROUP(eth_rgmii_tx_clk, 1), + GROUP(eth_txd2_rgmii, 1), + GROUP(eth_txd3_rgmii, 1), + + /* bank GPIOA */ + GROUP(spdif_out_a1, 4), + GROUP(spdif_out_a11, 3), + GROUP(spdif_out_a19, 2), + GROUP(spdif_out_a20, 1), + GROUP(spdif_in_a1, 3), + GROUP(spdif_in_a7, 3), + GROUP(spdif_in_a19, 1), + GROUP(spdif_in_a20, 2), + GROUP(spi1_clk_a, 3), + GROUP(spi1_mosi_a, 3), + GROUP(spi1_miso_a, 3), + GROUP(spi1_ss0_a, 3), + GROUP(spi1_ss1, 3), + GROUP(pwm_a_a, 3), + GROUP(pwm_b_a, 3), + GROUP(pwm_c_a, 3), + GROUP(pwm_vs, 2), + GROUP(i2c2_sda_a, 3), + GROUP(i2c2_sck_a, 3), + GROUP(i2c3_sda_a6, 4), + GROUP(i2c3_sck_a7, 4), + GROUP(i2c3_sda_a12, 4), + GROUP(i2c3_sck_a13, 4), + GROUP(i2c3_sda_a19, 4), + GROUP(i2c3_sck_a20, 4), + GROUP(pdm_dclk_a14, 1), + GROUP(pdm_dclk_a19, 3), + GROUP(pdm_din0, 1), + GROUP(pdm_din1, 1), + GROUP(pdm_din2, 1), + GROUP(pdm_din3, 1), + GROUP(mclk_c, 1), + GROUP(mclk_b, 1), + GROUP(tdmc_sclk, 1), + GROUP(tdmc_sclk_slv, 2), + GROUP(tdmc_fs, 1), + GROUP(tdmc_fs_slv, 2), + GROUP(tdmc_din0, 2), + GROUP(tdmc_dout0, 1), + GROUP(tdmc_din1, 2), + GROUP(tdmc_dout1, 1), + GROUP(tdmc_din2, 2), + GROUP(tdmc_dout2, 1), + GROUP(tdmc_din3, 2), + GROUP(tdmc_dout3, 1), + GROUP(tdmb_sclk, 1), + GROUP(tdmb_sclk_slv, 2), + GROUP(tdmb_fs, 1), + GROUP(tdmb_fs_slv, 2), + GROUP(tdmb_din0, 2), + GROUP(tdmb_dout0, 1), + GROUP(tdmb_din1, 2), + GROUP(tdmb_dout1, 1), + GROUP(tdmb_din2, 2), + GROUP(tdmb_dout2, 1), + GROUP(tdmb_din3, 2), + GROUP(tdmb_dout3, 1), +}; + +/* uart_ao_a */ +static const unsigned int uart_ao_tx_a_pins[] = {GPIOAO_0}; +static const unsigned int uart_ao_rx_a_pins[] = {GPIOAO_1}; +static const unsigned int uart_ao_cts_a_pins[] = {GPIOAO_2}; +static const unsigned int uart_ao_rts_a_pins[] = {GPIOAO_3}; + +/* uart_ao_b */ +static const unsigned int uart_ao_tx_b_pins[] = {GPIOAO_4}; +static const unsigned int uart_ao_rx_b_pins[] = {GPIOAO_5}; +static const unsigned int uart_ao_cts_b_pins[] = {GPIOAO_2}; +static const unsigned int uart_ao_rts_b_pins[] = {GPIOAO_3}; + +/* i2c_ao */ +static const unsigned int i2c_ao_sck_4_pins[] = {GPIOAO_4}; +static const unsigned int i2c_ao_sda_5_pins[] = {GPIOAO_5}; +static const unsigned int i2c_ao_sck_8_pins[] = {GPIOAO_8}; +static const unsigned int i2c_ao_sda_9_pins[] = {GPIOAO_9}; +static const unsigned int i2c_ao_sck_10_pins[] = {GPIOAO_10}; +static const unsigned int i2c_ao_sda_11_pins[] = {GPIOAO_11}; + +/* i2c_ao_slave */ +static const unsigned int i2c_ao_slave_sck_pins[] = {GPIOAO_10}; +static const unsigned int i2c_ao_slave_sda_pins[] = {GPIOAO_11}; + +/* ir_in */ +static const unsigned int remote_input_ao_pins[] = {GPIOAO_6}; + +/* ir_out */ +static const unsigned int remote_out_ao_pins[] = {GPIOAO_7}; + +/* pwm_ao_a */ +static const unsigned int pwm_ao_a_pins[] = {GPIOAO_3}; + +/* pwm_ao_b */ +static const unsigned int pwm_ao_b_ao2_pins[] = {GPIOAO_2}; +static const unsigned int pwm_ao_b_ao12_pins[] = {GPIOAO_12}; + +/* pwm_ao_c */ +static const unsigned int pwm_ao_c_ao8_pins[] = {GPIOAO_8}; +static const unsigned int pwm_ao_c_ao13_pins[] = {GPIOAO_13}; + +/* pwm_ao_d */ +static const unsigned int pwm_ao_d_pins[] = {GPIOAO_9}; + +/* jtag_ao */ +static const unsigned int jtag_ao_tdi_pins[] = {GPIOAO_3}; +static const unsigned int jtag_ao_tdo_pins[] = {GPIOAO_4}; +static const unsigned int jtag_ao_clk_pins[] = {GPIOAO_5}; +static const unsigned int jtag_ao_tms_pins[] = {GPIOAO_7}; + +static struct meson_pmx_group meson_axg_aobus_groups[] = { + GPIO_GROUP(GPIOAO_0, 0), + GPIO_GROUP(GPIOAO_1, 0), + GPIO_GROUP(GPIOAO_2, 0), + GPIO_GROUP(GPIOAO_3, 0), + GPIO_GROUP(GPIOAO_4, 0), + GPIO_GROUP(GPIOAO_5, 0), + GPIO_GROUP(GPIOAO_6, 0), + GPIO_GROUP(GPIOAO_7, 0), + GPIO_GROUP(GPIOAO_8, 0), + GPIO_GROUP(GPIOAO_9, 0), + GPIO_GROUP(GPIOAO_10, 0), + GPIO_GROUP(GPIOAO_11, 0), + GPIO_GROUP(GPIOAO_12, 0), + GPIO_GROUP(GPIOAO_13, 0), + GPIO_GROUP(GPIO_TEST_N, 0), + + /* bank AO */ + GROUP(uart_ao_tx_a, 1), + GROUP(uart_ao_rx_a, 1), + GROUP(uart_ao_cts_a, 2), + GROUP(uart_ao_rts_a, 2), + GROUP(uart_ao_tx_b, 1), + GROUP(uart_ao_rx_b, 1), + GROUP(uart_ao_cts_b, 1), + GROUP(uart_ao_rts_b, 1), + GROUP(i2c_ao_sck_4, 2), + GROUP(i2c_ao_sda_5, 2), + GROUP(i2c_ao_sck_8, 2), + GROUP(i2c_ao_sda_9, 2), + GROUP(i2c_ao_sck_10, 2), + GROUP(i2c_ao_sda_11, 2), + GROUP(i2c_ao_slave_sck, 1), + GROUP(i2c_ao_slave_sda, 1), + GROUP(remote_input_ao, 1), + GROUP(remote_out_ao, 1), + GROUP(pwm_ao_a, 3), + GROUP(pwm_ao_b_ao2, 3), + GROUP(pwm_ao_b_ao12, 3), + GROUP(pwm_ao_c_ao8, 3), + GROUP(pwm_ao_c_ao13, 3), + GROUP(pwm_ao_d, 3), + GROUP(jtag_ao_tdi, 4), + GROUP(jtag_ao_tdo, 4), + GROUP(jtag_ao_clk, 4), + GROUP(jtag_ao_tms, 4), +}; + +static const char * const gpio_periphs_groups[] = { + "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4", + "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9", + "GPIOZ_10", + + "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4", + "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9", + "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14", + + "GPIOA_0", "GPIOA_1", "GPIOA_2", "GPIOA_3", "GPIOA_4", + "GPIOA_5", "GPIOA_6", "GPIOA_7", "GPIOA_8", "GPIOA_9", + "GPIOA_10", "GPIOA_11", "GPIOA_12", "GPIOA_13", "GPIOA_14", + "GPIOA_15", "GPIOA_16", "GPIOA_17", "GPIOA_18", "GPIOA_19", + "GPIOA_20", + + "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4", + "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", + "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", + "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19", + "GPIOX_20", "GPIOX_21", "GPIOX_22", + + "GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4", + "GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9", + "GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14", + "GPIOY_15", +}; + +static const char * const emmc_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "emmc_clk", "emmc_cmd", "emmc_ds", +}; + +static const char * const nand_groups[] = { + "emmc_nand_d0", "emmc_nand_d1", "emmc_nand_d2", + "emmc_nand_d3", "emmc_nand_d4", "emmc_nand_d5", + "emmc_nand_d6", "emmc_nand_d7", + "nand_ce0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_wr", "nand_rb0", +}; + +static const char * const nor_groups[] = { + "nor_d", "nor_q", "nor_c", "nor_cs", + "nor_hold", "nor_wp", +}; + +static const char * const sdio_groups[] = { + "sdio_d0", "sdio_d1", "sdio_d2", "sdio_d3", + "sdio_cmd", "sdio_clk", +}; + +static const char * const spi0_groups[] = { + "spi0_clk", "spi0_mosi", "spi0_miso", "spi0_ss0", + "spi0_ss1", "spi0_ss2" +}; + +static const char * const spi1_groups[] = { + "spi1_clk_x", "spi1_mosi_x", "spi1_miso_x", "spi1_ss0_x", + "spi1_clk_a", "spi1_mosi_a", "spi1_miso_a", "spi1_ss0_a", + "spi1_ss1" +}; + +static const char * const uart_a_groups[] = { + "uart_tx_a", "uart_rx_a", "uart_cts_a", "uart_rts_a", +}; + +static const char * const uart_b_groups[] = { + "uart_tx_b_z", "uart_rx_b_z", "uart_cts_b_z", "uart_rts_b_z", + "uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x", +}; + +static const char * const uart_ao_b_z_groups[] = { + "uart_ao_tx_b_z", "uart_ao_rx_b_z", + "uart_ao_cts_b_z", "uart_ao_rts_b_z", +}; + +static const char * const i2c0_groups[] = { + "i2c0_sck", "i2c0_sda", +}; + +static const char * const i2c1_groups[] = { + "i2c1_sck_z", "i2c1_sda_z", + "i2c1_sck_x", "i2c1_sda_x", +}; + +static const char * const i2c2_groups[] = { + "i2c2_sck_x", "i2c2_sda_x", + "i2c2_sda_a", "i2c2_sck_a", +}; + +static const char * const i2c3_groups[] = { + "i2c3_sda_a6", "i2c3_sck_a7", + "i2c3_sda_a12", "i2c3_sck_a13", + "i2c3_sda_a19", "i2c3_sck_a20", +}; + +static const char * const eth_groups[] = { + "eth_rxd2_rgmii", "eth_rxd3_rgmii", "eth_rgmii_tx_clk", + "eth_txd2_rgmii", "eth_txd3_rgmii", + "eth_txd0_x", "eth_txd1_x", "eth_txen_x", "eth_rgmii_rx_clk_x", + "eth_rxd0_x", "eth_rxd1_x", "eth_rx_dv_x", "eth_mdio_x", + "eth_mdc_x", + "eth_txd0_y", "eth_txd1_y", "eth_txen_y", "eth_rgmii_rx_clk_y", + "eth_rxd0_y", "eth_rxd1_y", "eth_rx_dv_y", "eth_mdio_y", + "eth_mdc_y", +}; + +static const char * const pwm_a_groups[] = { + "pwm_a_z", "pwm_a_x18", "pwm_a_x20", "pwm_a_a", +}; + +static const char * const pwm_b_groups[] = { + "pwm_b_z", "pwm_b_x", "pwm_b_a", +}; + +static const char * const pwm_c_groups[] = { + "pwm_c_x10", "pwm_c_x17", "pwm_c_a", +}; + +static const char * const pwm_d_groups[] = { + "pwm_d_x11", "pwm_d_x16", +}; + +static const char * const pwm_vs_groups[] = { + "pwm_vs", +}; + +static const char * const spdif_out_groups[] = { + "spdif_out_z", "spdif_out_a1", "spdif_out_a11", + "spdif_out_a19", "spdif_out_a20", +}; + +static const char * const spdif_in_groups[] = { + "spdif_in_z", "spdif_in_a1", "spdif_in_a7", + "spdif_in_a19", "spdif_in_a20", +}; + +static const char * const jtag_ee_groups[] = { + "jtag_tdo_x", "jtag_tdi_x", "jtag_clk_x", + "jtag_tms_x", +}; + +static const char * const pdm_groups[] = { + "pdm_din0", "pdm_din1", "pdm_din2", "pdm_din3", + "pdm_dclk_a14", "pdm_dclk_a19", +}; + +static const char * const gpio_aobus_groups[] = { + "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", + "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", + "GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13", + "GPIO_TEST_N", +}; + +static const char * const uart_ao_a_groups[] = { + "uart_ao_tx_a", "uart_ao_rx_a", "uart_ao_cts_a", "uart_ao_rts_a", +}; + +static const char * const uart_ao_b_groups[] = { + "uart_ao_tx_b", "uart_ao_rx_b", "uart_ao_cts_b", "uart_ao_rts_b", +}; + +static const char * const i2c_ao_groups[] = { + "i2c_ao_sck_4", "i2c_ao_sda_5", + "i2c_ao_sck_8", "i2c_ao_sda_9", + "i2c_ao_sck_10", "i2c_ao_sda_11", +}; + +static const char * const i2c_ao_slave_groups[] = { + "i2c_ao_slave_sck", "i2c_ao_slave_sda", +}; + +static const char * const remote_input_ao_groups[] = { + "remote_input_ao", +}; + +static const char * const remote_out_ao_groups[] = { + "remote_out_ao", +}; + +static const char * const pwm_ao_a_groups[] = { + "pwm_ao_a", +}; + +static const char * const pwm_ao_b_groups[] = { + "pwm_ao_b_ao2", "pwm_ao_b_ao12", +}; + +static const char * const pwm_ao_c_groups[] = { + "pwm_ao_c_ao8", "pwm_ao_c_ao13", +}; + +static const char * const pwm_ao_d_groups[] = { + "pwm_ao_d", +}; + +static const char * const jtag_ao_groups[] = { + "jtag_ao_tdi", "jtag_ao_tdo", "jtag_ao_clk", "jtag_ao_tms", +}; + +static const char * const mclk_c_groups[] = { + "mclk_c", +}; + +static const char * const mclk_b_groups[] = { + "mclk_b", +}; + +static const char * const tdma_groups[] = { + "tdma_sclk", "tdma_sclk_slv", "tdma_fs", "tdma_fs_slv", + "tdma_din0", "tdma_dout0_x14", "tdma_dout0_x15", "tdma_dout1", + "tdma_din1", +}; + +static const char * const tdmc_groups[] = { + "tdmc_sclk", "tdmc_sclk_slv", "tdmc_fs", "tdmc_fs_slv", + "tdmc_din0", "tdmc_dout0", "tdmc_din1", "tdmc_dout1", + "tdmc_din2", "tdmc_dout2", "tdmc_din3", "tdmc_dout3", +}; + +static const char * const tdmb_groups[] = { + "tdmb_sclk", "tdmb_sclk_slv", "tdmb_fs", "tdmb_fs_slv", + "tdmb_din0", "tdmb_dout0", "tdmb_din1", "tdmb_dout1", + "tdmb_din2", "tdmb_dout2", "tdmb_din3", "tdmb_dout3", +}; + +static struct meson_pmx_func meson_axg_periphs_functions[] = { + FUNCTION(gpio_periphs), + FUNCTION(emmc), + FUNCTION(nor), + FUNCTION(spi0), + FUNCTION(spi1), + FUNCTION(sdio), + FUNCTION(nand), + FUNCTION(uart_a), + FUNCTION(uart_b), + FUNCTION(uart_ao_b_z), + FUNCTION(i2c0), + FUNCTION(i2c1), + FUNCTION(i2c2), + FUNCTION(i2c3), + FUNCTION(eth), + FUNCTION(pwm_a), + FUNCTION(pwm_b), + FUNCTION(pwm_c), + FUNCTION(pwm_d), + FUNCTION(pwm_vs), + FUNCTION(spdif_out), + FUNCTION(spdif_in), + FUNCTION(jtag_ee), + FUNCTION(pdm), + FUNCTION(mclk_b), + FUNCTION(mclk_c), + FUNCTION(tdma), + FUNCTION(tdmb), + FUNCTION(tdmc), +}; + +static struct meson_pmx_func meson_axg_aobus_functions[] = { + FUNCTION(gpio_aobus), + FUNCTION(uart_ao_a), + FUNCTION(uart_ao_b), + FUNCTION(i2c_ao), + FUNCTION(i2c_ao_slave), + FUNCTION(remote_input_ao), + FUNCTION(remote_out_ao), + FUNCTION(pwm_ao_a), + FUNCTION(pwm_ao_b), + FUNCTION(pwm_ao_c), + FUNCTION(pwm_ao_d), + FUNCTION(jtag_ao), +}; + +static struct meson_bank meson_axg_periphs_banks[] = { + /* name first last pullen pull dir out in */ + BANK("Z", GPIOZ_0, GPIOZ_10, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), + BANK("BOOT", BOOT_0, BOOT_14, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), + BANK("A", GPIOA_0, GPIOA_20, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), + BANK("X", GPIOX_0, GPIOX_22, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), + BANK("Y", GPIOY_0, GPIOY_15, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), +}; + +static struct meson_bank meson_axg_aobus_banks[] = { + /* name first last pullen pull dir out in */ + BANK("AO", GPIOAO_0, GPIOAO_13, 0, 16, 0, 0, 0, 0, 0, 16, 1, 0), +}; + +static struct meson_pmx_bank meson_axg_periphs_pmx_banks[] = { + /* name first lask reg offset */ + BANK_PMX("Z", GPIOZ_0, GPIOZ_10, 0x2, 0), + BANK_PMX("BOOT", BOOT_0, BOOT_14, 0x0, 0), + BANK_PMX("A", GPIOA_0, GPIOA_20, 0xb, 0), + BANK_PMX("X", GPIOX_0, GPIOX_22, 0x4, 0), + BANK_PMX("Y", GPIOY_0, GPIOY_15, 0x8, 0), +}; + +static struct meson_axg_pmx_data meson_axg_periphs_pmx_banks_data = { + .pmx_banks = meson_axg_periphs_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_axg_periphs_pmx_banks), +}; + +static struct meson_pmx_bank meson_axg_aobus_pmx_banks[] = { + BANK_PMX("AO", GPIOAO_0, GPIOAO_13, 0x0, 0), +}; + +static struct meson_axg_pmx_data meson_axg_aobus_pmx_banks_data = { + .pmx_banks = meson_axg_aobus_pmx_banks, + .num_pmx_banks = ARRAY_SIZE(meson_axg_aobus_pmx_banks), +}; + +struct meson_pinctrl_data meson_axg_periphs_pinctrl_data = { + .name = "periphs-banks", + .pin_base = 11, + .groups = meson_axg_periphs_groups, + .funcs = meson_axg_periphs_functions, + .banks = meson_axg_periphs_banks, + .num_pins = 100, + .num_groups = ARRAY_SIZE(meson_axg_periphs_groups), + .num_funcs = ARRAY_SIZE(meson_axg_periphs_functions), + .num_banks = ARRAY_SIZE(meson_axg_periphs_banks), + .gpio_driver = &meson_axg_gpio_driver, + .pmx_data = &meson_axg_periphs_pmx_banks_data, +}; + +struct meson_pinctrl_data meson_axg_aobus_pinctrl_data = { + .name = "aobus-banks", + .pin_base = 0, + .groups = meson_axg_aobus_groups, + .funcs = meson_axg_aobus_functions, + .banks = meson_axg_aobus_banks, + .num_pins = 14, + .num_groups = ARRAY_SIZE(meson_axg_aobus_groups), + .num_funcs = ARRAY_SIZE(meson_axg_aobus_functions), + .num_banks = ARRAY_SIZE(meson_axg_aobus_banks), + .gpio_driver = &meson_axg_gpio_driver, + .pmx_data = &meson_axg_aobus_pmx_banks_data, +}; + +static const struct udevice_id meson_axg_pinctrl_match[] = { + { + .compatible = "amlogic,meson-axg-periphs-pinctrl", + .data = (ulong)&meson_axg_periphs_pinctrl_data, + }, + { + .compatible = "amlogic,meson-axg-aobus-pinctrl", + .data = (ulong)&meson_axg_aobus_pinctrl_data, + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(meson_axg_pinctrl) = { + .name = "meson-axg-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(meson_axg_pinctrl_match), + .probe = meson_pinctrl_probe, + .priv_auto_alloc_size = sizeof(struct meson_pinctrl), + .ops = &meson_axg_pinctrl_ops, +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-axg.h b/drivers/pinctrl/meson/pinctrl-meson-axg.h new file mode 100644 index 00000000000..c8d2b3af036 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-axg.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com> + * Copyright (C) 2017 Xingyu Chen <xingyu.chen@amlogic.com> + */ + +#ifndef __PINCTRL_MESON_AXG_H__ +#define __PINCTRL_MESON_AXG_H__ + +#include "pinctrl-meson.h" + +struct meson_pmx_bank { + const char *name; + unsigned int first; + unsigned int last; + unsigned int reg; + unsigned int offset; +}; + +struct meson_axg_pmx_data { + struct meson_pmx_bank *pmx_banks; + unsigned int num_pmx_banks; +}; + +#define BANK_PMX(n, f, l, r, o) \ + { \ + .name = n, \ + .first = f, \ + .last = l, \ + .reg = r, \ + .offset = o, \ + } + +struct meson_pmx_axg_data { + unsigned int func; +}; + +#define PMX_DATA(f) \ + { \ + .func = f, \ + } + +#define GROUP(grp, f) \ + { \ + .name = #grp, \ + .pins = grp ## _pins, \ + .num_pins = ARRAY_SIZE(grp ## _pins), \ + .data = (const struct meson_pmx_axg_data[]){ \ + PMX_DATA(f), \ + }, \ + } + +#define GPIO_GROUP(gpio, b) \ + { \ + .name = #gpio, \ + .pins = (const unsigned int[]){ PIN(gpio, b) }, \ + .num_pins = 1, \ + .data = (const struct meson_pmx_axg_data[]){ \ + PMX_DATA(0), \ + }, \ + } + +extern const struct pinctrl_ops meson_axg_pinctrl_ops; +extern const struct driver meson_axg_gpio_driver; + +#endif /* __PINCTRL_MESON_AXG_H__ */ diff --git a/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c b/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c new file mode 100644 index 00000000000..fc1538ea719 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-gx-pmx.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com> + */ + +#include <asm/gpio.h> +#include <common.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <linux/io.h> +#include "pinctrl-meson-gx.h" + +static void meson_gx_pinmux_disable_other_groups(struct meson_pinctrl *priv, + unsigned int pin, + int sel_group) +{ + struct meson_pmx_group *group; + struct meson_gx_pmx_data *pmx_data; + void __iomem *addr; + int i, j; + + for (i = 0; i < priv->data->num_groups; i++) { + group = &priv->data->groups[i]; + pmx_data = (struct meson_gx_pmx_data *)group->data; + if (pmx_data->is_gpio || i == sel_group) + continue; + + for (j = 0; j < group->num_pins; j++) { + if (group->pins[j] == pin) { + /* We have found a group using the pin */ + debug("pinmux: disabling %s\n", group->name); + addr = priv->reg_mux + pmx_data->reg * 4; + writel(readl(addr) & ~BIT(pmx_data->bit), addr); + } + } + } +} + +static int meson_gx_pinmux_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct meson_pinctrl *priv = dev_get_priv(dev); + const struct meson_pmx_group *group; + const struct meson_pmx_func *func; + struct meson_gx_pmx_data *pmx_data; + void __iomem *addr; + int i; + + group = &priv->data->groups[group_selector]; + pmx_data = (struct meson_gx_pmx_data *)group->data; + func = &priv->data->funcs[func_selector]; + + debug("pinmux: set group %s func %s\n", group->name, func->name); + + /* + * Disable groups using the same pins. + * The selected group is not disabled to avoid glitches. + */ + for (i = 0; i < group->num_pins; i++) { + meson_gx_pinmux_disable_other_groups(priv, + group->pins[i], + group_selector); + } + + /* Function 0 (GPIO) doesn't need any additional setting */ + if (func_selector) { + addr = priv->reg_mux + pmx_data->reg * 4; + writel(readl(addr) | BIT(pmx_data->bit), addr); + } + + return 0; +} + +const struct pinctrl_ops meson_gx_pinctrl_ops = { + .get_groups_count = meson_pinctrl_get_groups_count, + .get_group_name = meson_pinctrl_get_group_name, + .get_functions_count = meson_pinmux_get_functions_count, + .get_function_name = meson_pinmux_get_function_name, + .pinmux_group_set = meson_gx_pinmux_group_set, + .set_state = pinctrl_generic_set_state, +}; + +static const struct dm_gpio_ops meson_gx_gpio_ops = { + .set_value = meson_gpio_set, + .get_value = meson_gpio_get, + .get_function = meson_gpio_get_direction, + .direction_input = meson_gpio_direction_input, + .direction_output = meson_gpio_direction_output, +}; + +const struct driver meson_gx_gpio_driver = { + .name = "meson-gx-gpio", + .id = UCLASS_GPIO, + .probe = meson_gpio_probe, + .ops = &meson_gx_gpio_ops, +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-gx.h b/drivers/pinctrl/meson/pinctrl-meson-gx.h new file mode 100644 index 00000000000..4c1aa1a3002 --- /dev/null +++ b/drivers/pinctrl/meson/pinctrl-meson-gx.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com> + */ + +#ifndef __PINCTRL_MESON_GX_H__ +#define __PINCTRL_MESON_GX_H__ + +#include "pinctrl-meson.h" + +struct meson_gx_pmx_data { + bool is_gpio; + unsigned int reg; + unsigned int bit; +}; + +#define PMX_DATA(r, b, g) \ + { \ + .reg = r, \ + .bit = b, \ + .is_gpio = g, \ + } + +#define GROUP(grp, r, b) \ + { \ + .name = #grp, \ + .pins = grp ## _pins, \ + .num_pins = ARRAY_SIZE(grp ## _pins), \ + .data = (const struct meson_gx_pmx_data[]){ \ + PMX_DATA(r, b, false), \ + }, \ + } + +#define GPIO_GROUP(gpio, b) \ + { \ + .name = #gpio, \ + .pins = (const unsigned int[]){ PIN(gpio, b) }, \ + .num_pins = 1, \ + .data = (const struct meson_gx_pmx_data[]){ \ + PMX_DATA(0, 0, true), \ + }, \ + } + +extern const struct pinctrl_ops meson_gx_pinctrl_ops; +extern const struct driver meson_gx_gpio_driver; + +#endif /* __PINCTRL_MESON_GX_H__ */ diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index a8e47e3c4e8..22e8b055d79 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -11,7 +11,7 @@ #include <dm/pinctrl.h> #include <dt-bindings/gpio/meson-gxbb-gpio.h> -#include "pinctrl-meson.h" +#include "pinctrl-meson-gx.h" #define EE_OFF 15 @@ -417,6 +417,7 @@ struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = { .num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions), .num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks), + .gpio_driver = &meson_gx_gpio_driver, }; struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { @@ -429,6 +430,7 @@ struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { .num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions), .num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks), + .gpio_driver = &meson_gx_gpio_driver, }; static const struct udevice_id meson_gxbb_pinctrl_match[] = { @@ -449,5 +451,5 @@ U_BOOT_DRIVER(meson_gxbb_pinctrl) = { .of_match = of_match_ptr(meson_gxbb_pinctrl_match), .probe = meson_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct meson_pinctrl), - .ops = &meson_pinctrl_ops, + .ops = &meson_gx_pinctrl_ops, }; diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c index ba6e3531d93..1819eee4d07 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c @@ -11,7 +11,7 @@ #include <dm/pinctrl.h> #include <dt-bindings/gpio/meson-gxl-gpio.h> -#include "pinctrl-meson.h" +#include "pinctrl-meson-gx.h" #define EE_OFF 11 @@ -699,6 +699,7 @@ struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = { .num_groups = ARRAY_SIZE(meson_gxl_periphs_groups), .num_funcs = ARRAY_SIZE(meson_gxl_periphs_functions), .num_banks = ARRAY_SIZE(meson_gxl_periphs_banks), + .gpio_driver = &meson_gx_gpio_driver, }; struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = { @@ -711,6 +712,7 @@ struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = { .num_groups = ARRAY_SIZE(meson_gxl_aobus_groups), .num_funcs = ARRAY_SIZE(meson_gxl_aobus_functions), .num_banks = ARRAY_SIZE(meson_gxl_aobus_banks), + .gpio_driver = &meson_gx_gpio_driver, }; static const struct udevice_id meson_gxl_pinctrl_match[] = { @@ -731,5 +733,5 @@ U_BOOT_DRIVER(meson_gxl_pinctrl) = { .of_match = of_match_ptr(meson_gxl_pinctrl_match), .probe = meson_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct meson_pinctrl), - .ops = &meson_pinctrl_ops, + .ops = &meson_gx_pinctrl_ops, }; diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 387c241d12b..0bd6152803d 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -20,15 +20,15 @@ DECLARE_GLOBAL_DATA_PTR; static const char *meson_pinctrl_dummy_name = "_dummy"; -static int meson_pinctrl_get_groups_count(struct udevice *dev) +int meson_pinctrl_get_groups_count(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev); return priv->data->num_groups; } -static const char *meson_pinctrl_get_group_name(struct udevice *dev, - unsigned selector) +const char *meson_pinctrl_get_group_name(struct udevice *dev, + unsigned int selector) { struct meson_pinctrl *priv = dev_get_priv(dev); @@ -38,87 +38,21 @@ static const char *meson_pinctrl_get_group_name(struct udevice *dev, return priv->data->groups[selector].name; } -static int meson_pinmux_get_functions_count(struct udevice *dev) +int meson_pinmux_get_functions_count(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev); return priv->data->num_funcs; } -static const char *meson_pinmux_get_function_name(struct udevice *dev, - unsigned selector) +const char *meson_pinmux_get_function_name(struct udevice *dev, + unsigned int selector) { struct meson_pinctrl *priv = dev_get_priv(dev); return priv->data->funcs[selector].name; } -static void meson_pinmux_disable_other_groups(struct meson_pinctrl *priv, - unsigned int pin, int sel_group) -{ - struct meson_pmx_group *group; - void __iomem *addr; - int i, j; - - for (i = 0; i < priv->data->num_groups; i++) { - group = &priv->data->groups[i]; - if (group->is_gpio || i == sel_group) - continue; - - for (j = 0; j < group->num_pins; j++) { - if (group->pins[j] == pin) { - /* We have found a group using the pin */ - debug("pinmux: disabling %s\n", group->name); - addr = priv->reg_mux + group->reg * 4; - writel(readl(addr) & ~BIT(group->bit), addr); - } - } - } -} - -static int meson_pinmux_group_set(struct udevice *dev, - unsigned group_selector, - unsigned func_selector) -{ - struct meson_pinctrl *priv = dev_get_priv(dev); - const struct meson_pmx_group *group; - const struct meson_pmx_func *func; - void __iomem *addr; - int i; - - group = &priv->data->groups[group_selector]; - func = &priv->data->funcs[func_selector]; - - debug("pinmux: set group %s func %s\n", group->name, func->name); - - /* - * Disable groups using the same pins. - * The selected group is not disabled to avoid glitches. - */ - for (i = 0; i < group->num_pins; i++) { - meson_pinmux_disable_other_groups(priv, - group->pins[i], - group_selector); - } - - /* Function 0 (GPIO) doesn't need any additional setting */ - if (func_selector) { - addr = priv->reg_mux + group->reg * 4; - writel(readl(addr) | BIT(group->bit), addr); - } - - return 0; -} - -const struct pinctrl_ops meson_pinctrl_ops = { - .get_groups_count = meson_pinctrl_get_groups_count, - .get_group_name = meson_pinctrl_get_group_name, - .get_functions_count = meson_pinmux_get_functions_count, - .get_function_name = meson_pinmux_get_function_name, - .pinmux_group_set = meson_pinmux_group_set, - .set_state = pinctrl_generic_set_state, -}; - static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset, enum meson_reg_type reg_type, unsigned int *reg, unsigned int *bit) @@ -149,7 +83,7 @@ static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset, return 0; } -static int meson_gpio_get(struct udevice *dev, unsigned int offset) +int meson_gpio_get(struct udevice *dev, unsigned int offset) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; @@ -162,7 +96,7 @@ static int meson_gpio_get(struct udevice *dev, unsigned int offset) return !!(readl(priv->reg_gpio + reg) & BIT(bit)); } -static int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) +int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; @@ -177,7 +111,7 @@ static int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) return 0; } -static int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) +int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit, val; @@ -192,7 +126,7 @@ static int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT; } -static int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) +int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; @@ -207,8 +141,8 @@ static int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) return 0; } -static int meson_gpio_direction_output(struct udevice *dev, - unsigned int offset, int value) +int meson_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; @@ -229,7 +163,7 @@ static int meson_gpio_direction_output(struct udevice *dev, return 0; } -static int meson_gpio_probe(struct udevice *dev) +int meson_gpio_probe(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev->parent); struct gpio_dev_priv *uc_priv; @@ -241,21 +175,6 @@ static int meson_gpio_probe(struct udevice *dev) return 0; } -static const struct dm_gpio_ops meson_gpio_ops = { - .set_value = meson_gpio_set, - .get_value = meson_gpio_get, - .get_function = meson_gpio_get_direction, - .direction_input = meson_gpio_direction_input, - .direction_output = meson_gpio_direction_output, -}; - -static struct driver meson_gpio_driver = { - .name = "meson-gpio", - .id = UCLASS_GPIO, - .probe = meson_gpio_probe, - .ops = &meson_gpio_ops, -}; - static fdt_addr_t parse_address(int offset, const char *name, int na, int ns) { int index, len = 0; @@ -334,7 +253,7 @@ int meson_pinctrl_probe(struct udevice *dev) sprintf(name, "meson-gpio"); /* Create child device UCLASS_GPIO and bind it */ - device_bind(dev, &meson_gpio_driver, name, NULL, gpio, &gpio_dev); + device_bind(dev, priv->data->gpio_driver, name, NULL, gpio, &gpio_dev); dev_set_of_offset(gpio_dev, gpio); return 0; diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h index 6ec89ba117b..bdee721fc00 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.h +++ b/drivers/pinctrl/meson/pinctrl-meson.h @@ -12,9 +12,7 @@ struct meson_pmx_group { const char *name; const unsigned int *pins; unsigned int num_pins; - bool is_gpio; - unsigned int reg; - unsigned int bit; + const void *data; }; struct meson_pmx_func { @@ -33,6 +31,8 @@ struct meson_pinctrl_data { unsigned int num_groups; unsigned int num_funcs; unsigned int num_banks; + const struct driver *gpio_driver; + void *pmx_data; }; struct meson_pinctrl { @@ -89,23 +89,6 @@ struct meson_bank { #define PIN(x, b) (b + x) -#define GROUP(grp, r, b) \ - { \ - .name = #grp, \ - .pins = grp ## _pins, \ - .num_pins = ARRAY_SIZE(grp ## _pins), \ - .reg = r, \ - .bit = b, \ - } - -#define GPIO_GROUP(gpio, b) \ - { \ - .name = #gpio, \ - .pins = (const unsigned int[]){ PIN(gpio, b) }, \ - .num_pins = 1, \ - .is_gpio = true, \ - } - #define FUNCTION(fn) \ { \ .name = #fn, \ @@ -131,6 +114,20 @@ struct meson_bank { extern const struct pinctrl_ops meson_pinctrl_ops; +int meson_pinctrl_get_groups_count(struct udevice *dev); +const char *meson_pinctrl_get_group_name(struct udevice *dev, + unsigned int selector); +int meson_pinmux_get_functions_count(struct udevice *dev); +const char *meson_pinmux_get_function_name(struct udevice *dev, + unsigned int selector); int meson_pinctrl_probe(struct udevice *dev); +int meson_gpio_get(struct udevice *dev, unsigned int offset); +int meson_gpio_set(struct udevice *dev, unsigned int offset, int value); +int meson_gpio_get_direction(struct udevice *dev, unsigned int offset); +int meson_gpio_direction_input(struct udevice *dev, unsigned int offset); +int meson_gpio_direction_output(struct udevice *dev, unsigned int offset, + int value); +int meson_gpio_probe(struct udevice *dev); + #endif /* __PINCTRL_MESON_H__ */ diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index a08b4288b40..93deaef8096 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -23,6 +23,13 @@ config IMX8_POWER_DOMAIN Enable support for manipulating NXP i.MX8 on-SoC power domains via IPC requests to the SCU. +config MTK_POWER_DOMAIN + bool "Enable the MediaTek power domain driver" + depends on POWER_DOMAIN && ARCH_MEDIATEK + help + Enable support for manipulating MediaTek power domains via MMIO + mapped registers. + config MESON_GX_VPU_POWER_DOMAIN bool "Enable Amlogic Meson GX VPU power domain driver" depends on ARCH_MESON diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index b08d18f7ac3..695aafe17d2 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain.o +obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o diff --git a/drivers/power/domain/mtk-power-domain.c b/drivers/power/domain/mtk-power-domain.c new file mode 100644 index 00000000000..c67e8804b16 --- /dev/null +++ b/drivers/power/domain/mtk-power-domain.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <power-domain-uclass.h> +#include <regmap.h> +#include <syscon.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <linux/iopoll.h> + +#include <dt-bindings/power/mt7623-power.h> +#include <dt-bindings/power/mt7629-power.h> + +#define SPM_EN (0xb16 << 16 | 0x1) +#define SPM_VDE_PWR_CON 0x0210 +#define SPM_MFG_PWR_CON 0x0214 +#define SPM_ISP_PWR_CON 0x0238 +#define SPM_DIS_PWR_CON 0x023c +#define SPM_CONN_PWR_CON 0x0280 +#define SPM_BDP_PWR_CON 0x029c +#define SPM_ETH_PWR_CON 0x02a0 +#define SPM_HIF_PWR_CON 0x02a4 +#define SPM_IFR_MSC_PWR_CON 0x02a8 +#define SPM_ETHSYS_PWR_CON 0x2e0 +#define SPM_HIF0_PWR_CON 0x2e4 +#define SPM_HIF1_PWR_CON 0x2e8 +#define SPM_PWR_STATUS 0x60c +#define SPM_PWR_STATUS_2ND 0x610 + +#define PWR_RST_B_BIT BIT(0) +#define PWR_ISO_BIT BIT(1) +#define PWR_ON_BIT BIT(2) +#define PWR_ON_2ND_BIT BIT(3) +#define PWR_CLK_DIS_BIT BIT(4) + +#define PWR_STATUS_CONN BIT(1) +#define PWR_STATUS_DISP BIT(3) +#define PWR_STATUS_MFG BIT(4) +#define PWR_STATUS_ISP BIT(5) +#define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_BDP BIT(14) +#define PWR_STATUS_ETH BIT(15) +#define PWR_STATUS_HIF BIT(16) +#define PWR_STATUS_IFR_MSC BIT(17) +#define PWR_STATUS_ETHSYS BIT(24) +#define PWR_STATUS_HIF0 BIT(25) +#define PWR_STATUS_HIF1 BIT(26) + +/* Infrasys configuration */ +#define INFRA_TOPDCM_CTRL 0x10 +#define INFRA_TOPAXI_PROT_EN 0x220 +#define INFRA_TOPAXI_PROT_STA1 0x228 + +#define DCM_TOP_EN BIT(0) + +enum scp_domain_type { + SCPSYS_MT7623, + SCPSYS_MT7629, +}; + +struct scp_domain; + +struct scp_domain_data { + struct scp_domain *scpd; + u32 sta_mask; + int ctl_offs; + u32 sram_pdn_bits; + u32 sram_pdn_ack_bits; + u32 bus_prot_mask; +}; + +struct scp_domain { + void __iomem *base; + void __iomem *infracfg; + enum scp_domain_type type; + struct scp_domain_data *data; +}; + +static struct scp_domain_data scp_domain_mt7623[] = { + [MT7623_POWER_DOMAIN_CONN] = { + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .bus_prot_mask = BIT(8) | BIT(2), + }, + [MT7623_POWER_DOMAIN_DISP] = { + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .bus_prot_mask = BIT(2), + }, + [MT7623_POWER_DOMAIN_MFG] = { + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT7623_POWER_DOMAIN_VDEC] = { + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT7623_POWER_DOMAIN_ISP] = { + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + }, + [MT7623_POWER_DOMAIN_BDP] = { + .sta_mask = PWR_STATUS_BDP, + .ctl_offs = SPM_BDP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + }, + [MT7623_POWER_DOMAIN_ETH] = { + .sta_mask = PWR_STATUS_ETH, + .ctl_offs = SPM_ETH_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT7623_POWER_DOMAIN_HIF] = { + .sta_mask = PWR_STATUS_HIF, + .ctl_offs = SPM_HIF_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT7623_POWER_DOMAIN_IFR_MSC] = { + .sta_mask = PWR_STATUS_IFR_MSC, + .ctl_offs = SPM_IFR_MSC_PWR_CON, + }, +}; + +static struct scp_domain_data scp_domain_mt7629[] = { + [MT7629_POWER_DOMAIN_ETHSYS] = { + .sta_mask = PWR_STATUS_ETHSYS, + .ctl_offs = SPM_ETHSYS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .bus_prot_mask = (BIT(3) | BIT(17)), + }, + [MT7629_POWER_DOMAIN_HIF0] = { + .sta_mask = PWR_STATUS_HIF0, + .ctl_offs = SPM_HIF0_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .bus_prot_mask = GENMASK(25, 24), + }, + [MT7629_POWER_DOMAIN_HIF1] = { + .sta_mask = PWR_STATUS_HIF1, + .ctl_offs = SPM_HIF1_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .bus_prot_mask = GENMASK(28, 26), + }, +}; + +/** + * This function enables the bus protection bits for disabled power + * domains so that the system does not hang when some unit accesses the + * bus while in power down. + */ +static int mtk_infracfg_set_bus_protection(void __iomem *infracfg, + u32 mask) +{ + u32 val; + + clrsetbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask, mask); + + return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val, + (val & mask) == mask, 100); +} + +static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg, + u32 mask) +{ + u32 val; + + clrbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask); + + return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val, + !(val & mask), 100); +} + +static int scpsys_domain_is_on(struct scp_domain_data *data) +{ + struct scp_domain *scpd = data->scpd; + u32 sta = readl(scpd->base + SPM_PWR_STATUS) & + data->sta_mask; + u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) & + data->sta_mask; + + /* + * A domain is on when both status bits are set. If only one is set + * return an error. This happens while powering up a domain + */ + if (sta && sta2) + return true; + if (!sta && !sta2) + return false; + + return -EINVAL; +} + +static int scpsys_power_on(struct power_domain *power_domain) +{ + struct scp_domain *scpd = dev_get_priv(power_domain->dev); + struct scp_domain_data *data = &scpd->data[power_domain->id]; + void __iomem *ctl_addr = scpd->base + data->ctl_offs; + u32 pdn_ack = data->sram_pdn_ack_bits; + u32 val; + int ret, tmp; + + writel(SPM_EN, scpd->base); + + val = readl(ctl_addr); + val |= PWR_ON_BIT; + writel(val, ctl_addr); + + val |= PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0, + 100); + if (ret < 0) + return ret; + + val &= ~PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ISO_BIT; + writel(val, ctl_addr); + + val |= PWR_RST_B_BIT; + writel(val, ctl_addr); + + val &= ~data->sram_pdn_bits; + writel(val, ctl_addr); + + ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100); + if (ret < 0) + return ret; + + if (data->bus_prot_mask) { + ret = mtk_infracfg_clear_bus_protection(scpd->infracfg, + data->bus_prot_mask); + if (ret) + return ret; + } + + return 0; +} + +static int scpsys_power_off(struct power_domain *power_domain) +{ + struct scp_domain *scpd = dev_get_priv(power_domain->dev); + struct scp_domain_data *data = &scpd->data[power_domain->id]; + void __iomem *ctl_addr = scpd->base + data->ctl_offs; + u32 pdn_ack = data->sram_pdn_ack_bits; + u32 val; + int ret, tmp; + + if (data->bus_prot_mask) { + ret = mtk_infracfg_set_bus_protection(scpd->infracfg, + data->bus_prot_mask); + if (ret) + return ret; + } + + val = readl(ctl_addr); + val |= data->sram_pdn_bits; + writel(val, ctl_addr); + + ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack, + 100); + if (ret < 0) + return ret; + + val |= PWR_ISO_BIT; + writel(val, ctl_addr); + + val &= ~PWR_RST_B_BIT; + writel(val, ctl_addr); + + val |= PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100); + if (ret < 0) + return ret; + + return 0; +} + +static int scpsys_power_request(struct power_domain *power_domain) +{ + struct scp_domain *scpd = dev_get_priv(power_domain->dev); + struct scp_domain_data *data; + + data = &scpd->data[power_domain->id]; + data->scpd = scpd; + + return 0; +} + +static int scpsys_power_free(struct power_domain *power_domain) +{ + return 0; +} + +static int mtk_power_domain_hook(struct udevice *dev) +{ + struct scp_domain *scpd = dev_get_priv(dev); + + scpd->type = (enum scp_domain_type)dev_get_driver_data(dev); + + switch (scpd->type) { + case SCPSYS_MT7623: + scpd->data = scp_domain_mt7623; + break; + case SCPSYS_MT7629: + scpd->data = scp_domain_mt7629; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mtk_power_domain_probe(struct udevice *dev) +{ + struct ofnode_phandle_args args; + struct scp_domain *scpd = dev_get_priv(dev); + struct regmap *regmap; + struct clk_bulk bulk; + int err; + + scpd->base = dev_read_addr_ptr(dev); + if (!scpd->base) + return -ENOENT; + + err = mtk_power_domain_hook(dev); + if (err) + return err; + + /* get corresponding syscon phandle */ + err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args); + if (err) + return err; + + regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + scpd->infracfg = regmap_get_range(regmap, 0); + if (!scpd->infracfg) + return -ENOENT; + + /* enable Infra DCM */ + setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN); + + err = clk_get_bulk(dev, &bulk); + if (err) + return err; + + return clk_enable_bulk(&bulk); +} + +static const struct udevice_id mtk_power_domain_ids[] = { + { + .compatible = "mediatek,mt7623-scpsys", + .data = SCPSYS_MT7623, + }, + { + .compatible = "mediatek,mt7629-scpsys", + .data = SCPSYS_MT7629, + }, + { /* sentinel */ } +}; + +struct power_domain_ops mtk_power_domain_ops = { + .free = scpsys_power_free, + .off = scpsys_power_off, + .on = scpsys_power_on, + .request = scpsys_power_request, +}; + +U_BOOT_DRIVER(mtk_power_domain) = { + .name = "mtk_power_domain", + .id = UCLASS_POWER_DOMAIN, + .ops = &mtk_power_domain_ops, + .probe = mtk_power_domain_probe, + .of_match = mtk_power_domain_ids, + .priv_auto_alloc_size = sizeof(struct scp_domain), +}; diff --git a/drivers/power/pmic/act8846.c b/drivers/power/pmic/act8846.c index b0c759c647c..186fa907e18 100644 --- a/drivers/power/pmic/act8846.c +++ b/drivers/power/pmic/act8846.c @@ -50,7 +50,7 @@ static int act8846_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/as3722.c b/drivers/power/pmic/as3722.c index 63df6133549..54adcbf50f5 100644 --- a/drivers/power/pmic/as3722.c +++ b/drivers/power/pmic/as3722.c @@ -45,14 +45,14 @@ static int as3722_read_id(struct udevice *dev, uint *idp, uint *revisionp) ret = pmic_reg_read(dev, AS3722_ASIC_ID1); if (ret < 0) { - pr_err("failed to read ID1 register: %d", ret); + pr_err("failed to read ID1 register: %d\n", ret); return ret; } *idp = ret; ret = pmic_reg_read(dev, AS3722_ASIC_ID2); if (ret < 0) { - pr_err("failed to read ID2 register: %d", ret); + pr_err("failed to read ID2 register: %d\n", ret); return ret; } *revisionp = ret; @@ -70,7 +70,7 @@ int as3722_sd_set_voltage(struct udevice *dev, unsigned int sd, u8 value) ret = pmic_reg_write(dev, AS3722_SD_VOLTAGE(sd), value); if (ret < 0) { - pr_err("failed to write SD%u voltage register: %d", sd, ret); + pr_err("failed to write SD%u voltage register: %d\n", sd, ret); return ret; } @@ -86,8 +86,8 @@ int as3722_ldo_set_voltage(struct udevice *dev, unsigned int ldo, u8 value) ret = pmic_reg_write(dev, AS3722_LDO_VOLTAGE(ldo), value); if (ret < 0) { - pr_err("failed to write LDO%u voltage register: %d", ldo, - ret); + pr_err("failed to write LDO%u voltage register: %d\n", ldo, + ret); return ret; } @@ -101,12 +101,12 @@ static int as3722_probe(struct udevice *dev) ret = as3722_read_id(dev, &id, &revision); if (ret < 0) { - pr_err("failed to read ID: %d", ret); + pr_err("failed to read ID: %d\n", ret); return ret; } if (id != AS3722_DEVICE_ID) { - pr_err("unknown device"); + pr_err("unknown device\n"); return -ENOENT; } diff --git a/drivers/power/pmic/as3722_gpio.c b/drivers/power/pmic/as3722_gpio.c index 36f4fbfa470..96943bc1ad5 100644 --- a/drivers/power/pmic/as3722_gpio.c +++ b/drivers/power/pmic/as3722_gpio.c @@ -25,7 +25,7 @@ int as3722_gpio_configure(struct udevice *pmic, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); if (err) { - pr_err("failed to configure GPIO#%u: %d", gpio, err); + pr_err("failed to configure GPIO#%u: %d\n", gpio, err); return err; } @@ -45,7 +45,7 @@ static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio, err = pmic_reg_read(pmic, AS3722_GPIO_SIGNAL_OUT); if (err < 0) { - pr_err("failed to read GPIO signal out register: %d", err); + pr_err("failed to read GPIO signal out register: %d\n", err); return err; } value = err; @@ -60,7 +60,7 @@ static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_SIGNAL_OUT, value); if (err) { - pr_err("failed to set GPIO#%u %s: %d", gpio, l, err); + pr_err("failed to set GPIO#%u %s: %d\n", gpio, l, err); return err; } @@ -83,13 +83,14 @@ int as3722_gpio_direction_output(struct udevice *dev, unsigned int gpio, err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); if (err) { - pr_err("failed to configure GPIO#%u as output: %d", gpio, err); + pr_err("failed to configure GPIO#%u as output: %d\n", gpio, + err); return err; } err = as3722_gpio_set_value(pmic, gpio, value); if (err < 0) { - pr_err("failed to set GPIO#%u high: %d", gpio, err); + pr_err("failed to set GPIO#%u high: %d\n", gpio, err); return err; } diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c index 61fa76a5619..80efc0265d9 100644 --- a/drivers/power/pmic/i2c_pmic_emul.c +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -104,7 +104,7 @@ static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg, static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul) { struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); - struct udevice *pmic_dev = dev_get_parent(emul); + struct udevice *pmic_dev = i2c_emul_get_device(emul); struct uc_pmic_priv *priv = dev_get_uclass_priv(pmic_dev); const u8 *reg_defaults; diff --git a/drivers/power/pmic/lp873x.c b/drivers/power/pmic/lp873x.c index 432ad4cecf6..4ae4043b943 100644 --- a/drivers/power/pmic/lp873x.c +++ b/drivers/power/pmic/lp873x.c @@ -24,7 +24,7 @@ static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -34,7 +34,7 @@ static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -48,7 +48,7 @@ static int lp873x_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/lp87565.c b/drivers/power/pmic/lp87565.c index 450dbb8a780..3e5fc608d28 100644 --- a/drivers/power/pmic/lp87565.c +++ b/drivers/power/pmic/lp87565.c @@ -26,7 +26,7 @@ static int lp87565_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -37,7 +37,7 @@ static int lp87565_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return ret; } @@ -49,7 +49,7 @@ static int lp87565_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/max77686.c b/drivers/power/pmic/max77686.c index 834713af286..8e3a8cf870b 100644 --- a/drivers/power/pmic/max77686.c +++ b/drivers/power/pmic/max77686.c @@ -28,7 +28,7 @@ static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -38,7 +38,7 @@ static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff, static int max77686_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -52,8 +52,8 @@ static int max77686_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "voltage-regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, - dev->name); + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/max8997.c b/drivers/power/pmic/max8997.c index 0dcdbad5832..dbae155fb34 100644 --- a/drivers/power/pmic/max8997.c +++ b/drivers/power/pmic/max8997.c @@ -23,7 +23,7 @@ static int max8997_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -34,7 +34,7 @@ static int max8997_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return ret; } diff --git a/drivers/power/pmic/max8998.c b/drivers/power/pmic/max8998.c index f571add6e6a..f58d9f2d74c 100644 --- a/drivers/power/pmic/max8998.c +++ b/drivers/power/pmic/max8998.c @@ -23,7 +23,7 @@ static int max8998_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -34,7 +34,7 @@ static int max8998_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return ret; } diff --git a/drivers/power/pmic/mc34708.c b/drivers/power/pmic/mc34708.c index 2b2fc72a472..66253a4a43b 100644 --- a/drivers/power/pmic/mc34708.c +++ b/drivers/power/pmic/mc34708.c @@ -38,7 +38,7 @@ static int mc34708_write(struct udevice *dev, uint reg, const u8 *buff, ret = dm_i2c_write(dev, reg, buf, len); if (ret) - printf("write error to device: %p register: %#x!", dev, reg); + printf("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -53,7 +53,7 @@ static int mc34708_read(struct udevice *dev, uint reg, u8 *buff, int len) ret = dm_i2c_read(dev, reg, buf, len); if (ret) - printf("read error from device: %p register: %#x!", dev, reg); + printf("read error from device: %p register: %#x!\n", dev, reg); buff[0] = buf[2]; buff[1] = buf[1]; diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c index 250a5d34bbf..36be119b6cf 100644 --- a/drivers/power/pmic/palmas.c +++ b/drivers/power/pmic/palmas.c @@ -24,7 +24,7 @@ static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -34,7 +34,7 @@ static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff, static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -60,14 +60,14 @@ static int palmas_bind(struct udevice *dev) } if (!ofnode_valid(pmic_node)) { - debug("%s: %s pmic subnode not found!", __func__, dev->name); + debug("%s: %s pmic subnode not found!\n", __func__, dev->name); return -ENXIO; } regulators_node = ofnode_find_subnode(pmic_node, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s reg subnode not found!", __func__, dev->name); + debug("%s: %s reg subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/pfuze100.c b/drivers/power/pmic/pfuze100.c index 8a5a8996b43..6cf5f35f0f2 100644 --- a/drivers/power/pmic/pfuze100.c +++ b/drivers/power/pmic/pfuze100.c @@ -31,7 +31,7 @@ static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -41,7 +41,7 @@ static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff, static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -55,7 +55,7 @@ static int pfuze100_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index c60dfff5bfd..25c339ab12c 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -29,7 +29,7 @@ static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) { - debug("write error to device: %p register: %#x!", dev, reg); + debug("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -42,7 +42,7 @@ static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) { - debug("read error from device: %p register: %#x!", dev, reg); + debug("read error from device: %p register: %#x!\n", dev, reg); return ret; } @@ -57,7 +57,7 @@ static int rk8xx_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/rn5t567.c b/drivers/power/pmic/rn5t567.c index c3be3fed4a0..f238396d368 100644 --- a/drivers/power/pmic/rn5t567.c +++ b/drivers/power/pmic/rn5t567.c @@ -24,7 +24,7 @@ static int rn5t567_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) { - debug("write error to device: %p register: %#x!", dev, reg); + debug("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -37,7 +37,7 @@ static int rn5t567_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) { - debug("read error from device: %p register: %#x!", dev, reg); + debug("read error from device: %p register: %#x!\n", dev, reg); return ret; } diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c index e45d4bc6e16..f2aab6c4570 100644 --- a/drivers/power/pmic/s2mps11.c +++ b/drivers/power/pmic/s2mps11.c @@ -30,7 +30,7 @@ static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, ret = dm_i2c_write(dev, reg, buff, len); if (ret) - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return ret; } @@ -41,7 +41,7 @@ static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return ret; } @@ -53,8 +53,8 @@ static int s2mps11_probe(struct udevice *dev) regulators_node = dev_read_subnode(dev, "voltage-regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, - dev->name); + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/s5m8767.c b/drivers/power/pmic/s5m8767.c index 54e44ce8645..b5ddd4930e3 100644 --- a/drivers/power/pmic/s5m8767.c +++ b/drivers/power/pmic/s5m8767.c @@ -27,7 +27,7 @@ static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -37,7 +37,7 @@ static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -56,7 +56,7 @@ static int s5m8767_bind(struct udevice *dev) node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/power/pmic/sandbox.c b/drivers/power/pmic/sandbox.c index 64e2f276dab..d7870915de8 100644 --- a/drivers/power/pmic/sandbox.c +++ b/drivers/power/pmic/sandbox.c @@ -28,7 +28,7 @@ static int sandbox_pmic_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -39,7 +39,7 @@ static int sandbox_pmic_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c index 82351b66137..47af0123328 100644 --- a/drivers/power/pmic/stpmu1.c +++ b/drivers/power/pmic/stpmu1.c @@ -61,7 +61,7 @@ static int stpmu1_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - dev_dbg(dev, "regulators subnode not found!"); + dev_dbg(dev, "regulators subnode not found!\n"); return -ENXIO; } dev_dbg(dev, "found regulators subnode\n"); diff --git a/drivers/power/pmic/tps65090.c b/drivers/power/pmic/tps65090.c index 1d3bf00b568..5b1d19f3e0b 100644 --- a/drivers/power/pmic/tps65090.c +++ b/drivers/power/pmic/tps65090.c @@ -26,7 +26,7 @@ static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -39,8 +39,8 @@ static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len) ret = dm_i2c_read(dev, reg, buff, len); if (ret) { - pr_err("read error %d from device: %p register: %#x!", ret, dev, - reg); + pr_err("read error %d from device: %p register: %#x!\n", ret, + dev, reg); return -EIO; } @@ -54,7 +54,7 @@ static int tps65090_bind(struct udevice *dev) regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { - debug("%s: %s regulators subnode not found!", __func__, + debug("%s: %s regulators subnode not found!\n", __func__, dev->name); return -ENXIO; } diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index e14c1cf5922..976ec66df7a 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o +obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ diff --git a/drivers/ram/mediatek/Makefile b/drivers/ram/mediatek/Makefile new file mode 100644 index 00000000000..95507b593c4 --- /dev/null +++ b/drivers/ram/mediatek/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (c) 2018 MediaTek Inc. +# +# SPDX-License-Identifier: GPL-2.0 +# + +obj-$(CONFIG_TARGET_MT7629) = ddr3-mt7629.o diff --git a/drivers/ram/mediatek/ddr3-mt7629.c b/drivers/ram/mediatek/ddr3-mt7629.c new file mode 100644 index 00000000000..b413f499d03 --- /dev/null +++ b/drivers/ram/mediatek/ddr3-mt7629.c @@ -0,0 +1,766 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek DDR3 driver for MT7629 SoC + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Wu Zou <wu.zou@mediatek.com> + * Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> + +/* EMI */ +#define EMI_CONA 0x000 +#define EMI_CONF 0x028 +#define EMI_CONM 0x060 + +/* DDR PHY */ +#define DDRPHY_PLL1 0x0000 +#define DDRPHY_PLL2 0x0004 +#define DDRPHY_PLL3 0x0008 +#define DDRPHY_PLL4 0x000c +#define DDRPHY_PLL5 0x0010 +#define DDRPHY_PLL7 0x0018 +#define DDRPHY_B0_DLL_ARPI0 0x0080 +#define DDRPHY_B0_DLL_ARPI1 0x0084 +#define DDRPHY_B0_DLL_ARPI2 0x0088 +#define DDRPHY_B0_DLL_ARPI3 0x008c +#define DDRPHY_B0_DLL_ARPI4 0x0090 +#define DDRPHY_B0_DLL_ARPI5 0x0094 +#define DDRPHY_B0_DQ2 0x00a0 +#define DDRPHY_B0_DQ3 0x00a4 +#define DDRPHY_B0_DQ4 0x00a8 +#define DDRPHY_B0_DQ5 0x00ac +#define DDRPHY_B0_DQ6 0x00b0 +#define DDRPHY_B0_DQ7 0x00b4 +#define DDRPHY_B0_DQ8 0x00b8 +#define DDRPHY_B1_DLL_ARPI0 0x0100 +#define DDRPHY_B1_DLL_ARPI1 0x0104 +#define DDRPHY_B1_DLL_ARPI2 0x0108 +#define DDRPHY_B1_DLL_ARPI3 0x010c +#define DDRPHY_B1_DLL_ARPI4 0x0110 +#define DDRPHY_B1_DLL_ARPI5 0x0114 +#define DDRPHY_B1_DQ2 0x0120 +#define DDRPHY_B1_DQ3 0x0124 +#define DDRPHY_B1_DQ4 0x0128 +#define DDRPHY_B1_DQ5 0x012c +#define DDRPHY_B1_DQ6 0x0130 +#define DDRPHY_B1_DQ7 0x0134 +#define DDRPHY_B1_DQ8 0x0138 +#define DDRPHY_CA_DLL_ARPI0 0x0180 +#define DDRPHY_CA_DLL_ARPI1 0x0184 +#define DDRPHY_CA_DLL_ARPI2 0x0188 +#define DDRPHY_CA_DLL_ARPI3 0x018c +#define DDRPHY_CA_DLL_ARPI4 0x0190 +#define DDRPHY_CA_DLL_ARPI5 0x0194 +#define DDRPHY_CA_CMD2 0x01a0 +#define DDRPHY_CA_CMD3 0x01a4 +#define DDRPHY_CA_CMD5 0x01ac +#define DDRPHY_CA_CMD6 0x01b0 +#define DDRPHY_CA_CMD7 0x01b4 +#define DDRPHY_CA_CMD8 0x01b8 +#define DDRPHY_MISC_VREF_CTRL 0x0264 +#define DDRPHY_MISC_IMP_CTRL0 0x0268 +#define DDRPHY_MISC_IMP_CTRL1 0x026c +#define DDRPHY_MISC_SHU_OPT 0x0270 +#define DDRPHY_MISC_SPM_CTRL0 0x0274 +#define DDRPHY_MISC_SPM_CTRL1 0x0278 +#define DDRPHY_MISC_SPM_CTRL2 0x027c +#define DDRPHY_MISC_CG_CTRL0 0x0284 +#define DDRPHY_MISC_CG_CTRL1 0x0288 +#define DDRPHY_MISC_CG_CTRL2 0x028c +#define DDRPHY_MISC_CG_CTRL4 0x0294 +#define DDRPHY_MISC_CTRL0 0x029c +#define DDRPHY_MISC_CTRL1 0x02a0 +#define DDRPHY_MISC_CTRL3 0x02a8 +#define DDRPHY_MISC_RXDVS1 0x05e4 +#define DDRPHY_SHU1_B0_DQ4 0x0c10 +#define DDRPHY_SHU1_B0_DQ5 0x0c14 +#define DDRPHY_SHU1_B0_DQ6 0x0c18 +#define DDRPHY_SHU1_B0_DQ7 0x0c1c +#define DDRPHY_SHU1_B1_DQ4 0x0c90 +#define DDRPHY_SHU1_B1_DQ5 0x0c94 +#define DDRPHY_SHU1_B1_DQ6 0x0c98 +#define DDRPHY_SHU1_B1_DQ7 0x0c9c +#define DDRPHY_SHU1_CA_CMD2 0x0d08 +#define DDRPHY_SHU1_CA_CMD4 0x0d10 +#define DDRPHY_SHU1_CA_CMD5 0x0d14 +#define DDRPHY_SHU1_CA_CMD6 0x0d18 +#define DDRPHY_SHU1_CA_CMD7 0x0d1c +#define DDRPHY_SHU1_PLL0 0x0d80 +#define DDRPHY_SHU1_PLL1 0x0d84 +#define DDRPHY_SHU1_PLL4 0x0d90 +#define DDRPHY_SHU1_PLL5 0x0d94 +#define DDRPHY_SHU1_PLL6 0x0d98 +#define DDRPHY_SHU1_PLL7 0x0d9C +#define DDRPHY_SHU1_PLL8 0x0da0 +#define DDRPHY_SHU1_PLL9 0x0da4 +#define DDRPHY_SHU1_PLL10 0x0da8 +#define DDRPHY_SHU1_PLL11 0x0dac +#define DDRPHY_SHU1_R0_B0_DQ2 0x0e08 +#define DDRPHY_SHU1_R0_B0_DQ3 0x0e0c +#define DDRPHY_SHU1_R0_B0_DQ4 0x0e10 +#define DDRPHY_SHU1_R0_B0_DQ5 0x0e14 +#define DDRPHY_SHU1_R0_B0_DQ6 0x0e18 +#define DDRPHY_SHU1_R0_B0_DQ7 0x0e1c +#define DDRPHY_SHU1_R0_B1_DQ2 0x0e58 +#define DDRPHY_SHU1_R0_B1_DQ3 0x0e5c +#define DDRPHY_SHU1_R0_B1_DQ4 0x0e60 +#define DDRPHY_SHU1_R0_B1_DQ5 0x0e64 +#define DDRPHY_SHU1_R0_B1_DQ6 0x0e68 +#define DDRPHY_SHU1_R0_B1_DQ7 0x0e6c +#define DDRPHY_SHU1_R0_CA_CMD9 0x0ec4 +#define DDRPHY_SHU1_R1_B0_DQ2 0x0f08 +#define DDRPHY_SHU1_R1_B0_DQ3 0x0f0c +#define DDRPHY_SHU1_R1_B0_DQ4 0x0f10 +#define DDRPHY_SHU1_R1_B0_DQ5 0x0f14 +#define DDRPHY_SHU1_R1_B0_DQ6 0x0f18 +#define DDRPHY_SHU1_R1_B0_DQ7 0x0f1c +#define DDRPHY_SHU1_R1_B1_DQ2 0x0f58 +#define DDRPHY_SHU1_R1_B1_DQ3 0x0f5c +#define DDRPHY_SHU1_R1_B1_DQ4 0x0f60 +#define DDRPHY_SHU1_R1_B1_DQ5 0x0f64 +#define DDRPHY_SHU1_R1_B1_DQ6 0x0f68 +#define DDRPHY_SHU1_R1_B1_DQ7 0x0f6c +#define DDRPHY_SHU1_R1_CA_CMD9 0x0fc4 + +/* DRAMC */ +#define DRAMC_DDRCONF0 0x0000 +#define DRAMC_DRAMCTRL 0x0004 +#define DRAMC_MISCTL0 0x0008 +#define DRAMC_PERFCTL0 0x000c +#define DRAMC_ARBCTL 0x0010 +#define DRAMC_RSTMASK 0x001c +#define DRAMC_PADCTRL 0x0020 +#define DRAMC_CKECTRL 0x0024 +#define DRAMC_RKCFG 0x0034 +#define DRAMC_DRAMC_PD_CTRL 0x0038 +#define DRAMC_CLKAR 0x003c +#define DRAMC_CLKCTRL 0x0040 +#define DRAMC_SREFCTRL 0x0048 +#define DRAMC_REFCTRL0 0x004c +#define DRAMC_REFCTRL1 0x0050 +#define DRAMC_REFRATRE_FILTER 0x0054 +#define DRAMC_ZQCS 0x0058 +#define DRAMC_MRS 0x005c +#define DRAMC_SPCMD 0x0060 +#define DRAMC_SPCMDCTRL 0x0064 +#define DRAMC_HW_MRR_FUN 0x0074 +#define DRAMC_TEST2_1 0x0094 +#define DRAMC_TEST2_2 0x0098 +#define DRAMC_TEST2_3 0x009c +#define DRAMC_TEST2_4 0x00a0 +#define DRAMC_CATRAINING1 0x00b0 +#define DRAMC_DUMMY_RD 0x00d0 +#define DRAMC_SHUCTRL 0x00d4 +#define DRAMC_SHUCTRL2 0x00dc +#define DRAMC_STBCAL 0x0200 +#define DRAMC_STBCAL1 0x0204 +#define DRAMC_EYESCAN 0x020c +#define DRAMC_DVFSDLL 0x0210 +#define DRAMC_SHU_ACTIM0 0x0800 +#define DRAMC_SHU_ACTIM1 0x0804 +#define DRAMC_SHU_ACTIM2 0x0808 +#define DRAMC_SHU_ACTIM3 0x080c +#define DRAMC_SHU_ACTIM4 0x0810 +#define DRAMC_SHU_ACTIM5 0x0814 +#define DRAMC_SHU_ACTIM_XRT 0x081c +#define DRAMC_SHU_AC_TIME_05T 0x0820 +#define DRAMC_SHU_CONF0 0x0840 +#define DRAMC_SHU_CONF1 0x0844 +#define DRAMC_SHU_CONF2 0x0848 +#define DRAMC_SHU_CONF3 0x084c +#define DRAMC_SHU_RANKCTL 0x0858 +#define DRAMC_SHU_CKECTRL 0x085c +#define DRAMC_SHU_ODTCTRL 0x0860 +#define DRAMC_SHU_PIPE 0x0878 +#define DRAMC_SHU_SELPH_CA1 0x0880 +#define DRAMC_SHU_SELPH_CA2 0x0884 +#define DRAMC_SHU_SELPH_CA3 0x0888 +#define DRAMC_SHU_SELPH_CA4 0x088c +#define DRAMC_SHU_SELPH_CA5 0x0890 +#define DRAMC_SHU_SELPH_CA6 0x0894 +#define DRAMC_SHU_SELPH_CA7 0x0898 +#define DRAMC_SHU_SELPH_CA8 0x089c +#define DRAMC_SHU_SELPH_DQS0 0x08a0 +#define DRAMC_SHU_SELPH_DQS1 0x08a4 +#define DRAMC_SHU1_DRVING1 0x08a8 +#define DRAMC_SHU1_DRVING2 0x08ac +#define DRAMC_SHU1_WODT 0x08c0 +#define DRAMC_SHU_SCINTV 0x08c8 +#define DRAMC_SHURK0_DQSCTL 0x0a00 +#define DRAMC_SHURK0_DQSIEN 0x0a04 +#define DRAMC_SHURK0_SELPH_ODTEN0 0x0a1c +#define DRAMC_SHURK0_SELPH_ODTEN1 0x0a20 +#define DRAMC_SHURK0_SELPH_DQSG0 0x0a24 +#define DRAMC_SHURK0_SELPH_DQSG1 0x0a28 +#define DRAMC_SHURK0_SELPH_DQ0 0x0a2c +#define DRAMC_SHURK0_SELPH_DQ1 0x0a30 +#define DRAMC_SHURK0_SELPH_DQ2 0x0a34 +#define DRAMC_SHURK0_SELPH_DQ3 0x0a38 +#define DRAMC_SHURK1_DQSCTL 0x0b00 +#define DRAMC_SHURK1_SELPH_ODTEN0 0x0b1c +#define DRAMC_SHURK1_SELPH_ODTEN1 0x0b20 +#define DRAMC_SHURK1_SELPH_DQSG0 0x0b24 +#define DRAMC_SHURK1_SELPH_DQSG1 0x0b28 +#define DRAMC_SHURK1_SELPH_DQ0 0x0b2c +#define DRAMC_SHURK1_SELPH_DQ1 0x0b30 +#define DRAMC_SHURK1_SELPH_DQ2 0x0b34 +#define DRAMC_SHURK1_SELPH_DQ3 0x0b38 +#define DRAMC_SHURK2_SELPH_ODTEN0 0x0c1c +#define DRAMC_SHURK2_SELPH_ODTEN1 0x0c20 +#define DRAMC_SHU_DQSG_RETRY 0x0c54 + +#define EMI_COL_ADDR_MASK GENMASK(13, 12) +#define EMI_COL_ADDR_SHIFT 12 +#define WALKING_PATTERN 0x12345678 +#define WALKING_STEP 0x4000000 + +struct mtk_ddr3_priv { + fdt_addr_t emi; + fdt_addr_t ddrphy; + fdt_addr_t dramc_ao; + struct clk phy; + struct clk phy_mux; + struct clk mem; + struct clk mem_mux; +}; + +#ifdef CONFIG_SPL_BUILD +static int mtk_ddr3_rank_size_detect(struct udevice *dev) +{ + struct mtk_ddr3_priv *priv = dev_get_priv(dev); + int step; + u32 start, test; + + /* To detect size, we have to make sure it's single rank + * and it has maximum addressing region + */ + + writel(WALKING_PATTERN, CONFIG_SYS_SDRAM_BASE); + + if (readl(CONFIG_SYS_SDRAM_BASE) != WALKING_PATTERN) + return -EINVAL; + + for (step = 0; step < 5; step++) { + writel(~WALKING_PATTERN, CONFIG_SYS_SDRAM_BASE + + (WALKING_STEP << step)); + + start = readl(CONFIG_SYS_SDRAM_BASE); + test = readl(CONFIG_SYS_SDRAM_BASE + (WALKING_STEP << step)); + if ((test != ~WALKING_PATTERN) || test == start) + break; + } + + step = step ? step - 1 : 3; + clrsetbits_le32(priv->emi + EMI_CONA, EMI_COL_ADDR_MASK, + step << EMI_COL_ADDR_SHIFT); + + return 0; +} + +static int mtk_ddr3_init(struct udevice *dev) +{ + struct mtk_ddr3_priv *priv = dev_get_priv(dev); + int ret; + + ret = clk_set_parent(&priv->phy, &priv->phy_mux); + if (ret) + return ret; + + /* EMI Setting */ + writel(0x00003010, priv->emi + EMI_CONA); + writel(0x00000000, priv->emi + EMI_CONF); + writel(0x000006b8, priv->emi + EMI_CONM); + /* DQS */ + writel(0x20c00, priv->dramc_ao + DRAMC_SHU1_DRVING1); + /* Clock */ + writel(0x8320c83, priv->dramc_ao + DRAMC_SHU1_DRVING2); + + /* DDRPHY setting */ + writel(0x2201, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0x3000000c, priv->dramc_ao + DRAMC_CLKCTRL); + writel(0xe08, priv->ddrphy + DDRPHY_CA_CMD5); + writel(0x60e, priv->ddrphy + DDRPHY_SHU1_CA_CMD5); + writel(0x0, priv->ddrphy + DDRPHY_MISC_SPM_CTRL1); + writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_SPM_CTRL0); + writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_SPM_CTRL2); + writel(0x6003bf, priv->ddrphy + DDRPHY_MISC_CG_CTRL2); + writel(0x13300000, priv->ddrphy + DDRPHY_MISC_CG_CTRL4); + + writel(0x1, priv->ddrphy + DDRPHY_SHU1_CA_CMD7); + writel(0x21, priv->ddrphy + DDRPHY_SHU1_B0_DQ7); + writel(0x1, priv->ddrphy + DDRPHY_SHU1_B1_DQ7); + writel(0xfff0, priv->ddrphy + DDRPHY_CA_CMD2); + writel(0x0, priv->ddrphy + DDRPHY_B0_DQ2); + writel(0x0, priv->ddrphy + DDRPHY_B1_DQ2); + writel(0x7, priv->ddrphy + DDRPHY_MISC_RXDVS1); + writel(0x10, priv->ddrphy + DDRPHY_PLL3); + writel(0x8e8e0000, priv->ddrphy + DDRPHY_MISC_VREF_CTRL); + writel(0x2e0040, priv->ddrphy + DDRPHY_MISC_IMP_CTRL0); + writel(0x50060e, priv->ddrphy + DDRPHY_SHU1_B0_DQ5); + writel(0x50060e, priv->ddrphy + DDRPHY_SHU1_B1_DQ5); + udelay(1); + + writel(0x10, priv->ddrphy + DDRPHY_B0_DQ3); + writel(0x10, priv->ddrphy + DDRPHY_B1_DQ3); + writel(0x3f600, priv->ddrphy + DDRPHY_MISC_CG_CTRL1); + writel(0x1010, priv->ddrphy + DDRPHY_B0_DQ4); + writel(0x1110e0e, priv->ddrphy + DDRPHY_B0_DQ5); + writel(0x10c10d0, priv->ddrphy + DDRPHY_B0_DQ6); + writel(0x3110e0e, priv->ddrphy + DDRPHY_B0_DQ5); + writel(0x1010, priv->ddrphy + DDRPHY_B1_DQ4); + writel(0x1110e0e, priv->ddrphy + DDRPHY_B1_DQ5); + writel(0x10c10d0, priv->ddrphy + DDRPHY_B1_DQ6); + writel(0x3110e0e, priv->ddrphy + DDRPHY_B1_DQ5); + writel(0x7fffffc, priv->ddrphy + DDRPHY_CA_CMD3); + writel(0xc0010, priv->ddrphy + DDRPHY_CA_CMD6); + writel(0x101, priv->ddrphy + DDRPHY_SHU1_CA_CMD2); + writel(0x41e, priv->ddrphy + DDRPHY_B0_DQ3); + writel(0x41e, priv->ddrphy + DDRPHY_B1_DQ3); + writel(0x180101, priv->ddrphy + DDRPHY_CA_CMD8); + writel(0x0, priv->ddrphy + DDRPHY_MISC_IMP_CTRL1); + writel(0x11400000, priv->ddrphy + DDRPHY_MISC_CG_CTRL4); + writel(0xfff0f0f0, priv->ddrphy + DDRPHY_MISC_SHU_OPT); + writel(0x1f, priv->ddrphy + DDRPHY_MISC_CG_CTRL0); + + writel(0x0, priv->ddrphy + DDRPHY_SHU1_CA_CMD6); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_B0_DQ6); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_B1_DQ6); + writel(0x40000, priv->ddrphy + DDRPHY_PLL4); + writel(0x0, priv->ddrphy + DDRPHY_PLL1); + writel(0x0, priv->ddrphy + DDRPHY_PLL2); + writel(0x666008, priv->ddrphy + DDRPHY_CA_DLL_ARPI5); + writel(0x80666008, priv->ddrphy + DDRPHY_B0_DLL_ARPI5); + writel(0x80666008, priv->ddrphy + DDRPHY_B1_DLL_ARPI5); + writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI0); + writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI0); + writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI0); + writel(0x400, priv->ddrphy + DDRPHY_CA_DLL_ARPI2); + writel(0x20400, priv->ddrphy + DDRPHY_B0_DLL_ARPI2); + writel(0x20400, priv->ddrphy + DDRPHY_B1_DLL_ARPI2); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_PLL9); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_PLL11); + writel(0xf7f, priv->ddrphy + DDRPHY_SHU1_PLL0); + writel(0x40000, priv->ddrphy + DDRPHY_SHU1_PLL8); + writel(0x40000, priv->ddrphy + DDRPHY_SHU1_PLL10); + writel(0xe57800fe, priv->ddrphy + DDRPHY_SHU1_PLL4); + writel(0xe57800fe, priv->ddrphy + DDRPHY_SHU1_PLL6); + + writel(0xB5000000, priv->ddrphy + DDRPHY_SHU1_PLL5); + writel(0xB5000000, priv->ddrphy + DDRPHY_SHU1_PLL7); + + writel(0x14d0002, priv->ddrphy + DDRPHY_PLL5); + writel(0x14d0002, priv->ddrphy + DDRPHY_PLL7); + writel(0x80040000, priv->ddrphy + DDRPHY_SHU1_PLL8); + writel(0x80040000, priv->ddrphy + DDRPHY_SHU1_PLL10); + writel(0xf, priv->ddrphy + DDRPHY_SHU1_PLL1); + writel(0x4, priv->ddrphy + DDRPHY_CA_DLL_ARPI0); + writel(0x1, priv->ddrphy + DDRPHY_B0_DLL_ARPI0); + writel(0x1, priv->ddrphy + DDRPHY_B1_DLL_ARPI0); + writel(0x698600, priv->ddrphy + DDRPHY_CA_DLL_ARPI5); + writel(0xc0778600, priv->ddrphy + DDRPHY_B0_DLL_ARPI5); + writel(0xc0778600, priv->ddrphy + DDRPHY_B1_DLL_ARPI5); + writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI4); + writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI4); + writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI4); + writel(0x2ba800, priv->ddrphy + DDRPHY_CA_DLL_ARPI1); + writel(0x2ae806, priv->ddrphy + DDRPHY_B0_DLL_ARPI1); + writel(0xae806, priv->ddrphy + DDRPHY_B1_DLL_ARPI1); + writel(0xba000, priv->ddrphy + DDRPHY_CA_DLL_ARPI3); + writel(0x2e800, priv->ddrphy + DDRPHY_B0_DLL_ARPI3); + writel(0x2e800, priv->ddrphy + DDRPHY_B1_DLL_ARPI3); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_CA_CMD4); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_B0_DQ4); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_B1_DQ4); + writel(0x4, priv->ddrphy + DDRPHY_CA_DLL_ARPI0); + writel(0x1, priv->ddrphy + DDRPHY_B0_DLL_ARPI0); + writel(0x1, priv->ddrphy + DDRPHY_B1_DLL_ARPI0); + writel(0x32cf0000, priv->ddrphy + DDRPHY_SHU1_CA_CMD6); + writel(0x32cd0000, priv->ddrphy + DDRPHY_SHU1_B0_DQ6); + writel(0x32cd0000, priv->ddrphy + DDRPHY_SHU1_B1_DQ6); + writel(0x80010000, priv->ddrphy + DDRPHY_PLL1); + writel(0x80000000, priv->ddrphy + DDRPHY_PLL2); + udelay(100); + + writel(0xc, priv->ddrphy + DDRPHY_CA_DLL_ARPI0); + writel(0x9, priv->ddrphy + DDRPHY_B0_DLL_ARPI0); + writel(0x9, priv->ddrphy + DDRPHY_B1_DLL_ARPI0); + writel(0xd0000, priv->ddrphy + DDRPHY_PLL4); + udelay(1); + + writel(0x82, priv->ddrphy + DDRPHY_MISC_CTRL1); + writel(0x2, priv->dramc_ao + DRAMC_DDRCONF0); + writel(0x3acf0000, priv->ddrphy + DDRPHY_SHU1_CA_CMD6); + writel(0x3acd0000, priv->ddrphy + DDRPHY_SHU1_B0_DQ6); + writel(0x3acd0000, priv->ddrphy + DDRPHY_SHU1_B1_DQ6); + udelay(1); + + writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI2); + writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI2); + writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI2); + writel(0x80, priv->ddrphy + DDRPHY_MISC_CTRL1); + writel(0x0, priv->dramc_ao + DRAMC_DDRCONF0); + writel(0x80000000, priv->ddrphy + DDRPHY_PLL1); + udelay(1); + + writel(0x698e00, priv->ddrphy + DDRPHY_CA_DLL_ARPI5); + udelay(1); + + writel(0xc0778e00, priv->ddrphy + DDRPHY_B0_DLL_ARPI5); + udelay(1); + + writel(0xc0778e00, priv->ddrphy + DDRPHY_B1_DLL_ARPI5); + udelay(1); + + ret = clk_set_parent(&priv->mem, &priv->mem_mux); + if (ret) + return ret; + + /* DDR PHY PLL setting */ + writel(0x51e, priv->ddrphy + DDRPHY_B0_DQ3); + writel(0x51e, priv->ddrphy + DDRPHY_B1_DQ3); + writel(0x8100008c, priv->ddrphy + DDRPHY_MISC_CTRL1); + writel(0x80101, priv->ddrphy + DDRPHY_CA_CMD8); + writel(0x100, priv->ddrphy + DDRPHY_CA_CMD7); + writel(0x0, priv->ddrphy + DDRPHY_CA_CMD7); + writel(0x0, priv->ddrphy + DDRPHY_B0_DQ7); + writel(0x0, priv->ddrphy + DDRPHY_B1_DQ7); + writel(0x51e, priv->ddrphy + DDRPHY_B0_DQ3); + writel(0xff051e, priv->ddrphy + DDRPHY_B1_DQ3); + writel(0x0, priv->ddrphy + DDRPHY_B0_DQ2); + writel(0x1ff, priv->ddrphy + DDRPHY_B1_DQ2); + + /* Update initial setting */ + writel(0x5fc, priv->ddrphy + DDRPHY_B0_DQ3); + writel(0xff05fc, priv->ddrphy + DDRPHY_B1_DQ3); + writel(0x10c12d9, priv->ddrphy + DDRPHY_B0_DQ6); + writel(0x10c12d9, priv->ddrphy + DDRPHY_B1_DQ6); + writel(0xc0259, priv->ddrphy + DDRPHY_CA_CMD6); + writel(0x4000, priv->ddrphy + DDRPHY_B0_DQ2); + writel(0x41ff, priv->ddrphy + DDRPHY_B1_DQ2); + writel(0x0, priv->ddrphy + DDRPHY_B0_DQ8); + writel(0x100, priv->ddrphy + DDRPHY_B1_DQ8); + writel(0x3110e0e, priv->ddrphy + DDRPHY_B0_DQ5); + writel(0x3110e0e, priv->ddrphy + DDRPHY_B1_DQ5); + writel(0x51060e, priv->ddrphy + DDRPHY_SHU1_B0_DQ5); + writel(0x51060e, priv->ddrphy + DDRPHY_SHU1_B1_DQ5); + writel(0x39eff6, priv->dramc_ao + DRAMC_SHU_SCINTV); + writel(0x204ffff, priv->dramc_ao + DRAMC_CLKAR); + writel(0x31b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0x0, priv->dramc_ao + DRAMC_PERFCTL0); + writel(0x80000, priv->dramc_ao + DRAMC_PERFCTL0); + + /* Dramc setting PC3 */ + writel(0x65714001, priv->dramc_ao + DRAMC_REFCTRL0); + + writel(0x11351131, priv->ddrphy + DDRPHY_MISC_CTRL3); + writel(0x200600, priv->dramc_ao + DRAMC_SHU_DQSG_RETRY); + writel(0x101d007, priv->dramc_ao + DRAMC_SHUCTRL2); + writel(0xe090601, priv->dramc_ao + DRAMC_DVFSDLL); + writel(0x20003000, priv->dramc_ao + DRAMC_DDRCONF0); + writel(0x3900020f, priv->ddrphy + DDRPHY_MISC_CTRL0); + writel(0xa20810bf, priv->dramc_ao + DRAMC_SHU_CONF0); + writel(0x30050, priv->dramc_ao + DRAMC_SHU_ODTCTRL); + writel(0x25712000, priv->dramc_ao + DRAMC_REFCTRL0); + writel(0xb0100000, priv->dramc_ao + DRAMC_STBCAL); + writel(0x8000000, priv->dramc_ao + DRAMC_SREFCTRL); + writel(0xc0000000, priv->dramc_ao + DRAMC_SHU_PIPE); + writel(0x731004, priv->dramc_ao + DRAMC_RKCFG); + writel(0x8007320f, priv->dramc_ao + DRAMC_SHU_CONF2); + writel(0x2a7c0, priv->dramc_ao + DRAMC_SHU_SCINTV); + writel(0xc110, priv->dramc_ao + DRAMC_SHUCTRL); + writel(0x30000700, priv->dramc_ao + DRAMC_REFCTRL1); + writel(0x6543b321, priv->dramc_ao + DRAMC_REFRATRE_FILTER); + + /* Update PCDDR3 default setting */ + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA1); + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA2); + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA3); + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA4); + writel(0x10000111, priv->dramc_ao + DRAMC_SHU_SELPH_CA5); + writel(0x1000000, priv->dramc_ao + DRAMC_SHU_SELPH_CA6); + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA7); + writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA8); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_CA_CMD9); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_CA_CMD9); + writel(0x11112222, priv->dramc_ao + DRAMC_SHU_SELPH_DQS0); + writel(0x33331111, priv->dramc_ao + DRAMC_SHU_SELPH_DQS1); + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ0); + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ1); + writel(0x33331111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ2); + writel(0x33331111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ3); + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ0); + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ1); + writel(0x33331111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ2); + writel(0x33331111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ3); + writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7); + writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ7); + writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7); + writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ7); + writel(0x0, priv->dramc_ao + DRAMC_SHURK0_SELPH_ODTEN0); + writel(0x0, priv->dramc_ao + DRAMC_SHURK0_SELPH_ODTEN1); + writel(0x0, priv->dramc_ao + DRAMC_SHURK1_SELPH_ODTEN0); + writel(0x0, priv->dramc_ao + DRAMC_SHURK1_SELPH_ODTEN1); + writel(0x0, priv->dramc_ao + DRAMC_SHURK2_SELPH_ODTEN0); + writel(0x66666666, priv->dramc_ao + DRAMC_SHURK2_SELPH_ODTEN1); + writel(0x2c000b0f, priv->dramc_ao + DRAMC_SHU_CONF1); + writel(0x11111111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG0); + writel(0x64646464, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG1); + writel(0x11111111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQSG0); + writel(0x64646464, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQSG1); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ2); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ3); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ4); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ5); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ6); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ2); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ3); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ4); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ5); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ6); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ2); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ3); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ4); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ5); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ6); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ2); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ3); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ4); + writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ5); + writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ6); + writel(0x20000001, priv->dramc_ao + DRAMC_SHU_RANKCTL); + writel(0x2, priv->dramc_ao + DRAMC_SHURK0_DQSCTL); + writel(0x2, priv->dramc_ao + DRAMC_SHURK1_DQSCTL); + writel(0x4020b07, priv->dramc_ao + DRAMC_SHU_ACTIM0); + writel(0xb060400, priv->dramc_ao + DRAMC_SHU_ACTIM1); + writel(0x8090200, priv->dramc_ao + DRAMC_SHU_ACTIM2); + writel(0x810018, priv->dramc_ao + DRAMC_SHU_ACTIM3); + writel(0x1e9700ff, priv->dramc_ao + DRAMC_SHU_ACTIM4); + writel(0x1000908, priv->dramc_ao + DRAMC_SHU_ACTIM5); + writel(0x801040b, priv->dramc_ao + DRAMC_SHU_ACTIM_XRT); + writel(0x20000D1, priv->dramc_ao + DRAMC_SHU_AC_TIME_05T); + writel(0x80010000, priv->ddrphy + DDRPHY_PLL2); + udelay(500); + + writel(0x81080000, priv->dramc_ao + DRAMC_MISCTL0); + writel(0xacf13, priv->dramc_ao + DRAMC_PERFCTL0); + writel(0xacf12, priv->dramc_ao + DRAMC_PERFCTL0); + writel(0x80, priv->dramc_ao + DRAMC_ARBCTL); + writel(0x9, priv->dramc_ao + DRAMC_PADCTRL); + writel(0x80000107, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL); + writel(0x3000000c, priv->dramc_ao + DRAMC_CLKCTRL); + writel(0x25714001, priv->dramc_ao + DRAMC_REFCTRL0); + writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0x4300000, priv->dramc_ao + DRAMC_CATRAINING1); + writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL); + writel(0x731414, priv->dramc_ao + DRAMC_RKCFG); + writel(0x733414, priv->dramc_ao + DRAMC_RKCFG); + udelay(20); + + writel(0x80002050, priv->dramc_ao + DRAMC_CKECTRL); + udelay(100); + + writel(0x400000, priv->dramc_ao + DRAMC_MRS); + writel(0x401800, priv->dramc_ao + DRAMC_MRS); + writel(0x1, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + udelay(100); + + writel(0x601800, priv->dramc_ao + DRAMC_MRS); + writel(0x600000, priv->dramc_ao + DRAMC_MRS); + writel(0x1, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + udelay(100); + + writel(0x200000, priv->dramc_ao + DRAMC_MRS); + writel(0x200400, priv->dramc_ao + DRAMC_MRS); + writel(0x1, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + udelay(100); + + writel(0x400, priv->dramc_ao + DRAMC_MRS); + writel(0x1d7000, priv->dramc_ao + DRAMC_MRS); + writel(0x1, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + udelay(100); + + writel(0x702201, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0x10, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + writel(0x20, priv->dramc_ao + DRAMC_SPCMD); + writel(0x0, priv->dramc_ao + DRAMC_SPCMD); + writel(0x1, priv->dramc_ao + DRAMC_HW_MRR_FUN); + writel(0x702301, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0x702301, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0xa56, priv->dramc_ao + DRAMC_ZQCS); + writel(0xff0000, priv->dramc_ao + DRAMC_SHU_CONF3); + writel(0x15b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0x2cb00b0f, priv->dramc_ao + DRAMC_SHU_CONF1); + writel(0x65714001, priv->dramc_ao + DRAMC_REFCTRL0); + writel(0x48000000, priv->dramc_ao + DRAMC_SREFCTRL); + writel(0xc0000107, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL); + writel(0x10002, priv->dramc_ao + DRAMC_EYESCAN); + writel(0x15e00, priv->dramc_ao + DRAMC_STBCAL1); + writel(0x100000, priv->dramc_ao + DRAMC_TEST2_1); + writel(0x4000, priv->dramc_ao + DRAMC_TEST2_2); + writel(0x12000480, priv->dramc_ao + DRAMC_TEST2_3); + writel(0x301d007, priv->dramc_ao + DRAMC_SHUCTRL2); + writel(0x4782321, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0x30210000, priv->dramc_ao + DRAMC_SHU_CKECTRL); + writel(0x20000, priv->dramc_ao + DRAMC_DUMMY_RD); + writel(0x4080110d, priv->dramc_ao + DRAMC_TEST2_4); + writel(0x30000721, priv->dramc_ao + DRAMC_REFCTRL1); + writel(0x0, priv->dramc_ao + DRAMC_RSTMASK); + writel(0x4782320, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0x80002000, priv->dramc_ao + DRAMC_CKECTRL); + writel(0x45714001, priv->dramc_ao + DRAMC_REFCTRL0); + + /* Apply config before calibration */ + writel(0x120, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL); + writel(0x11351131, priv->ddrphy + DDRPHY_MISC_CTRL3); + writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_CG_CTRL0); + writel(0x2a7fe, priv->dramc_ao + DRAMC_SHU_SCINTV); + writel(0xff01ff, priv->dramc_ao + DRAMC_SHU_CONF3); + writel(0x4782320, priv->dramc_ao + DRAMC_DRAMCTRL); + writel(0xa56, priv->dramc_ao + DRAMC_ZQCS); + writel(0x80000000, priv->dramc_ao + DRAMC_SHU1_WODT); + writel(0x21, priv->ddrphy + DDRPHY_SHU1_B0_DQ7); + writel(0x1, priv->ddrphy + DDRPHY_SHU1_B1_DQ7); + writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL); + writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL); + writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL); + writel(0x10002, priv->dramc_ao + DRAMC_EYESCAN); + writel(0x8100008c, priv->ddrphy + DDRPHY_MISC_CTRL1); + writel(0x45714001, priv->dramc_ao + DRAMC_REFCTRL0); + writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL); + writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL); + + /* Write leveling */ + writel(0x1f2e2e00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7); + writel(0x202f2f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7); + writel(0x33221100, priv->dramc_ao + DRAMC_SHU_SELPH_DQS1); + writel(0x11112222, priv->dramc_ao + DRAMC_SHU_SELPH_DQS0); + + /* RX dqs gating cal */ + writel(0x11111010, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG0); + writel(0x20201717, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG1); + writel(0x1d1f, priv->dramc_ao + DRAMC_SHURK0_DQSIEN); + + /* RX window per-bit cal */ + writel(0x03030404, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ2); + writel(0x01010303, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ3); + writel(0x01010303, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ4); + writel(0x01010000, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ5); + writel(0x03030606, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ2); + writel(0x02020202, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ3); + writel(0x04040303, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ4); + writel(0x06060101, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ5); + + /* RX datlat cal */ + writel(0x28b00a0e, priv->dramc_ao + DRAMC_SHU_CONF1); + + /* TX window per-byte with 2UI cal */ + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ0); + writel(0x22220000, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ2); + writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ1); + writel(0x22220000, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ3); + writel(0x1f2e2e00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7); + writel(0x202f2f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7); + + return mtk_ddr3_rank_size_detect(dev); +} +#endif + +static int mtk_ddr3_probe(struct udevice *dev) +{ + struct mtk_ddr3_priv *priv = dev_get_priv(dev); + + priv->emi = dev_read_addr_index(dev, 0); + if (priv->emi == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->ddrphy = dev_read_addr_index(dev, 1); + if (priv->ddrphy == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->dramc_ao = dev_read_addr_index(dev, 2); + if (priv->dramc_ao == FDT_ADDR_T_NONE) + return -EINVAL; + +#ifdef CONFIG_SPL_BUILD + int ret; + + ret = clk_get_by_index(dev, 0, &priv->phy); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 1, &priv->phy_mux); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 2, &priv->mem); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 3, &priv->mem_mux); + if (ret) + return ret; + + ret = mtk_ddr3_init(dev); + if (ret) + return ret; +#endif + return 0; +} + +static int mtk_ddr3_get_info(struct udevice *dev, struct ram_info *info) +{ + struct mtk_ddr3_priv *priv = dev_get_priv(dev); + u32 val = readl(priv->emi + EMI_CONA); + + info->base = CONFIG_SYS_SDRAM_BASE; + + switch ((val & EMI_COL_ADDR_MASK) >> EMI_COL_ADDR_SHIFT) { + case 0: + info->size = SZ_128M; + break; + case 1: + info->size = SZ_256M; + break; + case 2: + info->size = SZ_512M; + break; + case 3: + info->size = SZ_1G; + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct ram_ops mtk_ddr3_ops = { + .get_info = mtk_ddr3_get_info, +}; + +static const struct udevice_id mtk_ddr3_ids[] = { + { .compatible = "mediatek,mt7629-dramc" }, + { } +}; + +U_BOOT_DRIVER(mediatek_ddr3) = { + .name = "mediatek_ddr3", + .id = UCLASS_RAM, + .of_match = mtk_ddr3_ids, + .ops = &mtk_ddr3_ops, + .probe = mtk_ddr3_probe, + .priv_auto_alloc_size = sizeof(struct mtk_ddr3_priv), +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index bcc01b135e5..fd0009b2e2d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -60,6 +60,16 @@ config RTC_ISL1208 This driver supports reading and writing the RTC/calendar and detects total power failures. +config RTC_RV3029 + bool "Enable RV3029 driver" + depends on DM_RTC + help + The MicroCrystal RV3029 is a I2C Real Time Clock (RTC) with 8-byte + battery-backed SRAM. + + This driver supports reading and writing the RTC/calendar and the + battery-baced SRAM section. + config RTC_RX8010SJ bool "Enable RX8010SJ driver" depends on DM_RTC @@ -94,4 +104,10 @@ config RTC_MC146818 clock with a wide array of features and 50 bytes of general-purpose, battery-backed RAM. The driver supports access to the clock and RAM. +config RTC_M41T62 + bool "Enable M41T62 driver" + help + Enable driver for ST's M41T62 compatible RTC devices (like RV-4162). + It is a serial (I2C) real-time clock (RTC) with alarm. + endmenu diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c index 137438389db..2ee7e00b021 100644 --- a/drivers/rtc/m41t62.c +++ b/drivers/rtc/m41t62.c @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * (C) Copyright 2018 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de. + * * (C) Copyright 2008 * Stefan Roese, DENX Software Engineering, sr@denx.de. * @@ -15,6 +18,7 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <rtc.h> #include <i2c.h> @@ -49,12 +53,8 @@ #define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */ -int rtc_get(struct rtc_time *tm) +static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf) { - u8 buf[M41T62_DATETIME_REG_SIZE]; - - i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); - debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, " "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", __FUNCTION__, @@ -77,20 +77,14 @@ int rtc_get(struct rtc_time *tm) __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - - return 0; } -int rtc_set(struct rtc_time *tm) +static void m41t62_set_rtc_buf(const struct rtc_time *tm, u8 *buf) { - u8 buf[M41T62_DATETIME_REG_SIZE]; - debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); - i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); - /* Merge time-data and register flags into buf[0..7] */ buf[M41T62_REG_SSEC] = 0; buf[M41T62_REG_SEC] = @@ -107,8 +101,99 @@ int rtc_set(struct rtc_time *tm) bin2bcd(tm->tm_mon) | (buf[M41T62_REG_MON] & ~0x1f); /* assume 20YY not 19YY */ buf[M41T62_REG_YEAR] = bin2bcd(tm->tm_year % 100); +} + +#ifdef CONFIG_DM_RTC +static int m41t62_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + u8 buf[M41T62_DATETIME_REG_SIZE]; + int ret; + + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret) + return ret; + + m41t62_update_rtc_time(tm, buf); + + return 0; +} + +static int m41t62_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + u8 buf[M41T62_DATETIME_REG_SIZE]; + int ret; + + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret) + return ret; + + m41t62_set_rtc_buf(tm, buf); + + ret = dm_i2c_write(dev, 0, buf, sizeof(buf)); + if (ret) { + printf("I2C write failed in %s()\n", __func__); + return ret; + } + + return 0; +} + +static int m41t62_rtc_reset(struct udevice *dev) +{ + u8 val; + + /* + * M41T82: Make sure HT (Halt Update) bit is cleared. + * This bit is 0 in M41T62 so its save to clear it always. + */ + + int ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val)); + + val &= ~M41T80_ALHOUR_HT; + ret |= dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val)); + + return ret; +} + +static const struct rtc_ops m41t62_rtc_ops = { + .get = m41t62_rtc_get, + .set = m41t62_rtc_set, + .reset = m41t62_rtc_reset, +}; + +static const struct udevice_id m41t62_rtc_ids[] = { + { .compatible = "st,m41t62" }, + { .compatible = "microcrystal,rv4162" }, + { } +}; + +U_BOOT_DRIVER(rtc_m41t62) = { + .name = "rtc-m41t62", + .id = UCLASS_RTC, + .of_match = m41t62_rtc_ids, + .ops = &m41t62_rtc_ops, +}; + +#else /* NON DM RTC code - will be removed */ +int rtc_get(struct rtc_time *tm) +{ + u8 buf[M41T62_DATETIME_REG_SIZE]; + + i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); + m41t62_update_rtc_time(tm, buf); + + return 0; +} + +int rtc_set(struct rtc_time *tm) +{ + u8 buf[M41T62_DATETIME_REG_SIZE]; + + i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); + m41t62_set_rtc_buf(tm, buf); - if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE)) { + if (i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, buf, + M41T62_DATETIME_REG_SIZE)) { printf("I2C write failed in %s()\n", __func__); return -1; } @@ -128,3 +213,4 @@ void rtc_reset(void) val &= ~M41T80_ALHOUR_HT; i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1); } +#endif /* CONFIG_DM_RTC */ diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index b8a7a8b2d3b..6528ddfebb4 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -31,10 +31,14 @@ static int rtc_month_days(unsigned int month, unsigned int year) /* * rtc_to_tm - Converts u64 to rtc_time. * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. + * + * This function is copied from rtc_time64_to_tm() in the Linux kernel. + * But in U-Boot January is month 1 and we do not subtract 1900 from the year. */ void rtc_to_tm(u64 time, struct rtc_time *tm) { - unsigned int month, year, secs, days; + unsigned int month, year, secs; + int days; days = div_u64_rem(time, 86400, &secs); diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index c676f0ff359..a0a238aedda 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -122,4 +122,5 @@ int rtc_write32(struct udevice *dev, unsigned int reg, u32 value) UCLASS_DRIVER(rtc) = { .name = "rtc", .id = UCLASS_RTC, + .post_bind = dm_scan_fdt_dev, }; diff --git a/drivers/rtc/rv3029.c b/drivers/rtc/rv3029.c index dd4d0607a8f..38acb9c9924 100644 --- a/drivers/rtc/rv3029.c +++ b/drivers/rtc/rv3029.c @@ -1,189 +1,495 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2010 - * Heiko Schocher, DENX Software Engineering, hs@denx.de + * (C) Copyright 2018 Theobroma Systems Design und Consulting GmbH + * + * Based on a the Linux rtc-rv3029c2.c driver written by: + * Gregory Hermant <gregory.hermant@calao-systems.com> + * Michael Buesch <m@bues.ch> */ + #include <common.h> #include <command.h> +#include <dm.h> #include <i2c.h> #include <rtc.h> -#define RTC_RV3029_CTRL1 0x00 -#define RTC_RV3029_CTRL1_EERE (1 << 3) - -#define RTC_RV3029_CTRL_STATUS 0x03 -#define RTC_RV3029_CTRLS_EEBUSY (1 << 7) +#define RTC_RV3029_PAGE_LEN 7 -#define RTC_RV3029_CTRL_RESET 0x04 -#define RTC_RV3029_CTRL_SYS_R (1 << 4) +/* control section */ +#define RV3029_ONOFF_CTRL 0x00 +#define RV3029_ONOFF_CTRL_WE BIT(0) +#define RV3029_ONOFF_CTRL_TE BIT(1) +#define RV3029_ONOFF_CTRL_TAR BIT(2) +#define RV3029_ONOFF_CTRL_EERE BIT(3) +#define RV3029_ONOFF_CTRL_SRON BIT(4) +#define RV3029_ONOFF_CTRL_TD0 BIT(5) +#define RV3029_ONOFF_CTRL_TD1 BIT(6) +#define RV3029_ONOFF_CTRL_CLKINT BIT(7) +#define RV3029_IRQ_CTRL 0x01 +#define RV3029_IRQ_CTRL_AIE BIT(0) +#define RV3029_IRQ_CTRL_TIE BIT(1) +#define RV3029_IRQ_CTRL_V1IE BIT(2) +#define RV3029_IRQ_CTRL_V2IE BIT(3) +#define RV3029_IRQ_CTRL_SRIE BIT(4) +#define RV3029_IRQ_FLAGS 0x02 +#define RV3029_IRQ_FLAGS_AF BIT(0) +#define RV3029_IRQ_FLAGS_TF BIT(1) +#define RV3029_IRQ_FLAGS_V1IF BIT(2) +#define RV3029_IRQ_FLAGS_V2IF BIT(3) +#define RV3029_IRQ_FLAGS_SRF BIT(4) +#define RV3029_STATUS 0x03 +#define RV3029_STATUS_VLOW1 BIT(2) +#define RV3029_STATUS_VLOW2 BIT(3) +#define RV3029_STATUS_SR BIT(4) +#define RV3029_STATUS_PON BIT(5) +#define RV3029_STATUS_EEBUSY BIT(7) +#define RV3029_RST_CTRL 0x04 +#define RV3029_RST_CTRL_SYSR BIT(4) +#define RV3029_CONTROL_SECTION_LEN 0x05 -#define RTC_RV3029_CLOCK_PAGE 0x08 -#define RTC_RV3029_PAGE_LEN 7 +/* watch section */ +#define RV3029_W_SEC 0x08 +#define RV3029_W_MINUTES 0x09 +#define RV3029_W_HOURS 0x0A +#define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */ +#define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */ +#define RV3029_W_DATE 0x0B +#define RV3029_W_DAYS 0x0C +#define RV3029_W_MONTHS 0x0D +#define RV3029_W_YEARS 0x0E -#define RV3029C2_W_SECONDS 0x00 -#define RV3029C2_W_MINUTES 0x01 -#define RV3029C2_W_HOURS 0x02 -#define RV3029C2_W_DATE 0x03 -#define RV3029C2_W_DAYS 0x04 -#define RV3029C2_W_MONTHS 0x05 -#define RV3029C2_W_YEARS 0x06 +/* eeprom control section */ +#define RV3029_CONTROL_E2P_EECTRL 0x30 +#define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */ +#define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */ +#define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */ +#define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */ +#define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\ + RV3029_TRICKLE_5K |\ + RV3029_TRICKLE_20K |\ + RV3029_TRICKLE_80K) +#define RV3029_TRICKLE_SHIFT 4 -#define RV3029C2_REG_HR_12_24 (1 << 6) /* 24h/12h mode */ -#define RV3029C2_REG_HR_PM (1 << 5) /* PM/AM bit in 12h mode */ -#define RTC_RV3029_EEPROM_CTRL 0x30 -#define RTC_RV3029_TRICKLE_1K (1 << 4) -#define RTC_RV3029_TRICKLE_5K (1 << 5) -#define RTC_RV3029_TRICKLE_20K (1 << 6) -#define RTC_RV3029_TRICKLE_80K (1 << 7) - -int rtc_get( struct rtc_time *tmp ) +static int rv3029_rtc_get(struct udevice *dev, struct rtc_time *tm) { - int ret; - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 regs[RTC_RV3029_PAGE_LEN]; + int ret; - ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, buf, \ - RTC_RV3029_PAGE_LEN); - if (ret) { + ret = dm_i2c_read(dev, RV3029_W_SEC, regs, sizeof(regs)); + if (ret < 0) { printf("%s: error reading RTC: %x\n", __func__, ret); - return -1; + return -EIO; + } + + tm->tm_sec = bcd2bin(regs[RV3029_W_SEC - RV3029_W_SEC]); + tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES - RV3029_W_SEC]); + + /* HR field has a more complex interpretation */ + { + const u8 _hr = regs[RV3029_W_HOURS - RV3029_W_SEC]; + + if (_hr & RV3029_REG_HR_12_24) { + /* 12h format */ + tm->tm_hour = bcd2bin(_hr & 0x1f); + if (_hr & RV3029_REG_HR_PM) /* PM flag set */ + tm->tm_hour += 12; + } else { + /* 24h format */ + tm->tm_hour = bcd2bin(_hr & 0x3f); + } } - tmp->tm_sec = bcd2bin( buf[RV3029C2_W_SECONDS] & 0x7f); - tmp->tm_min = bcd2bin( buf[RV3029C2_W_MINUTES] & 0x7f); - if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_12_24) { - /* 12h format */ - tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x1f); - if (buf[RV3029C2_W_HOURS] & RV3029C2_REG_HR_PM) - /* PM flag set */ - tmp->tm_hour += 12; - } else - tmp->tm_hour = bcd2bin(buf[RV3029C2_W_HOURS] & 0x3f); - - tmp->tm_mday = bcd2bin( buf[RV3029C2_W_DATE] & 0x3F ); - tmp->tm_mon = bcd2bin( buf[RV3029C2_W_MONTHS] & 0x1F ); - tmp->tm_wday = bcd2bin( buf[RV3029C2_W_DAYS] & 0x07 ); + + tm->tm_mday = bcd2bin(regs[RV3029_W_DATE - RV3029_W_SEC]); + tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS - RV3029_W_SEC]) - 1; /* RTC supports only years > 1999 */ - tmp->tm_year = bcd2bin( buf[RV3029C2_W_YEARS]) + 2000; - tmp->tm_yday = 0; - tmp->tm_isdst = 0; + tm->tm_year = bcd2bin(regs[RV3029_W_YEARS - RV3029_W_SEC]) + 2000; + tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS - RV3029_W_SEC]) - 1; + + tm->tm_yday = 0; + tm->tm_isdst = 0; - debug( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec ); + debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; } -int rtc_set( struct rtc_time *tmp ) +static int rv3029_rtc_set(struct udevice *dev, const struct rtc_time *tm) { - int ret; - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 regs[RTC_RV3029_PAGE_LEN]; + + debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n", + __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); - debug( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - if (tmp->tm_year < 2000) { - printf("RTC: year %d < 2000 not possible\n", tmp->tm_year); - return -1; + if (tm->tm_year < 2000) { + printf("%s: year %d (before 2000) not supported\n", + __func__, tm->tm_year); + return -EINVAL; } - buf[RV3029C2_W_SECONDS] = bin2bcd(tmp->tm_sec); - buf[RV3029C2_W_MINUTES] = bin2bcd(tmp->tm_min); - buf[RV3029C2_W_HOURS] = bin2bcd(tmp->tm_hour); - /* set 24h format */ - buf[RV3029C2_W_HOURS] &= ~RV3029C2_REG_HR_12_24; - buf[RV3029C2_W_DATE] = bin2bcd(tmp->tm_mday); - buf[RV3029C2_W_DAYS] = bin2bcd(tmp->tm_wday); - buf[RV3029C2_W_MONTHS] = bin2bcd(tmp->tm_mon); - tmp->tm_year -= 2000; - buf[RV3029C2_W_YEARS] = bin2bcd(tmp->tm_year); - ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CLOCK_PAGE, 1, - buf, RTC_RV3029_PAGE_LEN); - - /* give the RTC some time to update */ - udelay(1000); - return ret; + + regs[RV3029_W_SEC - RV3029_W_SEC] = bin2bcd(tm->tm_sec); + regs[RV3029_W_MINUTES - RV3029_W_SEC] = bin2bcd(tm->tm_min); + regs[RV3029_W_HOURS - RV3029_W_SEC] = bin2bcd(tm->tm_hour); + regs[RV3029_W_DATE - RV3029_W_SEC] = bin2bcd(tm->tm_mday); + regs[RV3029_W_MONTHS - RV3029_W_SEC] = bin2bcd(tm->tm_mon + 1); + regs[RV3029_W_DAYS - RV3029_W_SEC] = bin2bcd(tm->tm_wday + 1) & 0x7; + regs[RV3029_W_YEARS - RV3029_W_SEC] = bin2bcd(tm->tm_year - 2000); + + return dm_i2c_write(dev, RV3029_W_SEC, regs, sizeof(regs)); } -/* sets EERE-Bit (automatic EEPROM refresh) */ -static void set_eere_bit(int state) +static int rv3029_rtc_reset(struct udevice *dev) { - unsigned char reg_ctrl1; + u8 ctrl = RV3029_RST_CTRL_SYSR; + unsigned long start; + const unsigned long timeout_ms = 10000; + int ret; - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL1, 1, - ®_ctrl1, 1); + /* trigger the system-reset */ + ret = dm_i2c_write(dev, RV3029_RST_CTRL, &ctrl, 1); + if (ret < 0) + return -EIO; - if (state) - reg_ctrl1 |= RTC_RV3029_CTRL1_EERE; - else - reg_ctrl1 &= (~RTC_RV3029_CTRL1_EERE); + /* wait for the system-reset to complete */ + start = get_timer(0); + do { + if (get_timer(start) > timeout_ms) + return -ETIMEDOUT; - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL1, 1, - ®_ctrl1, 1); + ret = dm_i2c_read(dev, RV3029_RST_CTRL, &ctrl, 1); + if (ret < 0) + return -EIO; + } while (ctrl & RV3029_RST_CTRL_SYSR); + + return 0; } -/* waits until EEPROM page is no longer busy (times out after 10ms*loops) */ -static int wait_eebusy(int loops) +static int rv3029_rtc_read8(struct udevice *dev, unsigned int reg) { - int i; - unsigned char ctrl_status; + u8 data; + int ret; + + ret = dm_i2c_read(dev, reg, &data, sizeof(data)); + return ret < 0 ? ret : data; +} - for (i = 0; i < loops; i++) { - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL_STATUS, - 1, &ctrl_status, 1); +static int rv3029_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + u8 data = val; + + return dm_i2c_write(dev, reg, &data, 1); +} + +#if defined(OF_CONTROL) +static int rv3029_get_sr(struct udevice *dev, u8 *buf) +{ + int ret = dm_i2c_read(dev, RV3029_STATUS, buf, 1); + + if (ret < 0) + return -EIO; + + dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]); + return 0; +} - if ((ctrl_status & RTC_RV3029_CTRLS_EEBUSY) == 0) +static int rv3029_set_sr(struct udevice *dev, u8 val) +{ + int ret; + + ret = dm_i2c_read(dev, RV3029_STATUS, &val, 1); + if (ret < 0) + return -EIO; + + dev_dbg(dev, "status = 0x%.2x (%d)\n", val, val); + return 0; +} + +static int rv3029_eeprom_busywait(struct udevice *dev) +{ + int i, ret; + u8 sr; + + for (i = 100; i > 0; i--) { + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + break; + if (!(sr & RV3029_STATUS_EEBUSY)) break; udelay(10000); } - return i; + if (i <= 0) { + dev_err(dev, "EEPROM busy wait timeout.\n"); + return -ETIMEDOUT; + } + + return ret; } -void rtc_reset (void) +static int rv3029_update_bits(struct udevice *dev, u8 reg, u8 mask, u8 set) { - unsigned char buf[RTC_RV3029_PAGE_LEN]; + u8 buf; + int ret; - buf[0] = RTC_RV3029_CTRL_SYS_R; - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_CTRL_RESET, 1, - buf, 1); + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; -#if defined(CONFIG_SYS_RV3029_TCR) - /* - * because EEPROM_CTRL register is in EEPROM page it is necessary to - * disable automatic EEPROM refresh and check if EEPROM is busy - * before EEPORM_CTRL register may be accessed - */ - set_eere_bit(0); - wait_eebusy(100); - /* read current trickle charger setting */ - (void)i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_RV3029_EEPROM_CTRL, - 1, buf, 1); - /* enable automatic EEPROM refresh again */ - set_eere_bit(1); + if ((buf & mask) == (set && mask)) + return 0; - /* - * to minimize EEPROM access write trickle charger setting only if it - * differs from current value - */ - if ((buf[0] & 0xF0) != CONFIG_SYS_RV3029_TCR) { - buf[0] = (buf[0] & 0x0F) | CONFIG_SYS_RV3029_TCR; - /* - * write trickle charger setting (disable autom. EEPROM - * refresh and wait until EEPROM is idle) - */ - set_eere_bit(0); - wait_eebusy(100); - (void)i2c_write(CONFIG_SYS_I2C_RTC_ADDR, - RTC_RV3029_EEPROM_CTRL, 1, buf, 1); - /* - * it is necessary to wait 10ms before EEBUSY-Bit may be read - * (this is not documented in the data sheet yet, but the - * manufacturer recommends it) + buf = (buf & ~mask) | (set & mask); + ret = dm_i2c_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3029_eeprom_exit(struct udevice *dev) +{ + /* Re-enable eeprom refresh */ + return rv3029_update_bits(dev, RV3029_ONOFF_CTRL, + RV3029_ONOFF_CTRL_EERE, + RV3029_ONOFF_CTRL_EERE); +} + +static int rv3029_eeprom_enter(struct udevice *dev) +{ + int ret; + u8 sr; + + /* Check whether we are in the allowed voltage range. */ + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + /* We clear the bits and retry once just in case + * we had a brown out in early startup. */ + sr &= ~RV3029_STATUS_VLOW1; + sr &= ~RV3029_STATUS_VLOW2; + ret = rv3029_set_sr(dev, sr); + if (ret < 0) + return ret; udelay(10000); - /* wait until EEPROM write access is finished */ - wait_eebusy(100); - set_eere_bit(1); + ret = rv3029_get_sr(dev, &sr); + if (ret < 0) + return ret; + if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) { + dev_err(dev, "Supply voltage is too low to safely access the EEPROM.\n"); + return -ENODEV; + } + } + + /* Disable eeprom refresh. */ + ret = rv3029_update_bits(dev, + RV3029_ONOFF_CTRL, RV3029_ONOFF_CTRL_EERE, 0); + if (ret < 0) + return ret; + + /* Wait for any previous eeprom accesses to finish. */ + ret = rv3029_eeprom_busywait(dev); + if (ret < 0) + rv3029_eeprom_exit(dev); + + return ret; +} + +static int rv3029_eeprom_read(struct udevice *dev, u8 reg, + u8 buf[], size_t len) +{ + int ret, err; + + err = rv3029_eeprom_enter(dev); + if (err < 0) + return err; + + ret = dm_i2c_read(dev, reg, buf, len); + + err = rv3029_eeprom_exit(dev); + if (err < 0) + return err; + + return ret; +} + +static int rv3029_eeprom_write(struct udevice *dev, u8 reg, + u8 const buf[], size_t len) +{ + int ret; + size_t i; + u8 tmp; + + ret = rv3029_eeprom_enter(dev); + if (ret < 0) + return ret; + + for (i = 0; i < len; i++, reg++) { + ret = dm_i2c_read(dev, reg, &tmp, 1); + if (ret < 0) + break; + if (tmp != buf[i]) { + ret = dm_i2c_write(dev, reg, &buf[i], 1); + if (ret < 0) + break; + } + ret = rv3029_eeprom_busywait(dev); + if (ret < 0) + break; } + + ret = rv3029_eeprom_exit(dev); + if (ret < 0) + return ret; + + return 0; +} + +static int rv3029_eeprom_update_bits(struct udevice *dev, + u8 reg, u8 mask, u8 set) +{ + u8 buf; + int ret; + + ret = rv3029_eeprom_read(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + /* + * If the EEPROM already reads the correct bitpattern, we don't need + * to update it. + */ + if ((buf & mask) == (set & mask)) + return 0; + + buf = (buf & ~mask) | (set & mask); + ret = rv3029_eeprom_write(dev, reg, &buf, 1); + if (ret < 0) + return ret; + + return 0; +} + +static void rv3029_trickle_config(struct udevice *dev) +{ + static const struct rv3029_trickle_tab_elem { + u32 r; /* resistance in ohms */ + u8 conf; /* trickle config bits */ + } rv3029_trickle_tab[] = { + { + .r = 1076, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 1091, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_20K, + }, { + .r = 1137, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K | + RV3029_TRICKLE_80K, + }, { + .r = 1154, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K, + }, { + .r = 1371, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 1395, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K, + }, { + .r = 1472, + .conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K, + }, { + .r = 1500, + .conf = RV3029_TRICKLE_1K, + }, { + .r = 3810, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K | + RV3029_TRICKLE_80K, + }, { + .r = 4000, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K, + }, { + .r = 4706, + .conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K, + }, { + .r = 5000, + .conf = RV3029_TRICKLE_5K, + }, { + .r = 16000, + .conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K, + }, { + .r = 20000, + .conf = RV3029_TRICKLE_20K, + }, { + .r = 80000, + .conf = RV3029_TRICKLE_80K, + }, + }; + int err; + u32 ohms; + u8 trickle_set_bits = 0; + + /* Configure the trickle charger. */ + err = dev_read_u32(dev, "trickle-resistor-ohms", &ohms); + + if (!err) { + /* Find trickle-charger config */ + for (int i = 0; i < ARRAY_SIZE(rv3029_trickle_tab); i++) + if (rv3029_trickle_tab[i].r >= ohms) { + dev_dbg(dev, "trickle charger at %d ohms\n", + rv3029_trickle_tab[i].r); + trickle_set_bits = rv3029_trickle_tab[i].conf; + break; + } + } + + dev_dbg(dev, "trickle charger config 0x%x\n", trickle_set_bits); + err = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL, + RV3029_TRICKLE_MASK, + trickle_set_bits); + if (err < 0) + dev_dbg(dev, "failed to update trickle charger\n"); +} +#else +static inline void rv3029_trickle_config(struct udevice *dev) +{ +} #endif + +static int rv3029_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | + DM_I2C_CHIP_WR_ADDRESS); + + rv3029_trickle_config(dev); + return 0; } + +static const struct rtc_ops rv3029_rtc_ops = { + .get = rv3029_rtc_get, + .set = rv3029_rtc_set, + .read8 = rv3029_rtc_read8, + .write8 = rv3029_rtc_write8, + .reset = rv3029_rtc_reset, +}; + +static const struct udevice_id rv3029_rtc_ids[] = { + { .compatible = "mc,rv3029" }, + { .compatible = "mc,rv3029c2" }, + { } +}; + +U_BOOT_DRIVER(rtc_rv3029) = { + .name = "rtc-rv3029", + .id = UCLASS_RTC, + .probe = rv3029_probe, + .of_match = rv3029_rtc_ids, + .ops = &rv3029_rtc_ops, +}; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 6625a65b584..3bcc61e7312 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -368,6 +368,16 @@ config DEBUG_UART_OMAP You will need to provide parameters to make this work. The driver will be available until the real driver model serial is running. +config DEBUG_UART_MTK + bool "MediaTek High-speed UART" + depends on MTK_SERIAL + help + Select this to enable a debug UART using the MediaTek High-speed + UART driver. + You will need to provide parameters to make this work. The + driver will be available until the real driver model serial is + running. + endchoice config DEBUG_UART_BASE @@ -698,6 +708,16 @@ config ZYNQ_SERIAL This driver supports the Cadence UART. It is found e.g. in Xilinx Zynq/ZynqMP. +config MTK_SERIAL + bool "MediaTek High-speed UART support" + depends on DM_SERIAL + help + Select this to enable UART support for MediaTek High-speed UART + devices. This driver uses driver model and requires a device + tree binding to operate. + The High-speed UART is compatible with the ns16550a UART and have + its own high-speed registers. + config MPC8XX_CONS bool "Console driver for MPC8XX" depends on MPC8xx diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index a48458f9553..b6377b10768 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o obj-$(CONFIG_OWL_SERIAL) += serial_owl.o obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o +obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index f21c240e64a..25b9d172433 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -272,26 +272,12 @@ static inline void _debug_uart_init(void) serial_dout(&com_port->lcr, UART_LCRVAL); } -static inline int NS16550_read_baud_divisor(struct NS16550 *com_port) -{ - int ret; - - serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL); - ret = serial_din(&com_port->dll) & 0xff; - ret |= (serial_din(&com_port->dlm) & 0xff) << 8; - serial_dout(&com_port->lcr, UART_LCRVAL); - - return ret; -} - static inline void _debug_uart_putc(int ch) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; - while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) { - if (!NS16550_read_baud_divisor(com_port)) - return; - } + while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) + ; serial_dout(&com_port->thr, ch); } diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index c499601f000..09365ba6a1e 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -119,7 +119,6 @@ U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); serial_initfunc(atmel_serial_initialize); serial_initfunc(mcf_serial_initialize); serial_initfunc(mpc85xx_serial_initialize); -serial_initfunc(mpc8xx_serial_initialize); serial_initfunc(mxc_serial_initialize); serial_initfunc(ns16550_serial_initialize); serial_initfunc(pl01x_serial_initialize); @@ -173,7 +172,6 @@ void serial_initialize(void) atmel_serial_initialize(); mcf_serial_initialize(); mpc85xx_serial_initialize(); - mpc8xx_serial_initialize(); mxc_serial_initialize(); ns16550_serial_initialize(); pl01x_serial_initialize(); diff --git a/drivers/serial/serial_mpc8xx.c b/drivers/serial/serial_mpc8xx.c index 292912b7ee2..50d6e70f177 100644 --- a/drivers/serial/serial_mpc8xx.c +++ b/drivers/serial/serial_mpc8xx.c @@ -6,6 +6,7 @@ #include <common.h> #include <command.h> +#include <dm.h> #include <serial.h> #include <watchdog.h> #include <asm/cpm_8xx.h> @@ -35,9 +36,9 @@ struct serialbuffer { uchar txbuf; /* tx buffers */ }; -static void serial_setdivisor(cpm8xx_t __iomem *cp) +static void serial_setdivisor(cpm8xx_t __iomem *cp, int baudrate) { - int divisor = (gd->cpu_clk + 8 * gd->baudrate) / 16 / gd->baudrate; + int divisor = (gd->cpu_clk + 8 * baudrate) / 16 / baudrate; if (divisor / 16 > 0x1000) { /* bad divisor, assume 50MHz clock and 9600 baud */ @@ -58,7 +59,7 @@ static void serial_setdivisor(cpm8xx_t __iomem *cp) * as serial console interface. */ -static void smc_setbrg(void) +static int serial_mpc8xx_setbrg(struct udevice *dev, int baudrate) { immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cp = &(im->im_cpm); @@ -71,10 +72,12 @@ static void smc_setbrg(void) out_be32(&cp->cp_simode, 0); - serial_setdivisor(cp); + serial_setdivisor(cp, baudrate); + + return 0; } -static int smc_init(void) +static int serial_mpc8xx_probe(struct udevice *dev) { immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR; smc_t __iomem *sp; @@ -139,7 +142,7 @@ static int smc_init(void) out_8(&sp->smc_smce, 0xff); /* Set up the baud rate generator */ - smc_setbrg(); + serial_mpc8xx_setbrg(dev, gd->baudrate); /* Make the first buffer the only buffer. */ setbits_be16(&rtx->txbd.cbd_sc, BD_SC_WRAP); @@ -166,14 +169,14 @@ static int smc_init(void) return 0; } -static void smc_putc(const char c) +static int serial_mpc8xx_putc(struct udevice *dev, const char c) { immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cpmp = &(im->im_cpm); struct serialbuffer __iomem *rtx; if (c == '\n') - smc_putc('\r'); + serial_mpc8xx_putc(dev, '\r'); rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE]; @@ -184,15 +187,11 @@ static void smc_putc(const char c) while (in_be16(&rtx->txbd.cbd_sc) & BD_SC_READY) WATCHDOG_RESET(); -} -static void smc_puts(const char *s) -{ - while (*s) - smc_putc(*s++); + return 0; } -static int smc_getc(void) +static int serial_mpc8xx_getc(struct udevice *dev) { immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cpmp = &(im->im_cpm); @@ -222,34 +221,37 @@ static int smc_getc(void) return c; } -static int smc_tstc(void) +static int serial_mpc8xx_pending(struct udevice *dev, bool input) { immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR; cpm8xx_t __iomem *cpmp = &(im->im_cpm); struct serialbuffer __iomem *rtx; + if (!input) + return 0; + rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE]; return !(in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY); } -struct serial_device serial_smc_device = { - .name = "serial_smc", - .start = smc_init, - .stop = NULL, - .setbrg = smc_setbrg, - .getc = smc_getc, - .tstc = smc_tstc, - .putc = smc_putc, - .puts = smc_puts, +static const struct dm_serial_ops serial_mpc8xx_ops = { + .putc = serial_mpc8xx_putc, + .pending = serial_mpc8xx_pending, + .getc = serial_mpc8xx_getc, + .setbrg = serial_mpc8xx_setbrg, }; -__weak struct serial_device *default_serial_console(void) -{ - return &serial_smc_device; -} +static const struct udevice_id serial_mpc8xx_ids[] = { + { .compatible = "fsl,pq1-smc" }, + { } +}; -void mpc8xx_serial_initialize(void) -{ - serial_register(&serial_smc_device); -} +U_BOOT_DRIVER(serial_mpc8xx) = { + .name = "serial_mpc8xx", + .id = UCLASS_SERIAL, + .of_match = serial_mpc8xx_ids, + .probe = serial_mpc8xx_probe, + .ops = &serial_mpc8xx_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c new file mode 100644 index 00000000000..bce1be82279 --- /dev/null +++ b/drivers/serial/serial_mtk.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek High-speed UART driver + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <clk.h> +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <errno.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/io.h> +#include <asm/types.h> + +struct mtk_serial_regs { + u32 rbr; + u32 ier; + u32 fcr; + u32 lcr; + u32 mcr; + u32 lsr; + u32 msr; + u32 spr; + u32 mdr1; + u32 highspeed; + u32 sample_count; + u32 sample_point; + u32 fracdiv_l; + u32 fracdiv_m; + u32 escape_en; + u32 guard; + u32 rx_sel; +}; + +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier + +#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ + +#define UART_LSR_DR 0x01 /* Data ready */ +#define UART_LSR_THRE 0x20 /* Xmit holding register empty */ + +/* the data is correct if the real baud is within 3%. */ +#define BAUD_ALLOW_MAX(baud) ((baud) + (baud) * 3 / 100) +#define BAUD_ALLOW_MIX(baud) ((baud) - (baud) * 3 / 100) + +struct mtk_serial_priv { + struct mtk_serial_regs __iomem *regs; + u32 clock; +}; + +static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud) +{ + bool support_clk12m_baud115200; + u32 quot, samplecount, realbaud; + + if ((baud <= 115200) && (priv->clock == 12000000)) + support_clk12m_baud115200 = true; + else + support_clk12m_baud115200 = false; + + if (baud <= 115200) { + writel(0, &priv->regs->highspeed); + quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud); + + if (support_clk12m_baud115200) { + writel(3, &priv->regs->highspeed); + quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud); + if (quot == 0) + quot = 1; + + samplecount = DIV_ROUND_CLOSEST(priv->clock, + quot * baud); + if (samplecount != 0) { + realbaud = priv->clock / samplecount / quot; + if ((realbaud > BAUD_ALLOW_MAX(baud)) || + (realbaud < BAUD_ALLOW_MIX(baud))) { + pr_info("baud %d can't be handled\n", + baud); + } + } else { + pr_info("samplecount is 0\n"); + } + } + } else if (baud <= 576000) { + writel(2, &priv->regs->highspeed); + + /* Set to next lower baudrate supported */ + if ((baud == 500000) || (baud == 576000)) + baud = 460800; + quot = DIV_ROUND_UP(priv->clock, 4 * baud); + } else { + writel(3, &priv->regs->highspeed); + quot = DIV_ROUND_UP(priv->clock, 256 * baud); + } + + /* set divisor */ + writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr); + writel(quot & 0xff, &priv->regs->dll); + writel((quot >> 8) & 0xff, &priv->regs->dlm); + writel(UART_LCR_WLS_8, &priv->regs->lcr); + + if (baud > 460800) { + u32 tmp; + + tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud); + writel(tmp - 1, &priv->regs->sample_count); + writel((tmp - 2) >> 1, &priv->regs->sample_point); + } else { + writel(0, &priv->regs->sample_count); + writel(0xff, &priv->regs->sample_point); + } + + if (support_clk12m_baud115200) { + writel(samplecount - 1, &priv->regs->sample_count); + writel((samplecount - 2) >> 1, &priv->regs->sample_point); + } +} + +static int mtk_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + + _mtk_serial_setbrg(priv, baudrate); + + return 0; +} + +static int mtk_serial_putc(struct udevice *dev, const char ch) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->regs->lsr) & UART_LSR_THRE)) + return -EAGAIN; + + writel(ch, &priv->regs->thr); + + if (ch == '\n') + WATCHDOG_RESET(); + + return 0; +} + +static int mtk_serial_getc(struct udevice *dev) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->regs->lsr) & UART_LSR_DR)) + return -EAGAIN; + + return readl(&priv->regs->rbr); +} + +static int mtk_serial_pending(struct udevice *dev, bool input) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + + if (input) + return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0; + else + return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1; +} + +static int mtk_serial_probe(struct udevice *dev) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + + /* Disable interrupt */ + writel(0, &priv->regs->ier); + + return 0; +} + +static int mtk_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct mtk_serial_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + struct clk clk; + int err; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->regs = map_physmem(addr, 0, MAP_NOCACHE); + + err = clk_get_by_index(dev, 0, &clk); + if (!err) { + err = clk_get_rate(&clk); + if (!IS_ERR_VALUE(err)) + priv->clock = err; + } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) { + debug("mtk_serial: failed to get clock\n"); + return err; + } + + if (!priv->clock) + priv->clock = dev_read_u32_default(dev, "clock-frequency", 0); + + if (!priv->clock) { + debug("mtk_serial: clock not defined\n"); + return -EINVAL; + } + + return 0; +} + +static const struct dm_serial_ops mtk_serial_ops = { + .putc = mtk_serial_putc, + .pending = mtk_serial_pending, + .getc = mtk_serial_getc, + .setbrg = mtk_serial_setbrg, +}; + +static const struct udevice_id mtk_serial_ids[] = { + { .compatible = "mediatek,hsuart" }, + { .compatible = "mediatek,mt6577-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_mtk) = { + .name = "serial_mtk", + .id = UCLASS_SERIAL, + .of_match = mtk_serial_ids, + .ofdata_to_platdata = mtk_serial_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct mtk_serial_priv), + .probe = mtk_serial_probe, + .ops = &mtk_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#ifdef CONFIG_DEBUG_UART_MTK + +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ + struct mtk_serial_priv priv; + + priv.regs = (void *) CONFIG_DEBUG_UART_BASE; + priv.clock = CONFIG_DEBUG_UART_CLOCK; + + writel(0, &priv.regs->ier); + + _mtk_serial_setbrg(&priv, CONFIG_BAUDRATE); +} + +static inline void _debug_uart_putc(int ch) +{ + struct mtk_serial_regs __iomem *regs = + (void *) CONFIG_DEBUG_UART_BASE; + + while (!(readl(®s->lsr) & UART_LSR_THRE)) + ; + + writel(ch, ®s->thr); +} + +DEBUG_UART_FUNCS + +#endif
\ No newline at end of file diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c index 9f09e3bf930..f0f0b79bc52 100644 --- a/drivers/sound/sound-i2s.c +++ b/drivers/sound/sound-i2s.c @@ -185,7 +185,8 @@ int sound_play(uint32_t msec, uint32_t frequency) return -1; } - sound_create_square_wave((unsigned short *)data, + sound_create_square_wave(g_i2stx_pri.samplingrate, + (unsigned short *)data, data_size / sizeof(unsigned short), frequency); diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index 969408186fd..4f0ad0d8f0d 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -7,11 +7,11 @@ #include <common.h> #include <sound.h> -void sound_create_square_wave(unsigned short *data, int size, uint32_t freq) +void sound_create_square_wave(uint sample_rate, unsigned short *data, int size, + uint freq) { - const int sample = 48000; const unsigned short amplitude = 16000; /* between 1 and 32767 */ - const int period = freq ? sample / freq : 0; + const int period = freq ? sample_rate / freq : 0; const int half = period / 2; assert(freq); @@ -25,12 +25,10 @@ void sound_create_square_wave(unsigned short *data, int size, uint32_t freq) for (i = 0; size && i < half; i++) { size -= 2; *data++ = amplitude; - *data++ = amplitude; } for (i = 0; size && i < period - half; i++) { size -= 2; *data++ = -amplitude; - *data++ = -amplitude; } } } diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 29db6fa3684..11fce9c4fe5 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -329,7 +329,7 @@ static const struct dm_spi_ops cadence_spi_ops = { }; static const struct udevice_id cadence_spi_ids[] = { - { .compatible = "cadence,qspi" }, + { .compatible = "cdns,qspi-nor" }, { } }; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index b84255bd274..2bc289a74cc 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -15,6 +15,8 @@ DECLARE_GLOBAL_DATA_PTR; +#define SPI_DEFAULT_SPEED_HZ 100000 + static int spi_set_speed_mode(struct udevice *bus, int speed, int mode) { struct dm_spi_ops *ops; @@ -58,7 +60,7 @@ int dm_spi_claim_bus(struct udevice *dev) speed = spi->max_hz; } if (!speed) - speed = 100000; + speed = SPI_DEFAULT_SPEED_HZ; if (speed != slave->speed) { int ret = spi_set_speed_mode(bus, speed, slave->mode); @@ -300,7 +302,13 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, } plat = dev_get_parent_platdata(dev); plat->cs = cs; - plat->max_hz = speed; + if (speed) { + plat->max_hz = speed; + } else { + printf("Warning: SPI speed fallback to %u kHz\n", + SPI_DEFAULT_SPEED_HZ / 1000); + plat->max_hz = SPI_DEFAULT_SPEED_HZ; + } plat->mode = mode; created = true; } else if (ret) { @@ -374,7 +382,8 @@ int spi_slave_ofdata_to_platdata(struct udevice *dev, int value; plat->cs = dev_read_u32_default(dev, "reg", -1); - plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency", 0); + plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency", + SPI_DEFAULT_SPEED_HZ); if (dev_read_bool(dev, "spi-cpol")) mode |= SPI_CPOL; if (dev_read_bool(dev, "spi-cpha")) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index d0cfc353066..b0e6f32f0bc 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -160,4 +160,11 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86. +config MTK_TIMER + bool "MediaTek timer support" + depends on TIMER + help + Select this to enable support for the timer found on + MediaTek devices. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 7f19c4970a4..c4fbab2aaca 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_STI_TIMER) += sti-timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o +obj-$(CONFIG_MTK_TIMER) += mtk_timer.o diff --git a/drivers/timer/mtk_timer.c b/drivers/timer/mtk_timer.c new file mode 100644 index 00000000000..b5e76bd3586 --- /dev/null +++ b/drivers/timer/mtk_timer.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek timer driver + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <timer.h> +#include <asm/io.h> + +#define MTK_GPT4_CTRL 0x40 +#define MTK_GPT4_CLK 0x44 +#define MTK_GPT4_CNT 0x48 + +#define GPT4_ENABLE BIT(0) +#define GPT4_CLEAR BIT(1) +#define GPT4_FREERUN GENMASK(5, 4) +#define GPT4_CLK_SYS 0x0 +#define GPT4_CLK_DIV1 0x0 + +struct mtk_timer_priv { + void __iomem *base; +}; + +static int mtk_timer_get_count(struct udevice *dev, u64 *count) +{ + struct mtk_timer_priv *priv = dev_get_priv(dev); + u32 val = readl(priv->base + MTK_GPT4_CNT); + + *count = timer_conv_64(val); + + return 0; +} + +static int mtk_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct mtk_timer_priv *priv = dev_get_priv(dev); + struct clk clk, parent; + int ret; + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_get_by_index(dev, 1, &parent); + if (!ret) { + ret = clk_set_parent(&clk, &parent); + if (ret) + return ret; + } + + uc_priv->clock_rate = clk_get_rate(&clk); + if (!uc_priv->clock_rate) + return -EINVAL; + + return 0; +} + +static const struct timer_ops mtk_timer_ops = { + .get_count = mtk_timer_get_count, +}; + +static const struct udevice_id mtk_timer_ids[] = { + { .compatible = "mediatek,timer" }, + { } +}; + +U_BOOT_DRIVER(mtk_timer) = { + .name = "mtk_timer", + .id = UCLASS_TIMER, + .of_match = mtk_timer_ids, + .priv_auto_alloc_size = sizeof(struct mtk_timer_priv), + .probe = mtk_timer_probe, + .ops = &mtk_timer_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index e993fd9f833..30194bce078 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -388,6 +388,27 @@ static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len) return offset; } +static int tpm_tis_lpc_close(struct udevice *dev) +{ + struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); + struct tpm_locality *regs = priv->regs; + u8 locality = 0; + + if (tpm_read_word(priv, ®s[locality].access) & + TIS_ACCESS_ACTIVE_LOCALITY) { + tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY, + ®s[locality].access); + + if (tis_wait_reg(priv, ®s[locality].access, + TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) { + printf("%s:%d - failed to release locality %d\n", + __FILE__, __LINE__, locality); + return -ETIMEDOUT; + } + } + return 0; +} + static int tpm_tis_lpc_open(struct udevice *dev) { struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); @@ -395,6 +416,12 @@ static int tpm_tis_lpc_open(struct udevice *dev) u8 locality = 0; /* we use locality zero for everything. */ int ret; + ret = tpm_tis_lpc_close(dev); + if (ret) { + printf("%s: Failed to close TPM\n", __func__); + return ret; + } + /* now request access to locality. */ tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, ®s[locality].access); @@ -410,27 +437,7 @@ static int tpm_tis_lpc_open(struct udevice *dev) tpm_write_word(priv, TIS_STS_COMMAND_READY, ®s[locality].tpm_status); - return 0; -} - -static int tpm_tis_lpc_close(struct udevice *dev) -{ - struct tpm_tis_lpc_priv *priv = dev_get_priv(dev); - struct tpm_locality *regs = priv->regs; - u8 locality = 0; - - if (tpm_read_word(priv, ®s[locality].access) & - TIS_ACCESS_ACTIVE_LOCALITY) { - tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY, - ®s[locality].access); - if (tis_wait_reg(priv, ®s[locality].access, - TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) { - printf("%s:%d - failed to release locality %d\n", - __FILE__, __LINE__, locality); - return -ETIMEDOUT; - } - } return 0; } diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index 79517f015af..3336f559e57 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -187,9 +187,11 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, code = get_unaligned_be32(sendbuf + sizeof(uint16_t) + sizeof(uint32_t)); +#ifdef DEBUG printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size, *recv_len, code); print_buffer(0, sendbuf, 1, send_size, 0); +#endif switch (code) { case TPM_CMD_GET_CAPABILITY: type = get_unaligned_be32(sendbuf + 14); @@ -306,6 +308,10 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, printf("Unknown tpm command %02x\n", code); return -ENOSYS; } +#ifdef DEBUG + printf("tpm: rx recv_len %zd\n", *recv_len); + print_buffer(0, recvbuf, 1, *recv_len, 0); +#endif return 0; } diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 4fbe172e05c..d456beb43fc 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -47,6 +47,11 @@ config DM_USB declared with the U_BOOT_USB_DEVICE() macro and will be automatically probed when found on the bus. +config SPL_DM_USB + bool "Enable driver model for USB in SPL" + depends on DM_USB + default y + source "drivers/usb/host/Kconfig" source "drivers/usb/dwc3/Kconfig" @@ -65,6 +70,7 @@ comment "USB peripherals" config USB_STORAGE bool "USB Mass Storage support" + depends on !(BLK && !DM_USB) ---help--- Say Y here if you want to connect USB mass storage devices to your board's USB port. diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile index 55e0547b169..3bedbf213f4 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -3,6 +3,6 @@ # (C) Copyright 2016 Freescale Semiconductor, Inc. # -obj-$(CONFIG_DM_USB) += common.o +obj-$(CONFIG_$(SPL_)DM_USB) += common.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1ab5cee6096..f1ca6191ce4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -789,7 +789,7 @@ MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) int dwc3_init(struct dwc3 *dwc) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 58fe91dc513..cfe29884e76 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -712,7 +712,7 @@ struct dwc3 { /* device lock */ spinlock_t lock; -#if defined(__UBOOT__) && defined(CONFIG_DM_USB) +#if defined(__UBOOT__) && CONFIG_IS_ENABLED(DM_USB) struct udevice *dev; #else struct device *dev; diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 1ce3361b458..3aca9ac265d 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -271,7 +271,7 @@ int usb_host_eth_scan(int mode) } usb_max_eth_dev = 0; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) /* * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB * Ethernet driver and then most of this file can be removed. diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 0a84f6850d1..bd596ce9773 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -1015,7 +1015,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) return -EINVAL; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) ret = usb_setup_ehci_gadget(&controller.ctrl); #else ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 90ef1f055f7..193583b437c 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -100,7 +100,7 @@ struct eth_dev { struct usb_gadget *gadget; struct usb_request *req; /* for control responses */ struct usb_request *stat_req; /* for cdc & rndis status */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct udevice *usb_udev; #endif @@ -2337,7 +2337,7 @@ fail: /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) int dm_usb_init(struct eth_dev *e_dev) { struct udevice *dev = NULL; @@ -2362,7 +2362,7 @@ static int _usb_eth_init(struct ether_priv *priv) unsigned long ts; unsigned long timeout = USB_CONNECT_TIMEOUT; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) if (dm_usb_init(dev)) { pr_err("USB ether not found\n"); return -ENODEV; @@ -2541,7 +2541,7 @@ void _usb_eth_halt(struct ether_priv *priv) } usb_gadget_unregister_driver(&priv->eth_driver); -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) board_usb_cleanup(0, USB_INIT_DEVICE); #endif } diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index cb8c315a151..285c20ae863 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -3,8 +3,8 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifdef CONFIG_DM_USB -obj-$(CONFIG_CMD_USB) += usb-uclass.o +ifdef CONFIG_$(SPL_)DM_USB +obj-y += usb-uclass.o obj-$(CONFIG_SANDBOX) += usb-sandbox.o endif diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index b6f008a4004..a62a2f8a951 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -29,7 +29,7 @@ #define MAX_ENDPOINT 16 struct dwc2_priv { -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); #ifdef CONFIG_DM_REGULATOR @@ -54,7 +54,7 @@ struct dwc2_priv { struct reset_ctl_bulk resets; }; -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) /* We need cacheline-aligned buffers for DMA transfers and dcache support */ DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, ARCH_DMA_MINALIGN); @@ -168,7 +168,7 @@ static void dwc_otg_core_reset(struct dwc2_core_regs *regs) mdelay(100); } -#if defined(CONFIG_DM_USB) && defined(CONFIG_DM_REGULATOR) +#if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR) static int dwc_vbus_supply_init(struct udevice *dev) { struct dwc2_priv *priv = dev_get_priv(dev); @@ -211,7 +211,7 @@ static int dwc_vbus_supply_init(struct udevice *dev) return 0; } -#if defined(CONFIG_DM_USB) +#if CONFIG_IS_ENABLED(DM_USB) static int dwc_vbus_supply_exit(struct udevice *dev) { return 0; @@ -1222,7 +1222,7 @@ static void dwc2_uninit_common(struct dwc2_core_regs *regs) DWC2_HPRT0_PRTRST); } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup) { @@ -1267,7 +1267,7 @@ int usb_lowlevel_stop(int index) } #endif -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 66dc63da089..6900848df1e 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -14,7 +14,7 @@ #include "ehci.h" -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index a8fb2b8ac3b..23e7e7125fd 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct ehci_fsl_priv { struct ehci_ctrl ehci; fdt_addr_t hcd_base; @@ -34,7 +34,7 @@ struct ehci_fsl_priv { #endif static void set_txfifothresh(struct usb_ehci *, u32); -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci, struct ehci_hccr *hccr, struct ehci_hcor *hcor); #else @@ -54,7 +54,7 @@ static int usb_phy_clk_valid(struct usb_ehci *ehci) } } -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_fsl_ofdata_to_platdata(struct udevice *dev) { struct ehci_fsl_priv *priv = dev_get_priv(dev); @@ -183,7 +183,7 @@ int ehci_hcd_stop(int index) } #endif -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_fsl_init(struct ehci_fsl_priv *priv, struct usb_ehci *ehci, struct ehci_hccr *hccr, struct ehci_hcor *hcor) #else @@ -192,7 +192,7 @@ static int ehci_fsl_init(int index, struct usb_ehci *ehci, #endif { const char *phy_type = NULL; -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) size_t len; char current_usb_controller[5]; #endif @@ -218,7 +218,7 @@ static int ehci_fsl_init(int index, struct usb_ehci *ehci, out_be32(&ehci->snoop2, 0x80000000 | SNOOP_SIZE_2GB); /* Init phy */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) if (priv->phy_type) phy_type = priv->phy_type; #else diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d1d8f08d986..4b28db70a56 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -30,7 +30,7 @@ */ #define HCHALT_TIMEOUT (8 * 1000) -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; #endif @@ -111,7 +111,7 @@ static struct descriptor { static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev) { -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) return dev_get_priv(usb_get_bus(udev->dev)); #else return udev->controller; @@ -973,7 +973,7 @@ static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops) } } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops) { struct ehci_ctrl *ctrl = &ehcic[index]; @@ -1097,7 +1097,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int usb_lowlevel_stop(int index) { ehci_shutdown(&ehcic[index]); @@ -1518,7 +1518,7 @@ static int _ehci_submit_int_msg(struct usb_device *dev, unsigned long pipe, return result; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int length) { @@ -1556,7 +1556,7 @@ int destroy_int_queue(struct usb_device *dev, struct int_queue *queue) } #endif -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 73432f2acd0..8efe6b63b97 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR; /* * USB 2.0 Bridge Address Decoding registers setup */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct ehci_mvebu_priv { struct ehci_ctrl ehci; @@ -228,4 +228,4 @@ int ehci_hcd_stop(int index) return 0; } -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index be010b1adb1..1acf08dfb7e 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -335,7 +335,7 @@ int ehci_mx6_common_init(struct usb_ehci *ehci, int index) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 6150f3d8885..04e7c5e37f8 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -19,7 +19,7 @@ struct ehci_pci_priv { struct phy phy; }; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_pci_init(struct udevice *dev, struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor) { @@ -121,9 +121,9 @@ int ehci_hcd_stop(int index) { return 0; } -#endif /* nCONFIG_DM_USB */ +#endif /* !CONFIG_IS_ENABLED(DM_USB) */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ehci_pci_probe(struct udevice *dev) { struct ehci_hccr *hccr; @@ -173,4 +173,4 @@ static struct pci_device_id ehci_pci_supported[] = { U_BOOT_PCI_DEVICE(ehci_pci, ehci_pci_supported); -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index 22e5afad6e0..a16cf135e31 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -153,7 +153,7 @@ int ehci_vf_common_init(struct usb_ehci *ehci, int index) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6ea9f105a65..3b6f889f7b7 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -120,7 +120,7 @@ static struct pci_device_id ehci_pci_ids[] = { #define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32) #define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256) -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) /* * The various ohci_mdelay(1) calls in the code seem unnecessary. We keep * them around when building for older boards not yet converted to the dm @@ -131,7 +131,7 @@ static struct pci_device_id ehci_pci_ids[] = { #define ohci_mdelay(x) mdelay(x) #endif -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) /* global ohci_t */ static ohci_t gohci; /* this must be aligned to a 256 byte boundary */ @@ -1691,7 +1691,7 @@ static int _ohci_destroy_int_queue(ohci_t *ohci, struct usb_device *dev, return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) /* submit routines called from usb.c */ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len) @@ -1980,7 +1980,7 @@ static int hc_interrupt(ohci_t *ohci) /*-------------------------------------------------------------------------*/ -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) /*-------------------------------------------------------------------------*/ @@ -2130,7 +2130,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, } #endif -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int ohci_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index fba78dcf7a7..f9f02cb09c5 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -27,7 +27,7 @@ #define ED_ALIGNMENT 16 #endif -#if defined CONFIG_DM_USB && ARCH_DMA_MINALIGN > 32 +#if CONFIG_IS_ENABLED(DM_USB) && ARCH_DMA_MINALIGN > 32 #define TD_ALIGNMENT ARCH_DMA_MINALIGN #else #define TD_ALIGNMENT 32 @@ -406,7 +406,7 @@ typedef struct ohci { const char *slot_name; } ohci_t; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) extern struct dm_usb_ops ohci_usb_ops; int ohci_register(struct udevice *dev, struct ohci_regs *regs); diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index 80754d76d03..dd0d156027e 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -109,7 +109,7 @@ void dwc3_set_fladj(struct dwc3 *dwc3_reg, u32 val) GFLADJ_30MHZ(val)); } -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int xhci_dwc3_setup_phy(struct udevice *dev) { struct xhci_dwc3_platdata *plat = dev_get_platdata(dev); diff --git a/drivers/usb/host/xhci-fsl.c b/drivers/usb/host/xhci-fsl.c index 047a8dfdef9..c0b98a8ec71 100644 --- a/drivers/usb/host/xhci-fsl.c +++ b/drivers/usb/host/xhci-fsl.c @@ -19,7 +19,7 @@ #include <dm.h> /* Declare global data pointer */ -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) static struct fsl_xhci fsl_xhci; unsigned long ctr_addr[] = FSL_USB_XHCI_ADDR; #else @@ -107,7 +107,7 @@ static int fsl_xhci_core_exit(struct fsl_xhci *fsl_xhci) return 0; } -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int xhci_fsl_probe(struct udevice *dev) { struct xhci_fsl_priv *priv = dev_get_priv(dev); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index da5dbd94edd..04ab540695b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -723,7 +723,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id = udev->slot_id; int speed = udev->speed; int route = 0; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct usb_device *dev = udev; struct usb_hub_device *hub; #endif @@ -739,7 +739,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, /* Only the control endpoint is valid - one endpoint context */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) /* Calculate the route string for this device */ port_num = dev->portnr; while (!usb_hub_is_root_hub(dev->dev)) { @@ -782,7 +782,7 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, BUG(); } -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) /* Set up TT fields to support FS/LS devices */ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) { struct udevice *parent = udev->dev; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9ded14cc3cb..44c5f2d264c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -108,13 +108,13 @@ static struct descriptor { }, }; -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) static struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; #endif struct xhci_ctrl *xhci_get_ctrl(struct usb_device *udev) { -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct udevice *dev; /* Find the USB controller */ @@ -741,7 +741,7 @@ static int _xhci_alloc_device(struct usb_device *udev) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int usb_alloc_device(struct usb_device *udev) { return _xhci_alloc_device(udev); @@ -1256,7 +1256,7 @@ static int xhci_lowlevel_stop(struct xhci_ctrl *ctrl) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int submit_control_msg(struct usb_device *udev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) { @@ -1340,9 +1340,9 @@ int usb_lowlevel_stop(int index) return 0; } -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int xhci_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a7555b2fa8a..60175044884 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1211,7 +1211,7 @@ void xhci_hcd_stop(int index); #define XHCI_STS_CNR (1 << 11) struct xhci_ctrl { -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) struct udevice *dev; #endif struct xhci_hccr *hccr; /* R/O registers, not need for volatile */ diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 2bf918eab46..d40772b1aa5 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -19,7 +19,7 @@ struct int_queue { struct urb urb; }; -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) struct musb_host_data musb_host; #endif @@ -243,7 +243,7 @@ int musb_lowlevel_init(struct musb_host_data *host) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int usb_lowlevel_stop(int index) { if (!musb_host.host) { @@ -300,9 +300,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) { return musb_lowlevel_init(&musb_host); } -#endif /* !CONFIG_DM_USB */ +#endif /* !CONFIG_IS_ENABLED(DM_USB) */ -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev, unsigned long pipe, void *buffer, int length, struct devrequest *setup) @@ -364,7 +364,7 @@ struct dm_usb_ops musb_usb_ops = { .destroy_int_queue = musb_destroy_int_queue, .reset_root_port = musb_reset_root_port, }; -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ #endif /* CONFIG_USB_MUSB_HOST */ #ifdef CONFIG_USB_MUSB_GADGET @@ -425,7 +425,7 @@ struct musb *musb_register(struct musb_hdrc_platform_data *plat, void *bdata, struct musb **musbp; switch (plat->mode) { -#if defined(CONFIG_USB_MUSB_HOST) && !defined(CONFIG_DM_USB) +#if defined(CONFIG_USB_MUSB_HOST) && !CONFIG_IS_ENABLED(DM_USB) case MUSB_HOST: musbp = &musb_host.host; break; diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c index 342d76bd6f8..58aed72b7d3 100644 --- a/drivers/usb/musb-new/omap2430.c +++ b/drivers/usb/musb-new/omap2430.c @@ -135,7 +135,7 @@ const struct musb_platform_ops omap2430_ops = { .disable = omap2430_musb_disable, }; -#if defined(CONFIG_DM_USB) +#if CONFIG_IS_ENABLED(DM_USB) struct omap2430_musb_platdata { void *base; @@ -276,4 +276,4 @@ U_BOOT_DRIVER(omap2430_musb) = { .priv_auto_alloc_size = sizeof(struct musb_host_data), }; -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index 9fbe2d6861d..ee0960704a0 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -19,7 +19,7 @@ DECLARE_GLOBAL_DATA_PTR; -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) /* USB 2.0 PHY Control */ #define CM_PHY_PWRDN (1 << 0) @@ -251,4 +251,4 @@ U_BOOT_DRIVER(ti_musb_wrapper) = { .bind = ti_musb_wrapper_bind, }; -#endif /* CONFIG_DM_USB */ +#endif /* CONFIG_IS_ENABLED(DM_USB) */ diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h index 760bd787bc0..f2c18ad3a2e 100644 --- a/drivers/usb/musb-new/usb-compat.h +++ b/drivers/usb/musb-new/usb-compat.h @@ -67,7 +67,7 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, return 0; } -#ifdef CONFIG_DM_USB +#if CONFIG_IS_ENABLED(DM_USB) static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) { struct udevice *parent = udev->dev->parent; diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c index 4fe8f47441e..4f1a0f3a5f7 100644 --- a/drivers/video/rockchip/rk_mipi.c +++ b/drivers/video/rockchip/rk_mipi.c @@ -106,7 +106,7 @@ int rk_mipi_dsi_enable(struct udevice *dev, rk_mipi_dsi_write(regs, VSYNC_ACTIVE_LOW, val); val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0; - rk_mipi_dsi_write(regs, DISPLAY_FLAGS_DE_LOW, val); + rk_mipi_dsi_write(regs, DATAEN_ACTIVE_LOW, val); val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0; rk_mipi_dsi_write(regs, COLORM_ACTIVE_LOW, val); @@ -241,7 +241,7 @@ int rk_mipi_phy_enable(struct udevice *dev) /* select the suitable value for fsfreqrang reg */ for (i = 0; i < ARRAY_SIZE(freq_rang); i++) { - if (ddr_clk / (MHz) >= freq_rang[i][0]) + if (ddr_clk / (MHz) <= freq_rang[i][0]) break; } if (i == ARRAY_SIZE(freq_rang)) { diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 1874887f2f3..2ca19d40491 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -272,6 +272,14 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) s++; /* ; */ s = parsenum(s, &col); + /* + * Video origin is [0, 0], terminal origin is [1, 1]. + */ + if (row) + --row; + if (col) + --col; + set_cursor_position(priv, row, col); break; @@ -344,7 +352,7 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) switch (val) { case 0: /* all attributes off */ - video_set_default_colors(vid_priv); + video_set_default_colors(dev->parent, false); break; case 1: /* bold */ diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 44dfa71b6f4..f307cf243bd 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -115,18 +115,29 @@ int video_clear(struct udevice *dev) return 0; } -void video_set_default_colors(struct video_priv *priv) +void video_set_default_colors(struct udevice *dev, bool invert) { + struct video_priv *priv = dev_get_uclass_priv(dev); + int fore, back; + #ifdef CONFIG_SYS_WHITE_ON_BLACK /* White is used when switching to bold, use light gray here */ - priv->fg_col_idx = VID_LIGHT_GRAY; - priv->colour_fg = vid_console_color(priv, VID_LIGHT_GRAY); - priv->colour_bg = vid_console_color(priv, VID_BLACK); + fore = VID_LIGHT_GRAY; + back = VID_BLACK; #else - priv->fg_col_idx = VID_BLACK; - priv->colour_fg = vid_console_color(priv, VID_BLACK); - priv->colour_bg = vid_console_color(priv, VID_WHITE); + fore = VID_BLACK; + back = VID_WHITE; #endif + if (invert) { + int temp; + + temp = fore; + fore = back; + back = temp; + } + priv->fg_col_idx = fore; + priv->colour_fg = vid_console_color(priv, fore); + priv->colour_bg = vid_console_color(priv, back); } /* Flush video activity to the caches */ @@ -215,11 +226,13 @@ static int video_post_probe(struct udevice *dev) /* Set up the line and display size */ priv->fb = map_sysmem(plat->base, plat->size); - priv->line_length = priv->xsize * VNBYTES(priv->bpix); + if (!priv->line_length) + priv->line_length = priv->xsize * VNBYTES(priv->bpix); + priv->fb_size = priv->line_length * priv->ysize; /* Set up colors */ - video_set_default_colors(priv); + video_set_default_colors(dev, false); if (!CONFIG_IS_ENABLED(NO_FB_CLEAR)) video_clear(dev); diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index 1377e190817..2898b0b55d7 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -7,6 +7,7 @@ #include <bmp_layout.h> #include <dm.h> #include <mapmem.h> +#include <splash.h> #include <video.h> #include <watchdog.h> #include <asm/unaligned.h> @@ -140,8 +141,6 @@ __weak void fb_put_word(uchar **fb, uchar **from) } #endif /* CONFIG_BMP_16BPP */ -#define BMP_ALIGN_CENTER 0x7fff - /** * video_splash_align_axis() - Align a single coordinate * diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4796da08239..b6974ad619a 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -103,6 +103,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. +config WDT_MTK + bool "MediaTek watchdog timer support" + depends on WDT && ARCH_MEDIATEK + help + Select this to enable watchdog timer for MediaTek SoCs. + The watchdog timer is stopped when initialized. + It performs full SoC reset. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT @@ -136,4 +144,11 @@ config WDT_MT7621 Select this to enable Ralink / Mediatek watchdog timer, which can be found on some MediaTek chips. +config WDT_MPC8xx + bool "MPC8xx watchdog timer support" + depends on WDT && MPC8xx + select CONFIG_MPC8xx_WATCHDOG + help + Select this to enable mpc8xx watchdog timer + endmenu diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index b8f2842f7ec..74738eeaf7a 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o +obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c index ccb06ac425f..c24c2a9da6d 100644 --- a/drivers/watchdog/mpc8xx_wdt.c +++ b/drivers/watchdog/mpc8xx_wdt.c @@ -4,6 +4,8 @@ */ #include <common.h> +#include <dm.h> +#include <wdt.h> #include <mpc8xx.h> #include <asm/cpm_8xx.h> #include <asm/io.h> @@ -16,3 +18,52 @@ void hw_watchdog_reset(void) out_be16(&immap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ } +#ifdef CONFIG_WDT_MPC8xx +static int mpc8xx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; + + out_be32(&immap->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR); + + if (!(in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE)) + return -EBUSY; + return 0; + +} + +static int mpc8xx_wdt_stop(struct udevice *dev) +{ + immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; + + out_be32(&immap->im_siu_conf.sc_sypcr, CONFIG_SYS_SYPCR & ~SYPCR_SWE); + + if (in_be32(&immap->im_siu_conf.sc_sypcr) & SYPCR_SWE) + return -EBUSY; + return 0; +} + +static int mpc8xx_wdt_reset(struct udevice *dev) +{ + hw_watchdog_reset(); + + return 0; +} + +static const struct wdt_ops mpc8xx_wdt_ops = { + .start = mpc8xx_wdt_start, + .reset = mpc8xx_wdt_reset, + .stop = mpc8xx_wdt_stop, +}; + +static const struct udevice_id mpc8xx_wdt_ids[] = { + { .compatible = "fsl,pq1-wdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_mpc8xx) = { + .name = "wdt_mpc8xx", + .id = UCLASS_WDT, + .of_match = mpc8xx_wdt_ids, + .ops = &mpc8xx_wdt_ops, +}; +#endif /* CONFIG_WDT_MPC8xx */ diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c new file mode 100644 index 00000000000..0b501733f27 --- /dev/null +++ b/drivers/watchdog/mtk_wdt.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Watchdog driver for MediaTek SoCs + * + * Copyright (C) 2018 MediaTek Inc. + * Author: Ryder Lee <ryder.lee@mediatek.com> + */ + +#include <common.h> +#include <dm.h> +#include <wdt.h> +#include <asm/io.h> + +#define MTK_WDT_MODE 0x00 +#define MTK_WDT_LENGTH 0x04 +#define MTK_WDT_RESTART 0x08 +#define MTK_WDT_STATUS 0x0c +#define MTK_WDT_INTERVAL 0x10 +#define MTK_WDT_SWRST 0x14 +#define MTK_WDT_REQ_MODE 0x30 +#define MTK_WDT_DEBUG_CTL 0x40 + +#define WDT_MODE_KEY (0x22 << 24) +#define WDT_MODE_EN BIT(0) +#define WDT_MODE_EXTPOL BIT(1) +#define WDT_MODE_EXTEN BIT(2) +#define WDT_MODE_IRQ_EN BIT(3) +#define WDT_MODE_DUAL_EN BIT(6) + +#define WDT_LENGTH_KEY 0x8 +#define WDT_LENGTH_TIMEOUT(n) ((n) << 5) + +#define WDT_RESTART_KEY 0x1971 +#define WDT_SWRST_KEY 0x1209 + +struct mtk_wdt_priv { + void __iomem *base; +}; + +static int mtk_wdt_reset(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + /* Reload watchdog duration */ + writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); + + return 0; +} + +static int mtk_wdt_stop(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + clrsetbits_le32(priv->base + MTK_WDT_MODE, WDT_MODE_EN, WDT_MODE_KEY); + + return 0; +} + +static int mtk_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + /* Kick watchdog to prevent counter == 0 */ + writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART); + + /* Reset */ + writel(WDT_SWRST_KEY, priv->base + MTK_WDT_SWRST); + hang(); + + return 0; +} + +static void mtk_wdt_set_timeout(struct udevice *dev, unsigned int timeout) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + /* + * One bit is the value of 512 ticks + * The clock has 32 KHz + */ + timeout = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY; + writel(timeout, priv->base + MTK_WDT_LENGTH); + + mtk_wdt_reset(dev); +} + +static int mtk_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + mtk_wdt_set_timeout(dev, timeout); + + /* Enable watchdog reset signal */ + setbits_le32(priv->base + MTK_WDT_MODE, + WDT_MODE_EN | WDT_MODE_KEY | WDT_MODE_EXTEN); + + return 0; +} + +static int mtk_wdt_probe(struct udevice *dev) +{ + struct mtk_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -ENOENT; + + /* Clear status */ + clrsetbits_le32(priv->base + MTK_WDT_MODE, + WDT_MODE_IRQ_EN | WDT_MODE_EXTPOL, WDT_MODE_KEY); + + return mtk_wdt_stop(dev); +} + +static const struct wdt_ops mtk_wdt_ops = { + .start = mtk_wdt_start, + .reset = mtk_wdt_reset, + .stop = mtk_wdt_stop, + .expire_now = mtk_wdt_expire_now, +}; + +static const struct udevice_id mtk_wdt_ids[] = { + { .compatible = "mediatek,wdt"}, + {} +}; + +U_BOOT_DRIVER(mtk_wdt) = { + .name = "mtk_wdt", + .id = UCLASS_WDT, + .of_match = mtk_wdt_ids, + .priv_auto_alloc_size = sizeof(struct mtk_wdt_priv), + .probe = mtk_wdt_probe, + .ops = &mtk_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +}; |