diff options
author | Tom Rini <trini@konsulko.com> | 2018-11-28 23:04:58 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2018-11-28 23:04:58 -0500 |
commit | e16c888fab5014b022d5781dc534f204460a073b (patch) | |
tree | 47ad22733082c607dcdb56f0329ee076039dbc70 /drivers | |
parent | 67cf22cbdef8c62ffa28b4caf935825fe410c68d (diff) | |
parent | a9da9eebf3d55eeb28dd521fc3b0fc1c9b5dc64b (diff) | |
download | u-boot-e16c888fab5014b022d5781dc534f204460a073b.tar.gz |
Merge branch '2018-11-28-master-imports'
- Add MediaTek support
Diffstat (limited to 'drivers')
32 files changed, 7848 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 821b5867e8..c128538303 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -10,6 +10,7 @@ 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_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_SOCFPGA) += altera/ obj-$(CONFIG_CLK_AT91) += at91/ diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile new file mode 100644 index 0000000000..0632dc87b6 --- /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 0000000000..c6b09d8e18 --- /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 0000000000..2601b6cf30 --- /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 0000000000..870b14ed8b --- /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 0000000000..74152ed9c6 --- /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/mmc/Kconfig b/drivers/mmc/Kconfig index 3f7458d409..fbd13964a0 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -602,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 23c5b0daef..801a26d821 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/mtk-sd.c b/drivers/mmc/mtk-sd.c new file mode 100644 index 0000000000..0741a525c0 --- /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/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ad0b8daba6..7e6fad305a 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 a3a6c6d163..293bad3a95 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 0000000000..1bd9a925a5 --- /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 0000000000..f6ef3627e8 --- /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 0000000000..fd37dfa442 --- /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 0000000000..aa6d1c2d91 --- /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 0000000000..938cc75496 --- /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 0000000000..86559f0f14 --- /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/power/domain/Kconfig b/drivers/power/domain/Kconfig index a08b4288b4..93deaef809 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 b08d18f7ac..695aafe17d 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 0000000000..c67e8804b1 --- /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/ram/Makefile b/drivers/ram/Makefile index e14c1cf592..976ec66df7 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 0000000000..95507b593c --- /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 0000000000..b413f499d0 --- /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/serial/Kconfig b/drivers/serial/Kconfig index 6625a65b58..3bcc61e731 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 a48458f955..b6377b1076 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/serial_mtk.c b/drivers/serial/serial_mtk.c new file mode 100644 index 0000000000..bce1be8227 --- /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/timer/Kconfig b/drivers/timer/Kconfig index d0cfc35306..b0e6f32f0b 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 7f19c4970a..c4fbab2aac 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 0000000000..b5e76bd358 --- /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/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4796da0823..4a9ebb6e26 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 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index b8f2842f7e..74738eeaf7 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/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c new file mode 100644 index 0000000000..0b501733f2 --- /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, +}; |